Home | History | Annotate | Download | only in libpp
      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