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