blob: b0422d16eb3c5b1b8238e89c064e593b8a226d9b [file] [log] [blame]
Upstreamcc2ee171970-01-12 13:46:40 +00001/**
2 * @file profile_container.cpp
3 * profile file container
4 *
5 * @remark Copyright 2002 OProfile authors
6 * @remark Read the file COPYING
7 *
8 * @author Philippe Elie
9 * @author John Levon
10 */
11
12#include <set>
13#include <vector>
14#include <string>
15#include <iostream>
16#include <algorithm>
17#include <numeric>
18
19#include "symbol.h"
20#include "op_header.h"
21#include "profile.h"
22#include "symbol_functors.h"
23#include "profile_container.h"
24#include "sample_container.h"
25#include "symbol_container.h"
26
27using namespace std;
28
29namespace {
30
31struct filename_by_samples {
32 filename_by_samples(debug_name_id id, double percent_)
33 : filename(id), percent(percent_)
34 {}
35
36 bool operator<(filename_by_samples const & lhs) const {
37 if (percent != lhs.percent)
38 return percent < lhs.percent;
39 return filename < lhs.filename;
40 }
41
42 debug_name_id filename;
43 // ratio of samples which belongs to this filename.
44 double percent;
45};
46
47} // anon namespace
48
49
50profile_container::profile_container(bool debug_info_, bool need_details_)
51 :
52 symbols(new symbol_container),
53 samples(new sample_container),
54 debug_info(debug_info_),
55 need_details(need_details_)
56{
57}
58
59
60profile_container::~profile_container()
61{
62}
63
64
65// Post condition:
66// the symbols/samples are sorted by increasing vma.
67// the range of sample_entry inside each symbol entry are valid
68// the samples_by_file_loc member var is correctly setup.
69void profile_container::add(profile_t const & profile,
70 op_bfd const & abfd, string const & app_name,
71 size_t pclass)
72{
73 string const image_name = abfd.get_filename();
74
75 for (symbol_index_t i = 0; i < abfd.syms.size(); ++i) {
76
77 unsigned long start, end;
78 symbol_entry symb_entry;
79
80 abfd.get_symbol_range(i, start, end);
81
82 profile_t::iterator_pair p_it =
83 profile.samples_range(start, end);
84
85 u32 count = accumulate(p_it.first, p_it.second, 0);
86
87 // skip entries with no samples
88 if (count == 0)
89 continue;
90
91 symb_entry.sample.counts[pclass] = count;
92 total_count[pclass] += count;
93
94 symb_entry.size = end - start;
95
96 symb_entry.name = symbol_names.create(abfd.syms[i].name());
97
98 symb_entry.sample.file_loc.linenr = 0;
99 if (debug_info) {
100 string filename;
101 if (abfd.get_linenr(i, start, filename,
102 symb_entry.sample.file_loc.linenr)) {
103 symb_entry.sample.file_loc.filename =
104 debug_names.create(filename);
105 }
106 }
107
108 symb_entry.image_name = image_names.create(image_name);
109 symb_entry.app_name = image_names.create(app_name);
110
111 bfd_vma base_vma = abfd.syms[i].vma();
112
113 symb_entry.sample.vma = abfd.sym_offset(i, start) + base_vma;
114
115 symbol_entry const * symbol = symbols->insert(symb_entry);
116
117 if (need_details) {
118 add_samples(abfd, i, p_it, symbol, pclass);
119 }
120 }
121}
122
123
124void
125profile_container::add_samples(op_bfd const & abfd, symbol_index_t sym_index,
126 profile_t::iterator_pair const & p_it,
127 symbol_entry const * symbol, size_t pclass)
128{
129 bfd_vma base_vma = abfd.syms[sym_index].vma();
130
131 profile_t::const_iterator it;
132 for (it = p_it.first; it != p_it.second ; ++it) {
133 sample_entry sample;
134
135 sample.counts[pclass] = it.count();
136
137 sample.file_loc.linenr = 0;
138 if (debug_info) {
139 string filename;
140 if (abfd.get_linenr(sym_index, it.vma(), filename,
141 sample.file_loc.linenr)) {
142 sample.file_loc.filename =
143 debug_names.create(filename);
144 }
145 }
146
147 sample.vma = abfd.sym_offset(sym_index, it.vma()) + base_vma;
148
149 samples->insert(symbol, sample);
150 }
151}
152
153
154symbol_collection const
155profile_container::select_symbols(symbol_choice & choice) const
156{
157 symbol_collection result;
158
159 double const threshold = choice.threshold / 100.0;
160
161 symbol_container::symbols_t::iterator it = symbols->begin();
162 symbol_container::symbols_t::iterator const end = symbols->end();
163
164 for (; it != end; ++it) {
165 if (choice.match_image
166 && (image_names.name(it->image_name) != choice.image_name))
167 continue;
168
169 double const percent =
170 op_ratio(it->sample.counts[0], total_count[0]);
171
172 if (percent >= threshold) {
173 result.push_back(&*it);
174
175 choice.hints = it->output_hint(choice.hints);
176 }
177 }
178
179 return result;
180}
181
182
183vector<debug_name_id> const
184profile_container::select_filename(double threshold) const
185{
186 set<debug_name_id> filename_set;
187
188 threshold /= 100.0;
189
190 // Trying to iterate on symbols to create the set of filenames which
191 // contain sample does not work: a symbol can contain samples and this
192 // symbol is in a source file that contain zero sample because only
193 // inline function in this source file contains samples.
194 sample_container::samples_iterator sit = samples->begin();
195 sample_container::samples_iterator const send = samples->end();
196
197 for (; sit != send; ++sit) {
198 debug_name_id name_id = sit->second.file_loc.filename;
199 if (name_id.set()) {
200 filename_set.insert(name_id);
201 }
202 }
203
204 // Give a sort order on filename for the selected pclass.
205 vector<filename_by_samples> file_by_samples;
206
207 set<debug_name_id>::const_iterator it = filename_set.begin();
208 set<debug_name_id>::const_iterator const end = filename_set.end();
209 for (; it != end; ++it) {
210 // FIXME: is samples_count() the right interface now ?
211 count_array_t counts = samples_count(*it);
212
213 double const ratio = op_ratio(counts[0], total_count[0]);
214 filename_by_samples const f(*it, ratio);
215
216 file_by_samples.push_back(f);
217 }
218
219 // now sort the file_by_samples entry.
220 sort(file_by_samples.begin(), file_by_samples.end());
221
222 // 2.91.66 doesn't like const_reverse_iterator in this context
223 vector<filename_by_samples>::reverse_iterator cit
224 = file_by_samples.rbegin();
225 vector<filename_by_samples>::reverse_iterator const cend
226 = file_by_samples.rend();
227
228 vector<debug_name_id> result;
229 for (; cit != cend; ++cit) {
230 if (cit->percent >= threshold)
231 result.push_back(cit->filename);
232 }
233
234 return result;
235}
236
237
238count_array_t profile_container::samples_count() const
239{
240 return total_count;
241}
242
243
244// Rest here are delegated to our private implementation.
245
246symbol_entry const *
247profile_container::find_symbol(string const & image_name, bfd_vma vma) const
248{
249 return symbols->find_by_vma(image_name, vma);
250}
251
252
253symbol_entry const *
254profile_container::find_symbol(debug_name_id filename, size_t linenr) const
255{
256 return symbols->find(filename, linenr);
257}
258
259
260sample_entry const *
261profile_container::find_sample(symbol_entry const * symbol, bfd_vma vma) const
262{
263 return samples->find_by_vma(symbol, vma);
264}
265
266
267count_array_t profile_container::samples_count(debug_name_id filename_id) const
268{
269 return samples->accumulate_samples(filename_id);
270}
271
272
273count_array_t profile_container::samples_count(debug_name_id filename,
274 size_t linenr) const
275{
276 return samples->accumulate_samples(filename, linenr);
277}
278
279
280sample_container::samples_iterator
281profile_container::begin(symbol_entry const * symbol) const
282{
283 return samples->begin(symbol);
284}
285
286
287sample_container::samples_iterator
288profile_container::end(symbol_entry const * symbol) const
289{
290 return samples->end(symbol);
291}
292
293
294sample_container::samples_iterator profile_container::begin() const
295{
296 return samples->begin();
297}
298
299
300sample_container::samples_iterator profile_container::end() const
301{
302 return samples->end();
303}
304
305symbol_entry const * profile_container::find(symbol_entry const & symbol) const
306{
307 return symbols->find(symbol);
308}
309
310symbol_container::symbols_t::iterator profile_container::begin_symbol() const
311{
312 return symbols->begin();
313}
314
315symbol_container::symbols_t::iterator profile_container::end_symbol() const
316{
317 return symbols->end();
318}