Home | History | Annotate | Download | only in libpp
      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 
     29 using namespace std;
     30 
     31 namespace {
     32 
     33 struct 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 
     52 profile_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 
     64 profile_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.
     73 void 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 
    133 void
    134 profile_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 
    164 symbol_collection const
    165 profile_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 
    193 vector<debug_name_id> const
    194 profile_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 
    247 count_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 
    255 symbol_entry const *
    256 profile_container::find_symbol(string const & image_name, bfd_vma vma) const
    257 {
    258 	return symbols->find_by_vma(image_name, vma);
    259 }
    260 
    261 
    262 symbol_collection const
    263 profile_container::find_symbol(debug_name_id filename, size_t linenr) const
    264 {
    265 	return symbols->find(filename, linenr);
    266 }
    267 
    268 
    269 symbol_collection const
    270 profile_container::select_symbols(debug_name_id filename) const
    271 {
    272 	return symbols->find(filename);
    273 }
    274 
    275 sample_entry const *
    276 profile_container::find_sample(symbol_entry const * symbol, bfd_vma vma) const
    277 {
    278 	return samples->find_by_vma(symbol, vma);
    279 }
    280 
    281 
    282 count_array_t profile_container::samples_count(debug_name_id filename_id) const
    283 {
    284 	return samples->accumulate_samples(filename_id);
    285 }
    286 
    287 
    288 count_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 
    295 sample_container::samples_iterator
    296 profile_container::begin(symbol_entry const * symbol) const
    297 {
    298 	return samples->begin(symbol);
    299 }
    300 
    301 
    302 sample_container::samples_iterator
    303 profile_container::end(symbol_entry const * symbol) const
    304 {
    305 	return samples->end(symbol);
    306 }
    307 
    308 
    309 sample_container::samples_iterator profile_container::begin() const
    310 {
    311 	return samples->begin();
    312 }
    313 
    314 
    315 sample_container::samples_iterator profile_container::end() const
    316 {
    317 	return samples->end();
    318 }
    319 
    320 symbol_entry const * profile_container::find(symbol_entry const & symbol) const
    321 {
    322 	return symbols->find(symbol);
    323 }
    324 
    325 symbol_container::symbols_t::iterator profile_container::begin_symbol() const
    326 {
    327 	return symbols->begin();
    328 }
    329 
    330 symbol_container::symbols_t::iterator profile_container::end_symbol() const
    331 {
    332 	return symbols->end();
    333 }
    334