1/**
2 * @file profile.h
3 * Encapsulation for samples files over all profile classes
4 * belonging to the same binary image
5 *
6 * @remark Copyright 2002 OProfile authors
7 * @remark Read the file COPYING
8 *
9 * @author Philippe Elie
10 * @author John Levon
11 */
12
13#ifndef PROFILE_H
14#define PROFILE_H
15
16#include <string>
17#include <map>
18#include <iterator>
19
20#include "odb.h"
21#include "op_types.h"
22#include "utility.h"
23#include "populate_for_spu.h"
24
25class opd_header;
26class op_bfd;
27
28/**
29 * Class containing a single sample file contents.
30 * i.e. set of count values for VMA offsets for
31 * a particular binary.
32 */
33class profile_t : noncopyable {
34public:
35	/**
36	 * profile_t - construct an empty  profile_t object
37	 */
38	profile_t();
39
40	/// return true if no sample file has been loaded
41	bool empty() const { return !file_header.get(); }
42
43	/// return the header of the last opened samples file
44	opd_header const & get_header() const {
45		return *file_header;
46	}
47
48	/**
49	 * count samples count w/o recording them
50	 * @param filename sample filename
51	 *
52	 * convenience interface for raw access to sample count w/o recording
53	 * them. It's placed here so all access to samples files go through
54	 * profile_t static or non static member.
55	 */
56	static count_type sample_count(std::string const & filename);
57
58	/**
59	 * Indicate if given sample file is from a Cell Broadband Engine
60	 * SPU profile
61	 * @param filename sample filename
62	 *
63	 * Convenience interface put here so all access to samples files
64	 * go through profile_t static or non static member.
65	 */
66	static enum profile_type is_spu_sample_file(std::string const & filename);
67
68	/**
69	 * cumulate sample file to our container of samples
70	 * @param filename  sample file name
71	 *
72	 * store samples for one sample file, sample file header is sanitized.
73	 *
74	 * all error are fatal
75	 */
76	void add_sample_file(std::string const & filename);
77
78	/// Set an appropriate start offset, see comments below.
79	void set_offset(op_bfd const & abfd);
80
81	class const_iterator;
82	typedef std::pair<const_iterator, const_iterator> iterator_pair;
83
84	/**
85	 * @param start  start offset
86	 * @param end  end offset
87	 *
88	 * return an iterator pair to [start, end) range
89	 */
90	iterator_pair
91	samples_range(odb_key_t start, odb_key_t end) const;
92
93	/// return a pair of iterator for all samples
94	iterator_pair samples_range() const;
95
96private:
97	/// helper for sample_count() and add_sample_file(). All error launch
98	/// an exception.
99	static void
100	open_sample_file(std::string const & filename, odb_t &);
101
102	/// copy of the samples file header
103	scoped_ptr<opd_header> file_header;
104
105	/// storage type for samples sorted by eip
106	typedef std::map<odb_key_t, count_type> ordered_samples_t;
107
108	/**
109	 * Samples are stored in hash table, iterating over hash table don't
110	 * provide any ordering, the above count() interface rely on samples
111	 * ordered by eip. This map is only a temporary storage where samples
112	 * are ordered by eip.
113	 */
114	ordered_samples_t ordered_samples;
115
116	/**
117	 * For certain profiles, such as kernel/modules, and anon
118	 * regions with a matching binary, this value is non-zero,
119	 * and represents the file offset of the relevant section.
120	 *
121	 * For kernel profiles, this is done because we use the information
122	 * provided in /proc/ksyms, which only gives the mapped position of
123	 * .text, and the symbol _text from vmlinux. This value is used to fix
124	 * up the sample offsets for kernel code as a result of this difference
125	 *
126	 * In user-space samples, the sample offset is from the start of the
127	 * mapped file, as seen in /proc/pid/maps. This is fine for
128	 * mappings of permanent files, but with anon mappings, we need
129	 * to adjust the key values to be a file offset against the
130	 * *binary* (if there is one). This can obviously be different.
131	 * So we pass our anon mapping start VMA to op_bfd, which looks
132	 * for a section with that VMA, then returns the section's
133	 * filepos. So all is good.
134	 *
135	 * Finally, note that for cg we can't use this inside the
136	 * profile_t, as we're storing two offsets in the key value. So
137	 * we do it later in that case.
138	 *
139	 * Phew.
140	 */
141	u64 start_offset;
142};
143
144
145// It will be easier to derive profile_t::const_iterator from
146// std::iterator<std::input_iterator_tag, unsigned int> but this doesn't
147// work for gcc <= 2.95 so we provide the neccessary typedef in the hard way.
148// See ISO C++ 17.4.3.1 � 1 and 14.7.3 � 9.
149namespace std {
150	template <>
151		struct iterator_traits<profile_t::const_iterator> {
152			typedef ptrdiff_t difference_type;
153			typedef count_type value_type;
154			typedef count_type * pointer;
155			typedef count_type & reference;
156			typedef input_iterator_tag iterator_category;
157		};
158}
159
160
161class profile_t::const_iterator
162{
163	typedef ordered_samples_t::const_iterator iterator_t;
164public:
165	const_iterator() : start_offset(0) {}
166	const_iterator(iterator_t it_, u64 start_offset_)
167		: it(it_), start_offset(start_offset_) {}
168
169	count_type operator*() const { return it->second; }
170	const_iterator & operator++() { ++it; return *this; }
171
172	odb_key_t vma() const { return it->first + start_offset; }
173	count_type count() const { return **this; }
174
175	bool operator!=(const_iterator const & rhs) const {
176		return it != rhs.it;
177	}
178	bool operator==(const_iterator const & rhs) const {
179		return it == rhs.it;
180	}
181
182private:
183	iterator_t it;
184	u64 start_offset;
185};
186
187#endif /* !PROFILE_H */
188