/**
* @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));
}