/** * @file profile.cpp * Encapsulation for samples files over all profile classes * belonging to the same binary image * * @remark Copyright 2002 OProfile authors * @remark Read the file COPYING * * @author Philippe Elie * @author John Levon */ #include <unistd.h> #include <cstring> #include <iostream> #include <string> #include <sstream> #include <cstring> #include <cerrno> #include "op_exception.h" #include "op_header.h" #include "op_config.h" #include "op_sample_file.h" #include "profile.h" #include "op_bfd.h" #include "cverb.h" #include "populate_for_spu.h" using namespace std; profile_t::profile_t() : start_offset(0) { } // static member count_type profile_t::sample_count(string const & filename) { odb_t samples_db; open_sample_file(filename, samples_db); count_type count = 0; odb_node_nr_t node_nr, pos; odb_node_t * node = odb_get_iterator(&samples_db, &node_nr); for (pos = 0; pos < node_nr; ++pos) count += node[pos].value; odb_close(&samples_db); return count; } //static member enum profile_type profile_t::is_spu_sample_file(string const & filename) { profile_type retval; odb_t samples_db; open_sample_file(filename, samples_db); opd_header const & hdr = *static_cast<opd_header *>(odb_get_data(&samples_db)); retval = hdr.spu_profile ? cell_spu_profile: normal_profile; odb_close(&samples_db); return retval; } //static member void profile_t::open_sample_file(string const & filename, odb_t & db) { // Check first if the sample file version is ok else odb_open() can // fail and the error message will be obscure. opd_header head = read_header(filename); if (head.version != OPD_VERSION) { ostringstream os; os << "oprofpp: samples files version mismatch, are you " << "running a daemon and post-profile tools with version " << "mismatch ?\n"; throw op_fatal_error(os.str()); } int rc = odb_open(&db, filename.c_str(), ODB_RDONLY, sizeof(struct opd_header)); if (rc) throw op_fatal_error(filename + ": " + strerror(rc)); } void profile_t::add_sample_file(string const & filename) { odb_t samples_db; open_sample_file(filename, samples_db); opd_header const & head = *static_cast<opd_header *>(odb_get_data(&samples_db)); // if we already read a sample file header pointer is non null if (file_header.get()) op_check_header(head, *file_header, filename); else file_header.reset(new opd_header(head)); odb_node_nr_t node_nr, pos; odb_node_t * node = odb_get_iterator(&samples_db, &node_nr); for (pos = 0; pos < node_nr; ++pos) { ordered_samples_t::iterator it = ordered_samples.find(node[pos].key); if (it != ordered_samples.end()) { it->second += node[pos].value; } else { ordered_samples_t::value_type val(node[pos].key, node[pos].value); ordered_samples.insert(val); } } odb_close(&samples_db); } void profile_t::set_offset(op_bfd const & abfd) { // if no bfd file has been located for this samples file, we can't // shift sample because abfd.get_symbol_range() return the whole // address space and setting a non zero start_offset will overflow // in get_symbol_range() caller. if (abfd.valid()) { opd_header const & header = get_header(); if (header.anon_start) { start_offset = header.anon_start; } else if (header.is_kernel) { start_offset = abfd.get_start_offset(0); } } cverb << (vdebug) << "start_offset is now " << start_offset << endl; } profile_t::iterator_pair profile_t::samples_range(odb_key_t start, odb_key_t end) const { // Check the start position isn't before start_offset: // this avoids wrapping/underflowing start/end. // This can happen on e.g. ARM kernels, where .init is // mapped before .text - we just have to skip any such // .init symbols. if (start < start_offset) { return make_pair(const_iterator(ordered_samples.end(), 0), const_iterator(ordered_samples.end(), 0)); } start -= start_offset; end -= start_offset; // sanity check if start > end caller will enter into an infinite loop if (start > end) { throw op_fatal_error("profile_t::samples_range(): start > end" " something wrong with kernel or module layout ?\n" "please report problem to " "oprofile-list@lists.sourceforge.net"); } ordered_samples_t::const_iterator first = ordered_samples.lower_bound(start); ordered_samples_t::const_iterator last = ordered_samples.lower_bound(end); return make_pair(const_iterator(first, start_offset), const_iterator(last, start_offset)); } profile_t::iterator_pair profile_t::samples_range() const { ordered_samples_t::const_iterator first = ordered_samples.begin(); ordered_samples_t::const_iterator last = ordered_samples.end(); return make_pair(const_iterator(first, start_offset), const_iterator(last, start_offset)); }