• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
profile_t()34 profile_t::profile_t()
35 	: start_offset(0)
36 {
37 }
38 
39 
40 // static member
sample_count(string const & filename)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
is_spu_sample_file(string const & filename)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
open_sample_file(string const & filename,odb_t & db)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 
add_sample_file(string const & filename)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 
set_offset(op_bfd const & abfd)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
samples_range(odb_key_t start,odb_key_t end) const147 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@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 
samples_range() const180 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