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 32using namespace std; 33 34profile_t::profile_t() 35 : start_offset(0) 36{ 37} 38 39 40// static member 41count_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 60enum 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 73void 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 94void 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 128void 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 146profile_t::iterator_pair 147profile_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@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 180profile_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