1/**
2 * @file symbol_sort.cpp
3 * Sorting symbols
4 *
5 * @remark Copyright 2002, 2003 OProfile authors
6 * @remark Read the file COPYING
7 *
8 * @author Philippe Elie
9 * @author John Levon
10 */
11
12#include "symbol_sort.h"
13#include "symbol_functors.h"
14
15#include "name_storage.h"
16#include "op_exception.h"
17
18#include <algorithm>
19#include <sstream>
20
21using namespace std;
22
23namespace {
24
25bool long_filenames;
26
27int image_compare(image_name_id l, image_name_id r)
28{
29	if (long_filenames)
30		return image_names.name(l).compare(image_names.name(r));
31	return image_names.basename(l).compare(image_names.basename(r));
32}
33
34
35int debug_compare(debug_name_id l, debug_name_id r)
36{
37	if (long_filenames)
38		return debug_names.name(l).compare(debug_names.name(r));
39	return debug_names.basename(l).compare(debug_names.basename(r));
40}
41
42
43int compare_by(sort_options::sort_order order,
44               symbol_entry const & lhs, symbol_entry const & rhs)
45{
46	switch (order) {
47		case sort_options::sample:
48			if (lhs.sample.counts[0] < rhs.sample.counts[0])
49				return 1;
50			if (lhs.sample.counts[0] > rhs.sample.counts[0])
51				return -1;
52			return 0;
53
54		case sort_options::symbol:
55			return symbol_names.demangle(lhs.name).compare(
56				symbol_names.demangle(rhs.name));
57
58		case sort_options::image:
59			return image_compare(lhs.image_name, rhs.image_name);
60
61		case sort_options::app_name:
62			return image_compare(lhs.app_name, rhs.app_name);
63
64		case sort_options::vma:
65			if (lhs.sample.vma < rhs.sample.vma)
66				return -1;
67			if (lhs.sample.vma > rhs.sample.vma)
68				return 1;
69			return 0;
70
71		case sort_options::debug: {
72			file_location const & f1 = lhs.sample.file_loc;
73			file_location const & f2 = rhs.sample.file_loc;
74			int ret = debug_compare(f1.filename, f2.filename);
75			if (ret == 0)
76				ret = f1.linenr - f2.linenr;
77			return ret;
78		}
79
80		default: {
81			// static_cast<> to shut up g++ 2.91.66 which warn
82			// about ambiguity between <<(int) and <<(long int)
83			ostringstream os;
84			os << "compare_by(): unknown sort option: "
85			   << static_cast<int>(order) << endl;
86			throw op_fatal_error(os.str());
87		}
88	}
89
90	return 0;
91}
92
93
94struct symbol_compare {
95	symbol_compare(vector<sort_options::sort_order> const & order,
96	               bool reverse)
97		: compare_order(order), reverse_sort(reverse) {}
98
99	bool operator()(symbol_entry const * lhs,
100			symbol_entry const * rhs) const {
101		return operator()(*lhs, *rhs);
102	}
103
104	bool operator()(symbol_entry const & lhs,
105			symbol_entry const & rhs) const;
106
107protected:
108	vector<sort_options::sort_order> const & compare_order;
109	bool reverse_sort;
110};
111
112
113bool symbol_compare::operator()(symbol_entry const & lhs,
114				symbol_entry const & rhs) const
115{
116	for (size_t i = 0; i < compare_order.size(); ++i) {
117		int ret = compare_by(compare_order[i], lhs, rhs);
118
119		if (reverse_sort)
120			ret = -ret;
121		if (ret != 0)
122			return ret < 0;
123	}
124	return false;
125}
126
127
128} // anonymous namespace
129
130
131void sort_options::
132sort(symbol_collection & syms, bool reverse_sort, bool lf) const
133{
134	long_filenames = lf;
135
136	vector<sort_order> sort_option(options);
137	for (sort_order cur = first; cur != last; cur = sort_order(cur + 1)) {
138		if (find(sort_option.begin(), sort_option.end(), cur) ==
139		    sort_option.end())
140			sort_option.push_back(cur);
141	}
142
143	stable_sort(syms.begin(), syms.end(),
144	            symbol_compare(sort_option, reverse_sort));
145}
146
147
148void sort_options::
149sort(diff_collection & syms, bool reverse_sort, bool lf) const
150{
151	long_filenames = lf;
152
153	vector<sort_order> sort_option(options);
154	for (sort_order cur = first; cur != last; cur = sort_order(cur + 1)) {
155		if (find(sort_option.begin(), sort_option.end(), cur) ==
156		    sort_option.end())
157			sort_option.push_back(cur);
158	}
159
160	stable_sort(syms.begin(), syms.end(),
161	            symbol_compare(sort_option, reverse_sort));
162}
163
164
165void sort_options::add_sort_option(string const & name)
166{
167	if (name == "vma") {
168		options.push_back(vma);
169	} else if (name == "sample") {
170		options.push_back(sample);
171	} else if (name == "symbol") {
172		options.push_back(symbol);
173	} else if (name == "debug") {
174		options.push_back(debug);
175	} else if (name == "image") {
176		options.push_back(image);
177	} else if (name == "app-name") {
178		options.push_back(app_name);
179	} else {
180		ostringstream os;
181		os << "unknown sort option: " << name << endl;
182		throw op_fatal_error(os.str());
183	}
184}
185
186
187void sort_options::add_sort_option(sort_options::sort_order order)
188{
189	options.push_back(order);
190}
191