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