| /** |
| * @file diff_container.cpp |
| * Container for diffed symbols |
| * |
| * @remark Copyright 2005 OProfile authors |
| * @remark Read the file COPYING |
| * |
| * @author Philippe Elie |
| * @author John Levon |
| */ |
| |
| /* older glibc has C99 INFINITY in _GNU_SOURCE */ |
| #ifndef _GNU_SOURCE |
| #define _GNU_SOURCE |
| #endif |
| |
| #include "diff_container.h" |
| |
| #include <cmath> |
| |
| using namespace std; |
| |
| |
| namespace { |
| |
| |
| /// a comparator suitable for diffing symbols |
| bool rough_less(symbol_entry const & lhs, symbol_entry const & rhs) |
| { |
| if (lhs.image_name != rhs.image_name) |
| return lhs.image_name < rhs.image_name; |
| |
| if (lhs.app_name != rhs.app_name) |
| return lhs.app_name < rhs.app_name; |
| |
| if (lhs.name != rhs.name) |
| return lhs.name < rhs.name; |
| |
| return false; |
| } |
| |
| |
| /// possibly add a diff sym |
| void |
| add_sym(diff_collection & syms, diff_symbol const & sym, |
| profile_container::symbol_choice & choice) |
| { |
| if (choice.match_image |
| && (image_names.name(sym.image_name) != choice.image_name)) |
| return; |
| |
| if (fabs(sym.diffs[0]) < choice.threshold) |
| return; |
| |
| choice.hints = sym.output_hint(choice.hints); |
| syms.push_back(sym); |
| } |
| |
| |
| /// add a symbol not present in the new profile |
| void |
| symbol_old(diff_collection & syms, symbol_entry const & sym, |
| profile_container::symbol_choice & choice) |
| { |
| diff_symbol symbol(sym); |
| symbol.diffs.fill(sym.sample.counts.size(), -INFINITY); |
| add_sym(syms, symbol, choice); |
| } |
| |
| |
| /// add a symbol not present in the old profile |
| void |
| symbol_new(diff_collection & syms, symbol_entry const & sym, |
| profile_container::symbol_choice & choice) |
| { |
| diff_symbol symbol(sym); |
| symbol.diffs.fill(sym.sample.counts.size(), INFINITY); |
| add_sym(syms, symbol, choice); |
| } |
| |
| |
| /// add a diffed symbol |
| void symbol_diff(diff_collection & syms, |
| symbol_entry const & sym1, count_array_t const & total1, |
| symbol_entry const & sym2, count_array_t const & total2, |
| profile_container::symbol_choice & choice) |
| { |
| diff_symbol symbol(sym2); |
| |
| size_t size = sym2.sample.counts.size(); |
| for (size_t i = 0; i != size; ++i) { |
| double percent1; |
| double percent2; |
| percent1 = op_ratio(sym1.sample.counts[i], total1[i]); |
| percent2 = op_ratio(sym2.sample.counts[i], total2[i]); |
| symbol.diffs[i] = op_ratio(percent2 - percent1, percent1); |
| symbol.diffs[i] *= 100.0; |
| } |
| |
| add_sym(syms, symbol, choice); |
| } |
| |
| |
| }; // namespace anon |
| |
| |
| diff_container::diff_container(profile_container const & c1, |
| profile_container const & c2) |
| : pc1(c1), pc2(c2), |
| total1(pc1.samples_count()), total2(pc2.samples_count()) |
| { |
| } |
| |
| |
| diff_collection const |
| diff_container::get_symbols(profile_container::symbol_choice & choice) const |
| { |
| diff_collection syms; |
| |
| /* |
| * Do a pairwise comparison of the two symbol sets. We're |
| * relying here on the symbol container being sorted such |
| * that rough_less() is suitable for iterating through the |
| * two lists (see less_symbol). |
| */ |
| |
| symbol_container::symbols_t::iterator it1 = pc1.begin_symbol(); |
| symbol_container::symbols_t::iterator end1 = pc1.end_symbol(); |
| symbol_container::symbols_t::iterator it2 = pc2.begin_symbol(); |
| symbol_container::symbols_t::iterator end2 = pc2.end_symbol(); |
| |
| while (it1 != end1 && it2 != end2) { |
| if (rough_less(*it1, *it2)) { |
| symbol_old(syms, *it1, choice); |
| ++it1; |
| } else if (rough_less(*it2, *it1)) { |
| symbol_new(syms, *it2, choice); |
| ++it2; |
| } else { |
| symbol_diff(syms, *it1, total1, *it2, total2, choice); |
| ++it1; |
| ++it2; |
| } |
| } |
| |
| for (; it1 != end1; ++it1) |
| symbol_old(syms, *it1, choice); |
| |
| for (; it2 != end2; ++it2) |
| symbol_new(syms, *it2, choice); |
| |
| return syms; |
| } |
| |
| |
| count_array_t const diff_container::samples_count() const |
| { |
| return total2; |
| } |