18cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/**
28cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @file profile.cpp
38cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * Encapsulation for samples files over all profile classes
48cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * belonging to the same binary image
58cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd *
68cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @remark Copyright 2002 OProfile authors
78cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @remark Read the file COPYING
88cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd *
98cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @author Philippe Elie
108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @author John Levon
118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */
128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <unistd.h>
148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <cstring>
158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <iostream>
178cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <string>
188cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <sstream>
198cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <cstring>
208cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
218cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <cerrno>
228cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
238cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "op_exception.h"
248cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "op_header.h"
258cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "op_config.h"
268cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "op_sample_file.h"
278cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "profile.h"
288cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "op_bfd.h"
298cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "cverb.h"
308cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "populate_for_spu.h"
318cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
328cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddusing namespace std;
338cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
348cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddprofile_t::profile_t()
358cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	: start_offset(0)
368cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
378cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
388cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
398cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
408cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd// static member
418cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddcount_type profile_t::sample_count(string const & filename)
428cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
438cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	odb_t samples_db;
448cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
458cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	open_sample_file(filename, samples_db);
468cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
478cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	count_type count = 0;
488cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
498cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	odb_node_nr_t node_nr, pos;
508cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	odb_node_t * node = odb_get_iterator(&samples_db, &node_nr);
518cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	for (pos = 0; pos < node_nr; ++pos)
528cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		count += node[pos].value;
538cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
548cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	odb_close(&samples_db);
558cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
568cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	return count;
578cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
588cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
598cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd//static member
608cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddenum profile_type profile_t::is_spu_sample_file(string const & filename)
618cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
628cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	profile_type retval;
638cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	odb_t samples_db;
648cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	open_sample_file(filename, samples_db);
658cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	opd_header const & hdr =
668cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		*static_cast<opd_header *>(odb_get_data(&samples_db));
678cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	retval = hdr.spu_profile ? cell_spu_profile: normal_profile;
688cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	odb_close(&samples_db);
698cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	return retval;
708cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
718cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
728cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd//static member
738cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddvoid profile_t::open_sample_file(string const & filename, odb_t & db)
748cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
758cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	// Check first if the sample file version is ok else odb_open() can
768cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	// fail and the error message will be obscure.
778cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	opd_header head = read_header(filename);
788cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
798cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (head.version != OPD_VERSION) {
808cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		ostringstream os;
818cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		os << "oprofpp: samples files version mismatch, are you "
828cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		   << "running a daemon and post-profile tools with version "
838cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		   <<  "mismatch ?\n";
848cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		throw op_fatal_error(os.str());
858cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	}
868cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
878cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	int rc = odb_open(&db, filename.c_str(), ODB_RDONLY,
888cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		sizeof(struct opd_header));
898cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
908cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (rc)
918cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		throw op_fatal_error(filename + ": " + strerror(rc));
928cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
938cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
948cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddvoid profile_t::add_sample_file(string const & filename)
958cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
968cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	odb_t samples_db;
978cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
988cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	open_sample_file(filename, samples_db);
998cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1008cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	opd_header const & head =
1018cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		*static_cast<opd_header *>(odb_get_data(&samples_db));
1028cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1038cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	// if we already read a sample file header pointer is non null
1048cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (file_header.get())
1058cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		op_check_header(head, *file_header, filename);
1068cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	else
1078cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		file_header.reset(new opd_header(head));
1088cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1098cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	odb_node_nr_t node_nr, pos;
1108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	odb_node_t * node = odb_get_iterator(&samples_db, &node_nr);
1118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	for (pos = 0; pos < node_nr; ++pos) {
1138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		ordered_samples_t::iterator it =
1148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		    ordered_samples.find(node[pos].key);
1158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		if (it != ordered_samples.end()) {
1168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			it->second += node[pos].value;
1178cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		} else {
1188cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			ordered_samples_t::value_type
1198cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd				val(node[pos].key, node[pos].value);
1208cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			ordered_samples.insert(val);
1218cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		}
1228cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	}
1238cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1248cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	odb_close(&samples_db);
1258cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
1268cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1278cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1288cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddvoid profile_t::set_offset(op_bfd const & abfd)
1298cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
1308cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	// if no bfd file has been located for this samples file, we can't
1318cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	// shift sample because abfd.get_symbol_range() return the whole
1328cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	// address space and setting a non zero start_offset will overflow
1338cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	// in get_symbol_range() caller.
1348cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (abfd.valid()) {
1358cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		opd_header const & header = get_header();
1368cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		if (header.anon_start) {
1378cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			start_offset = header.anon_start;
1388cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		} else if (header.is_kernel) {
1398cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			start_offset = abfd.get_start_offset(0);
1408cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		}
1418cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	}
1428cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	cverb << (vdebug) << "start_offset is now " << start_offset << endl;
1438cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
1448cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1458cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1468cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddprofile_t::iterator_pair
1478cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddprofile_t::samples_range(odb_key_t start, odb_key_t end) const
1488cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
1498cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	// Check the start position isn't before start_offset:
1508cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	// this avoids wrapping/underflowing start/end.
1518cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	// This can happen on e.g. ARM kernels, where .init is
1528cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	// mapped before .text - we just have to skip any such
1538cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	// .init symbols.
1548cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (start < start_offset) {
1558cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		return make_pair(const_iterator(ordered_samples.end(), 0),
1568cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			const_iterator(ordered_samples.end(), 0));
1578cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	}
1588cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1598cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	start -= start_offset;
1608cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	end -= start_offset;
1618cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1628cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	// sanity check if start > end caller will enter into an infinite loop
1638cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (start > end) {
1648cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		throw op_fatal_error("profile_t::samples_range(): start > end"
1658cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			" something wrong with kernel or module layout ?\n"
1668cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			"please report problem to "
1678cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			"oprofile-list@lists.sourceforge.net");
1688cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	}
1698cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1708cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	ordered_samples_t::const_iterator first =
1718cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		ordered_samples.lower_bound(start);
1728cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	ordered_samples_t::const_iterator last =
1738cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		ordered_samples.lower_bound(end);
1748cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1758cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	return make_pair(const_iterator(first, start_offset),
1768cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		const_iterator(last, start_offset));
1778cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
1788cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1798cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1808cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddprofile_t::iterator_pair profile_t::samples_range() const
1818cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
1828cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	ordered_samples_t::const_iterator first = ordered_samples.begin();
1838cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	ordered_samples_t::const_iterator last = ordered_samples.end();
1848cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1858cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	return make_pair(const_iterator(first, start_offset),
1868cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		const_iterator(last, start_offset));
1878cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
188