profile.cpp revision cc2ee177dbb3befca43e36cfc56778b006c3d050
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
15#include <iostream>
16#include <string>
17#include <sstream>
18
19#include <cerrno>
20
21#include "op_exception.h"
22#include "op_header.h"
23#include "op_config.h"
24#include "op_sample_file.h"
25#include "profile.h"
26#include "op_bfd.h"
27#include "cverb.h"
28
29using namespace std;
30
31profile_t::profile_t()
32	: start_offset(0)
33{
34}
35
36
37// static member
38unsigned int profile_t::sample_count(string const & filename)
39{
40	odb_t samples_db;
41
42	open_sample_file(filename, samples_db);
43
44	unsigned int count = 0;
45
46	odb_node_nr_t node_nr, pos;
47	odb_node_t * node = odb_get_iterator(&samples_db, &node_nr);
48	for (pos = 0; pos < node_nr; ++pos) {
49		if (node[pos].key)
50			count += node[pos].value;
51	}
52
53	odb_close(&samples_db);
54
55	return count;
56}
57
58//static member
59void profile_t::open_sample_file(string const & filename, odb_t & db)
60{
61	int rc = odb_open(&db, filename.c_str(), ODB_RDONLY,
62		sizeof(struct opd_header));
63
64	if (rc)
65		throw op_fatal_error(filename + ": " + strerror(rc));
66
67	opd_header const & head =
68		*static_cast<opd_header *>(odb_get_data(&db));
69
70	if (head.version != OPD_VERSION) {
71		ostringstream os;
72		os << "oprofpp: samples files version mismatch, are you "
73		   << "running a daemon and post-profile tools with version "
74		   <<  "mismatch ?\n";
75		throw op_fatal_error(os.str());
76	}
77}
78
79void profile_t::add_sample_file(string const & filename)
80{
81	odb_t samples_db;
82
83	open_sample_file(filename, samples_db);
84
85	opd_header const & head =
86		*static_cast<opd_header *>(odb_get_data(&samples_db));
87
88	// if we already read a sample file header pointer is non null
89	if (file_header.get())
90		op_check_header(head, *file_header, filename);
91
92	file_header.reset(new opd_header(head));
93
94	odb_node_nr_t node_nr, pos;
95	odb_node_t * node = odb_get_iterator(&samples_db, &node_nr);
96
97	for (pos = 0; pos < node_nr; ++pos) {
98		if (node[pos].key) {
99			ordered_samples_t::iterator it =
100				ordered_samples.find(node[pos].key);
101			if (it != ordered_samples.end()) {
102				it->second += node[pos].value;
103			} else {
104				ordered_samples_t::value_type
105					val(node[pos].key, node[pos].value);
106				ordered_samples.insert(val);
107			}
108		}
109	}
110
111	odb_close(&samples_db);
112}
113
114
115void profile_t::set_offset(op_bfd const & abfd)
116{
117	opd_header const & header = get_header();
118	if (header.anon_start || header.is_kernel)
119		start_offset = abfd.get_start_offset(header.anon_start);
120	cverb << (vdebug) << "start_offset is now " << start_offset << endl;
121}
122
123
124profile_t::iterator_pair
125profile_t::samples_range(odb_key_t start, odb_key_t end) const
126{
127	// Check the start position isn't before start_offset:
128	// this avoids wrapping/underflowing start/end.
129	// This can happen on e.g. ARM kernels, where .init is
130	// mapped before .text - we just have to skip any such
131	// .init symbols.
132	if (start < start_offset) {
133		return make_pair(const_iterator(ordered_samples.end(), 0),
134			const_iterator(ordered_samples.end(), 0));
135	}
136
137	start -= start_offset;
138	end -= start_offset;
139
140	// sanity check if start > end caller will enter into an infinite loop
141	if (start > end) {
142		throw op_fatal_error("profile_t::samples_range(): start > end"
143			" something wrong with kernel or module layout ?\n"
144			"please report problem to "
145			"oprofile-list@lists.sourceforge.net");
146	}
147
148	ordered_samples_t::const_iterator first =
149		ordered_samples.lower_bound(start);
150	ordered_samples_t::const_iterator last =
151		ordered_samples.lower_bound(end);
152
153	return make_pair(const_iterator(first, start_offset),
154		const_iterator(last, start_offset));
155}
156
157
158profile_t::iterator_pair profile_t::samples_range() const
159{
160	ordered_samples_t::const_iterator first = ordered_samples.begin();
161	ordered_samples_t::const_iterator last = ordered_samples.end();
162
163	return make_pair(const_iterator(first, start_offset),
164		const_iterator(last, start_offset));
165}
166