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 21 using namespace std; 22 23 24 namespace { 25 26 27 /// a comparator suitable for diffing symbols 28 bool 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 44 void 45 add_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 61 void 62 symbol_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 72 void 73 symbol_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 83 void 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 107 diff_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 115 diff_collection const 116 diff_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 156 count_array_t const diff_container::samples_count() const 157 { 158 return total2; 159 } 160