Home | History | Annotate | Download | only in libpp
      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