1/** 2 * @file diff_container.cpp 3 * Container for diffed symbols 4 * 5 * @remark Copyright 2005 OProfile authors 6 * @remark Read the file COPYING 7 * 8 * @author Philippe Elie 9 * @author John Levon 10 */ 11 12/* older glibc has C99 INFINITY in _GNU_SOURCE */ 13#ifndef _GNU_SOURCE 14#define _GNU_SOURCE 15#endif 16 17#include "diff_container.h" 18 19#include <cmath> 20 21using namespace std; 22 23 24namespace { 25 26 27/// a comparator suitable for diffing symbols 28bool rough_less(symbol_entry const & lhs, symbol_entry const & rhs) 29{ 30 if (lhs.image_name != rhs.image_name) 31 return lhs.image_name < rhs.image_name; 32 33 if (lhs.app_name != rhs.app_name) 34 return lhs.app_name < rhs.app_name; 35 36 if (lhs.name != rhs.name) 37 return lhs.name < rhs.name; 38 39 return false; 40} 41 42 43/// possibly add a diff sym 44void 45add_sym(diff_collection & syms, diff_symbol const & sym, 46 profile_container::symbol_choice & choice) 47{ 48 if (choice.match_image 49 && (image_names.name(sym.image_name) != choice.image_name)) 50 return; 51 52 if (fabs(sym.diffs[0]) < choice.threshold) 53 return; 54 55 choice.hints = sym.output_hint(choice.hints); 56 syms.push_back(sym); 57} 58 59 60/// add a symbol not present in the new profile 61void 62symbol_old(diff_collection & syms, symbol_entry const & sym, 63 profile_container::symbol_choice & choice) 64{ 65 diff_symbol symbol(sym); 66 symbol.diffs.fill(sym.sample.counts.size(), -INFINITY); 67 add_sym(syms, symbol, choice); 68} 69 70 71/// add a symbol not present in the old profile 72void 73symbol_new(diff_collection & syms, symbol_entry const & sym, 74 profile_container::symbol_choice & choice) 75{ 76 diff_symbol symbol(sym); 77 symbol.diffs.fill(sym.sample.counts.size(), INFINITY); 78 add_sym(syms, symbol, choice); 79} 80 81 82/// add a diffed symbol 83void symbol_diff(diff_collection & syms, 84 symbol_entry const & sym1, count_array_t const & total1, 85 symbol_entry const & sym2, count_array_t const & total2, 86 profile_container::symbol_choice & choice) 87{ 88 diff_symbol symbol(sym2); 89 90 size_t size = sym2.sample.counts.size(); 91 for (size_t i = 0; i != size; ++i) { 92 double percent1; 93 double percent2; 94 percent1 = op_ratio(sym1.sample.counts[i], total1[i]); 95 percent2 = op_ratio(sym2.sample.counts[i], total2[i]); 96 symbol.diffs[i] = op_ratio(percent2 - percent1, percent1); 97 symbol.diffs[i] *= 100.0; 98 } 99 100 add_sym(syms, symbol, choice); 101} 102 103 104}; // namespace anon 105 106 107diff_container::diff_container(profile_container const & c1, 108 profile_container const & c2) 109 : pc1(c1), pc2(c2), 110 total1(pc1.samples_count()), total2(pc2.samples_count()) 111{ 112} 113 114 115diff_collection const 116diff_container::get_symbols(profile_container::symbol_choice & choice) const 117{ 118 diff_collection syms; 119 120 /* 121 * Do a pairwise comparison of the two symbol sets. We're 122 * relying here on the symbol container being sorted such 123 * that rough_less() is suitable for iterating through the 124 * two lists (see less_symbol). 125 */ 126 127 symbol_container::symbols_t::iterator it1 = pc1.begin_symbol(); 128 symbol_container::symbols_t::iterator end1 = pc1.end_symbol(); 129 symbol_container::symbols_t::iterator it2 = pc2.begin_symbol(); 130 symbol_container::symbols_t::iterator end2 = pc2.end_symbol(); 131 132 while (it1 != end1 && it2 != end2) { 133 if (rough_less(*it1, *it2)) { 134 symbol_old(syms, *it1, choice); 135 ++it1; 136 } else if (rough_less(*it2, *it1)) { 137 symbol_new(syms, *it2, choice); 138 ++it2; 139 } else { 140 symbol_diff(syms, *it1, total1, *it2, total2, choice); 141 ++it1; 142 ++it2; 143 } 144 } 145 146 for (; it1 != end1; ++it1) 147 symbol_old(syms, *it1, choice); 148 149 for (; it2 != end2; ++it2) 150 symbol_new(syms, *it2, choice); 151 152 return syms; 153} 154 155 156count_array_t const diff_container::samples_count() const 157{ 158 return total2; 159} 160