/** * @file profile_container.cpp * profile file container * * @remark Copyright 2002 OProfile authors * @remark Read the file COPYING * * @author Philippe Elie * @author John Levon */ #include <set> #include <vector> #include <string> #include <iostream> #include <sstream> #include <algorithm> #include <numeric> #include "symbol.h" #include "op_header.h" #include "profile.h" #include "symbol_functors.h" #include "profile_container.h" #include "sample_container.h" #include "symbol_container.h" #include "populate_for_spu.h" using namespace std; namespace { struct filename_by_samples { filename_by_samples(debug_name_id id, double percent_) : filename(id), percent(percent_) {} bool operator<(filename_by_samples const & lhs) const { if (percent != lhs.percent) return percent < lhs.percent; return filename < lhs.filename; } debug_name_id filename; // ratio of samples which belongs to this filename. double percent; }; } // anon namespace profile_container::profile_container(bool debug_info_, bool need_details_, extra_images const & extra_) : symbols(new symbol_container), samples(new sample_container), debug_info(debug_info_), need_details(need_details_), extra_found_images(extra_) { } profile_container::~profile_container() { } // Post condition: // the symbols/samples are sorted by increasing vma. // the range of sample_entry inside each symbol entry are valid // the samples_by_file_loc member var is correctly setup. void profile_container::add(profile_t const & profile, op_bfd const & abfd, string const & app_name, size_t pclass) { string const image_name = abfd.get_filename(); opd_header header = profile.get_header(); for (symbol_index_t i = 0; i < abfd.syms.size(); ++i) { unsigned long long start = 0, end = 0; symbol_entry symb_entry; abfd.get_symbol_range(i, start, end); profile_t::iterator_pair p_it = profile.samples_range(start, end); count_type count = accumulate(p_it.first, p_it.second, 0ull); // skip entries with no samples if (count == 0) continue; symb_entry.sample.counts[pclass] = count; total_count[pclass] += count; symb_entry.size = end - start; symb_entry.name = symbol_names.create(abfd.syms[i].name()); symb_entry.sym_index = i; symb_entry.sample.file_loc.linenr = 0; if (debug_info) { string filename; if (abfd.get_linenr(i, start, filename, symb_entry.sample.file_loc.linenr)) { symb_entry.sample.file_loc.filename = debug_names.create(filename); } } symb_entry.image_name = image_names.create(image_name); symb_entry.app_name = image_names.create(app_name); symb_entry.sample.vma = abfd.syms[i].vma(); if ((header.spu_profile == cell_spu_profile) && header.embedded_offset) { symb_entry.spu_offset = header.embedded_offset; symb_entry.embedding_filename = image_names.create(abfd.get_embedding_filename()); } else { symb_entry.spu_offset = 0; } symbol_entry const * symbol = symbols->insert(symb_entry); if (need_details) add_samples(abfd, i, p_it, symbol, pclass, start); } } void profile_container::add_samples(op_bfd const & abfd, symbol_index_t sym_index, profile_t::iterator_pair const & p_it, symbol_entry const * symbol, size_t pclass, unsigned long start) { bfd_vma base_vma = abfd.syms[sym_index].vma(); profile_t::const_iterator it; for (it = p_it.first; it != p_it.second ; ++it) { sample_entry sample; sample.counts[pclass] = it.count(); sample.file_loc.linenr = 0; if (debug_info) { string filename; if (abfd.get_linenr(sym_index, it.vma(), filename, sample.file_loc.linenr)) { sample.file_loc.filename = debug_names.create(filename); } } sample.vma = (it.vma() - start) + base_vma; samples->insert(symbol, sample); } } symbol_collection const profile_container::select_symbols(symbol_choice & choice) const { symbol_collection result; double const threshold = choice.threshold / 100.0; symbol_container::symbols_t::iterator it = symbols->begin(); symbol_container::symbols_t::iterator const end = symbols->end(); for (; it != end; ++it) { if (choice.match_image && (image_names.name(it->image_name) != choice.image_name)) continue; double const percent = op_ratio(it->sample.counts[0], total_count[0]); if (percent >= threshold) { result.push_back(&*it); choice.hints = it->output_hint(choice.hints); } } return result; } vector<debug_name_id> const profile_container::select_filename(double threshold) const { set<debug_name_id> filename_set; threshold /= 100.0; // Trying to iterate on symbols to create the set of filenames which // contain sample does not work: a symbol can contain samples and this // symbol is in a source file that contain zero sample because only // inline function in this source file contains samples. sample_container::samples_iterator sit = samples->begin(); sample_container::samples_iterator const send = samples->end(); for (; sit != send; ++sit) { debug_name_id name_id = sit->second.file_loc.filename; if (name_id.set()) filename_set.insert(name_id); } // Give a sort order on filename for the selected pclass. vector<filename_by_samples> file_by_samples; set<debug_name_id>::const_iterator it = filename_set.begin(); set<debug_name_id>::const_iterator const end = filename_set.end(); for (; it != end; ++it) { // FIXME: is samples_count() the right interface now ? count_array_t counts = samples_count(*it); double const ratio = op_ratio(counts[0], total_count[0]); filename_by_samples const f(*it, ratio); file_by_samples.push_back(f); } // now sort the file_by_samples entry. sort(file_by_samples.begin(), file_by_samples.end()); // 2.91.66 doesn't like const_reverse_iterator in this context vector<filename_by_samples>::reverse_iterator cit = file_by_samples.rbegin(); vector<filename_by_samples>::reverse_iterator const cend = file_by_samples.rend(); vector<debug_name_id> result; for (; cit != cend; ++cit) { if (cit->percent >= threshold) result.push_back(cit->filename); } return result; } count_array_t profile_container::samples_count() const { return total_count; } // Rest here are delegated to our private implementation. symbol_entry const * profile_container::find_symbol(string const & image_name, bfd_vma vma) const { return symbols->find_by_vma(image_name, vma); } symbol_collection const profile_container::find_symbol(debug_name_id filename, size_t linenr) const { return symbols->find(filename, linenr); } symbol_collection const profile_container::select_symbols(debug_name_id filename) const { return symbols->find(filename); } sample_entry const * profile_container::find_sample(symbol_entry const * symbol, bfd_vma vma) const { return samples->find_by_vma(symbol, vma); } count_array_t profile_container::samples_count(debug_name_id filename_id) const { return samples->accumulate_samples(filename_id); } count_array_t profile_container::samples_count(debug_name_id filename, size_t linenr) const { return samples->accumulate_samples(filename, linenr); } sample_container::samples_iterator profile_container::begin(symbol_entry const * symbol) const { return samples->begin(symbol); } sample_container::samples_iterator profile_container::end(symbol_entry const * symbol) const { return samples->end(symbol); } sample_container::samples_iterator profile_container::begin() const { return samples->begin(); } sample_container::samples_iterator profile_container::end() const { return samples->end(); } symbol_entry const * profile_container::find(symbol_entry const & symbol) const { return symbols->find(symbol); } symbol_container::symbols_t::iterator profile_container::begin_symbol() const { return symbols->begin(); } symbol_container::symbols_t::iterator profile_container::end_symbol() const { return symbols->end(); }