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