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