1 /** 2 * @file profile.cpp 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 #include <unistd.h> 14 #include <cstring> 15 16 #include <iostream> 17 #include <string> 18 #include <sstream> 19 #include <cstring> 20 21 #include <cerrno> 22 23 #include "op_exception.h" 24 #include "op_header.h" 25 #include "op_config.h" 26 #include "op_sample_file.h" 27 #include "profile.h" 28 #include "op_bfd.h" 29 #include "cverb.h" 30 #include "populate_for_spu.h" 31 32 using namespace std; 33 34 profile_t::profile_t() 35 : start_offset(0) 36 { 37 } 38 39 40 // static member 41 count_type profile_t::sample_count(string const & filename) 42 { 43 odb_t samples_db; 44 45 open_sample_file(filename, samples_db); 46 47 count_type count = 0; 48 49 odb_node_nr_t node_nr, pos; 50 odb_node_t * node = odb_get_iterator(&samples_db, &node_nr); 51 for (pos = 0; pos < node_nr; ++pos) 52 count += node[pos].value; 53 54 odb_close(&samples_db); 55 56 return count; 57 } 58 59 //static member 60 enum profile_type profile_t::is_spu_sample_file(string const & filename) 61 { 62 profile_type retval; 63 odb_t samples_db; 64 open_sample_file(filename, samples_db); 65 opd_header const & hdr = 66 *static_cast<opd_header *>(odb_get_data(&samples_db)); 67 retval = hdr.spu_profile ? cell_spu_profile: normal_profile; 68 odb_close(&samples_db); 69 return retval; 70 } 71 72 //static member 73 void profile_t::open_sample_file(string const & filename, odb_t & db) 74 { 75 // Check first if the sample file version is ok else odb_open() can 76 // fail and the error message will be obscure. 77 opd_header head = read_header(filename); 78 79 if (head.version != OPD_VERSION) { 80 ostringstream os; 81 os << "oprofpp: samples files version mismatch, are you " 82 << "running a daemon and post-profile tools with version " 83 << "mismatch ?\n"; 84 throw op_fatal_error(os.str()); 85 } 86 87 int rc = odb_open(&db, filename.c_str(), ODB_RDONLY, 88 sizeof(struct opd_header)); 89 90 if (rc) 91 throw op_fatal_error(filename + ": " + strerror(rc)); 92 } 93 94 void profile_t::add_sample_file(string const & filename) 95 { 96 odb_t samples_db; 97 98 open_sample_file(filename, samples_db); 99 100 opd_header const & head = 101 *static_cast<opd_header *>(odb_get_data(&samples_db)); 102 103 // if we already read a sample file header pointer is non null 104 if (file_header.get()) 105 op_check_header(head, *file_header, filename); 106 else 107 file_header.reset(new opd_header(head)); 108 109 odb_node_nr_t node_nr, pos; 110 odb_node_t * node = odb_get_iterator(&samples_db, &node_nr); 111 112 for (pos = 0; pos < node_nr; ++pos) { 113 ordered_samples_t::iterator it = 114 ordered_samples.find(node[pos].key); 115 if (it != ordered_samples.end()) { 116 it->second += node[pos].value; 117 } else { 118 ordered_samples_t::value_type 119 val(node[pos].key, node[pos].value); 120 ordered_samples.insert(val); 121 } 122 } 123 124 odb_close(&samples_db); 125 } 126 127 128 void profile_t::set_offset(op_bfd const & abfd) 129 { 130 // if no bfd file has been located for this samples file, we can't 131 // shift sample because abfd.get_symbol_range() return the whole 132 // address space and setting a non zero start_offset will overflow 133 // in get_symbol_range() caller. 134 if (abfd.valid()) { 135 opd_header const & header = get_header(); 136 if (header.anon_start) { 137 start_offset = header.anon_start; 138 } else if (header.is_kernel) { 139 start_offset = abfd.get_start_offset(0); 140 } 141 } 142 cverb << (vdebug) << "start_offset is now " << start_offset << endl; 143 } 144 145 146 profile_t::iterator_pair 147 profile_t::samples_range(odb_key_t start, odb_key_t end) const 148 { 149 // Check the start position isn't before start_offset: 150 // this avoids wrapping/underflowing start/end. 151 // This can happen on e.g. ARM kernels, where .init is 152 // mapped before .text - we just have to skip any such 153 // .init symbols. 154 if (start < start_offset) { 155 return make_pair(const_iterator(ordered_samples.end(), 0), 156 const_iterator(ordered_samples.end(), 0)); 157 } 158 159 start -= start_offset; 160 end -= start_offset; 161 162 // sanity check if start > end caller will enter into an infinite loop 163 if (start > end) { 164 throw op_fatal_error("profile_t::samples_range(): start > end" 165 " something wrong with kernel or module layout ?\n" 166 "please report problem to " 167 "oprofile-list (at) lists.sourceforge.net"); 168 } 169 170 ordered_samples_t::const_iterator first = 171 ordered_samples.lower_bound(start); 172 ordered_samples_t::const_iterator last = 173 ordered_samples.lower_bound(end); 174 175 return make_pair(const_iterator(first, start_offset), 176 const_iterator(last, start_offset)); 177 } 178 179 180 profile_t::iterator_pair profile_t::samples_range() const 181 { 182 ordered_samples_t::const_iterator first = ordered_samples.begin(); 183 ordered_samples_t::const_iterator last = ordered_samples.end(); 184 185 return make_pair(const_iterator(first, start_offset), 186 const_iterator(last, start_offset)); 187 } 188