| /** |
| * @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(); |
| } |