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