Mike Dodd | 8cfa702 | 2010-11-17 11:12:26 -0800 | [diff] [blame] | 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 | |
| 25 | class opd_header; |
| 26 | class 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 | */ |
| 33 | class profile_t : noncopyable { |
| 34 | public: |
| 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 | |
| 96 | private: |
| 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. |
| 149 | namespace 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 | |
| 161 | class profile_t::const_iterator |
| 162 | { |
| 163 | typedef ordered_samples_t::const_iterator iterator_t; |
| 164 | public: |
| 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 | |
| 182 | private: |
| 183 | iterator_t it; |
| 184 | u64 start_offset; |
| 185 | }; |
| 186 | |
| 187 | #endif /* !PROFILE_H */ |