opreport_options.cpp revision cc2ee177dbb3befca43e36cfc56778b006c3d050
1/**
2 * @file opreport_options.cpp
3 * Options for opreport tool
4 *
5 * @remark Copyright 2003 OProfile authors
6 * @remark Read the file COPYING
7 *
8 * @author John Levon
9 * @author Philippe Elie
10 */
11
12#include <vector>
13#include <list>
14#include <iostream>
15#include <algorithm>
16#include <iterator>
17#include <fstream>
18
19#include "profile_spec.h"
20#include "arrange_profiles.h"
21#include "opreport_options.h"
22#include "popt_options.h"
23#include "string_filter.h"
24#include "file_manip.h"
25#include "cverb.h"
26
27using namespace std;
28
29profile_classes classes;
30profile_classes classes2;
31
32namespace options {
33	string archive_path;
34	string archive_path2;
35	demangle_type demangle = dmt_normal;
36	bool symbols;
37	bool callgraph;
38	bool debug_info;
39	bool details;
40	bool exclude_dependent;
41	string_filter symbol_filter;
42	sort_options sort_by;
43	merge_option merge_by;
44	bool show_header = true;
45	bool long_filenames;
46	bool show_address;
47	bool accumulated;
48	bool reverse_sort;
49	bool global_percent;
50}
51
52
53namespace {
54
55string outfile;
56vector<string> mergespec;
57vector<string> sort;
58vector<string> exclude_symbols;
59vector<string> include_symbols;
60string demangle_option = "normal";
61
62popt::option options_array[] = {
63	popt::option(options::callgraph, "callgraph", 'c',
64	             "show call graph"),
65	popt::option(options::details, "details", 'd',
66		     "output detailed samples for each symbol"),
67	popt::option(options::symbols, "symbols", 'l',
68		     "list all symbols"),
69
70	popt::option(outfile, "output-file", 'o',
71	             "output to the given filename", "file"),
72
73	popt::option(sort, "sort", 's',
74		     "sort by", "sample,image,app-name,symbol,debug,vma"),
75	popt::option(options::reverse_sort, "reverse-sort", 'r',
76		     "use reverse sort"),
77	popt::option(mergespec, "merge", 'm',
78		     "comma separated list", "cpu,lib,tid,tgid,unitmask,all"),
79	popt::option(options::exclude_dependent, "exclude-dependent", 'x',
80		     "exclude libs, kernel, and module samples for applications"),
81	popt::option(exclude_symbols, "exclude-symbols", 'e',
82		     "exclude these comma separated symbols", "symbols"),
83	popt::option(include_symbols, "include-symbols", 'i',
84		     "include these comma separated symbols", "symbols"),
85	popt::option(options::threshold_opt, "threshold", 't',
86		     "minimum percentage needed to produce output",
87		     "percent"),
88
89	popt::option(demangle_option, "demangle", 'D',
90		     "demangle GNU C++ symbol names (default normal)",
91	             "none|normal|smart"),
92	// PP:5
93	popt::option(options::debug_info, "debug-info", 'g',
94		     "add source file and line number to output"),
95	popt::option(options::show_header, "no-header", 'n',
96		     "remove all headers from output"),
97	popt::option(options::show_address, "show-address", 'w',
98	             "show VMA address of each symbol"),
99	popt::option(options::long_filenames, "long-filenames", 'f',
100		     "show the full path of filenames"),
101	popt::option(options::accumulated, "accumulated", 'a',
102		     "percentage field show accumulated count"),
103	popt::option(options::global_percent, "global-percent", '%',
104		     "percentage are not relative to symbol count or image "
105		     "count but total sample count"),
106};
107
108
109void handle_sort_option()
110{
111	if (sort.empty()) {
112		// PP:5.14 sort default to sample
113		sort.push_back("sample");
114	}
115
116	vector<string>::const_iterator cit = sort.begin();
117	vector<string>::const_iterator end = sort.end();
118
119	for (; cit != end; ++cit) {
120		options::sort_by.add_sort_option(*cit);
121	}
122}
123
124
125void handle_output_file()
126{
127	if (outfile.empty())
128		return;
129
130	static ofstream os(outfile.c_str());
131	if (!os) {
132		cerr << "Couldn't open \"" << outfile
133		     << "\" for writing." << endl;
134		exit(EXIT_FAILURE);
135	}
136
137	cout.rdbuf(os.rdbuf());
138}
139
140
141///  Check incompatible or meaningless options.
142void check_options(bool diff)
143{
144	using namespace options;
145
146	bool do_exit = false;
147
148	if (callgraph) {
149		symbols = true;
150		if (details) {
151			cerr << "--callgraph is incompatible with --details" << endl;
152			do_exit = true;
153		}
154
155		if (diff) {
156			cerr << "differential profiles are incompatible with --callgraph" << endl;
157			do_exit = true;
158		}
159	}
160
161	if (details && diff) {
162		cerr << "differential profiles are incompatible with --details" << endl;
163		do_exit = true;
164	}
165
166	if (!symbols) {
167		if (diff) {
168			cerr << "different profiles are meaningless "
169				"without --symbols" << endl;
170			do_exit = true;
171		}
172
173		if (show_address) {
174			cerr << "--show-address is meaningless "
175				"without --symbols" << endl;
176			do_exit = true;
177		}
178
179		if (debug_info || accumulated) {
180			cerr << "--debug-info and --accumulated are "
181			     << "meaningless without --symbols" << endl;
182			do_exit = true;
183		}
184
185		if (!exclude_symbols.empty() || !include_symbols.empty()) {
186			cerr << "--exclude-symbols and --include-symbols are "
187			     << "meaningless without --symbols" << endl;
188			do_exit = true;
189		}
190
191		if (find(sort_by.options.begin(), sort_by.options.end(),
192			 sort_options::vma) != sort_by.options.end()) {
193			cerr << "--sort=vma is "
194			     << "meaningless without --symbols" << endl;
195			do_exit = true;
196		}
197	}
198
199	if (global_percent && symbols && !(details || callgraph)) {
200		cerr << "--global-percent is meaningless with --symbols "
201		        "and without --details or --callgraph" << endl;
202		do_exit = true;
203	}
204
205	if (do_exit)
206		exit(EXIT_FAILURE);
207}
208
209
210/// process a spec into classes
211string process_spec(profile_classes & classes, list<string> const & spec)
212{
213	using namespace options;
214
215	copy(spec.begin(), spec.end(),
216	     ostream_iterator<string>(cverb << vsfile, " "));
217	cverb << vsfile << "\n\n";
218
219	profile_spec const pspec =
220		profile_spec::create(spec, extra_found_images);
221
222	list<string> sample_files = pspec.generate_file_list(exclude_dependent,
223	                                                     !options::callgraph);
224
225	cverb << vsfile << "Archive: " << pspec.get_archive_path() << endl;
226
227	cverb << vsfile << "Matched sample files: " << sample_files.size()
228	      << endl;
229	copy(sample_files.begin(), sample_files.end(),
230	     ostream_iterator<string>(cverb << vsfile, "\n"));
231
232	classes = arrange_profiles(sample_files, merge_by);
233
234	cverb << vsfile << "profile_classes:\n" << classes << endl;
235
236	if (classes.v.empty()) {
237		cerr << "error: no sample files found: profile specification "
238		     "too strict ?" << endl;
239		exit(EXIT_FAILURE);
240	}
241
242	return pspec.get_archive_path();
243}
244
245
246} // namespace anon
247
248
249void handle_options(options::spec const & spec)
250{
251	using namespace options;
252
253	if (details) {
254		symbols = true;
255		show_address = true;
256	}
257
258	handle_sort_option();
259	merge_by = handle_merge_option(mergespec, true, exclude_dependent);
260	handle_output_file();
261	demangle = handle_demangle_option(demangle_option);
262	check_options(spec.first.size());
263
264	symbol_filter = string_filter(include_symbols, exclude_symbols);
265
266	if (!spec.first.size()) {
267		archive_path = process_spec(classes, spec.common);
268	} else {
269		cverb << vsfile << "profile spec 1:" << endl;
270		archive_path = process_spec(classes, spec.first);
271		cverb << vsfile << "profile spec 2:" << endl;
272		archive_path2 = process_spec(classes2, spec.second);
273
274		if (!classes.matches(classes2)) {
275			cerr << "profile classes are incompatible" << endl;
276			exit(EXIT_FAILURE);
277		}
278	}
279}
280