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 "xml_output.h"
26 #include "xml_utils.h"
27 #include "cverb.h"
28
29 using namespace std;
30
31 profile_classes classes;
32 profile_classes classes2;
33
34 namespace options {
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 bool xml;
51 string xml_options;
52 }
53
54
55 namespace {
56
57 string outfile;
58 vector<string> mergespec;
59 vector<string> sort;
60 vector<string> exclude_symbols;
61 vector<string> include_symbols;
62 string demangle_option = "normal";
63
64 popt::option options_array[] = {
65 popt::option(options::callgraph, "callgraph", 'c',
66 "show call graph"),
67 popt::option(options::details, "details", 'd',
68 "output detailed samples for each symbol"),
69 popt::option(options::symbols, "symbols", 'l',
70 "list all symbols"),
71
72 popt::option(outfile, "output-file", 'o',
73 "output to the given filename", "file"),
74
75 popt::option(sort, "sort", 's',
76 "sort by", "sample,image,app-name,symbol,debug,vma"),
77 popt::option(options::reverse_sort, "reverse-sort", 'r',
78 "use reverse sort"),
79 popt::option(mergespec, "merge", 'm',
80 "comma separated list", "cpu,lib,tid,tgid,unitmask,all"),
81 popt::option(options::exclude_dependent, "exclude-dependent", 'x',
82 "exclude libs, kernel, and module samples for applications"),
83 popt::option(exclude_symbols, "exclude-symbols", 'e',
84 "exclude these comma separated symbols", "symbols"),
85 popt::option(include_symbols, "include-symbols", 'i',
86 "include these comma separated symbols", "symbols"),
87 popt::option(options::threshold_opt, "threshold", 't',
88 "minimum percentage needed to produce output",
89 "percent"),
90
91 popt::option(demangle_option, "demangle", 'D',
92 "demangle GNU C++ symbol names (default normal)",
93 "none|normal|smart"),
94 // PP:5
95 popt::option(options::debug_info, "debug-info", 'g',
96 "add source file and line number to output"),
97 popt::option(options::show_header, "no-header", 'n',
98 "remove all headers from output"),
99 popt::option(options::show_address, "show-address", 'w',
100 "show VMA address of each symbol"),
101 popt::option(options::long_filenames, "long-filenames", 'f',
102 "show the full path of filenames"),
103 popt::option(options::accumulated, "accumulated", 'a',
104 "percentage field show accumulated count"),
105 popt::option(options::global_percent, "global-percent", '%',
106 "percentage are not relative to symbol count or image "
107 "count but total sample count"),
108
109 popt::option(options::xml, "xml", 'X',
110 "XML output"),
111
112 };
113
114
handle_sort_option()115 void handle_sort_option()
116 {
117 if (options::xml && !sort.empty()) {
118 cerr << "warning: sort options ignored because they "
119 << "are incompatible with --xml" << endl;
120 // don't allow any other sorting, except the default below,
121 // to mess up symbol traversal for XML
122 sort.clear();
123 }
124
125 if (sort.empty() || options::xml) {
126 // PP:5.14 sort default to sample
127 if (options::xml) {
128 // implicitly sort by app-name,image so that in the
129 // symbol traversal all library module symbols are
130 // grouped together with their application
131 sort.push_back("app-name");
132 sort.push_back("image");
133 } else
134 sort.push_back("sample");
135 }
136
137 vector<string>::const_iterator cit = sort.begin();
138 vector<string>::const_iterator end = sort.end();
139
140 for (; cit != end; ++cit)
141 options::sort_by.add_sort_option(*cit);
142 }
143
144
handle_output_file()145 void handle_output_file()
146 {
147 if (outfile.empty())
148 return;
149
150 static ofstream os(outfile.c_str());
151 if (!os) {
152 cerr << "Couldn't open \"" << outfile
153 << "\" for writing." << endl;
154 exit(EXIT_FAILURE);
155 }
156
157 cout.rdbuf(os.rdbuf());
158 }
159
160
161 /// Check incompatible or meaningless options.
check_options(bool diff)162 void check_options(bool diff)
163 {
164 using namespace options;
165
166 bool do_exit = false;
167
168 if (callgraph) {
169 symbols = true;
170 if (details) {
171 cerr << "--callgraph is incompatible with --details" << endl;
172 do_exit = true;
173 }
174
175 if (diff) {
176 cerr << "differential profiles are incompatible with --callgraph" << endl;
177 do_exit = true;
178 }
179 }
180
181 if (xml) {
182 if (accumulated) {
183 cerr << "--accumulated is incompatible with --xml" << endl;
184 do_exit = true;
185 }
186
187 if (global_percent) {
188 cerr << "--global_percent is incompatible with --xml" << endl;
189 do_exit = true;
190 }
191 }
192
193
194 if (details && diff) {
195 cerr << "differential profiles are incompatible with --details" << endl;
196 do_exit = true;
197 }
198
199 if (!symbols) {
200 if (diff) {
201 cerr << "different profiles are meaningless "
202 "without --symbols" << endl;
203 do_exit = true;
204 }
205
206 if (show_address) {
207 cerr << "--show-address is meaningless "
208 "without --symbols" << endl;
209 do_exit = true;
210 }
211
212 if (debug_info || accumulated) {
213 cerr << "--debug-info and --accumulated are "
214 << "meaningless without --symbols" << endl;
215 do_exit = true;
216 }
217
218 if (!exclude_symbols.empty() || !include_symbols.empty()) {
219 cerr << "--exclude-symbols and --include-symbols are "
220 << "meaningless without --symbols" << endl;
221 do_exit = true;
222 }
223
224 if (find(sort_by.options.begin(), sort_by.options.end(),
225 sort_options::vma) != sort_by.options.end()) {
226 cerr << "--sort=vma is "
227 << "meaningless without --symbols" << endl;
228 do_exit = true;
229 }
230 }
231
232 if (global_percent && symbols && !(details || callgraph)) {
233 cerr << "--global-percent is meaningless with --symbols "
234 "and without --details or --callgraph" << endl;
235 do_exit = true;
236 }
237
238 if (do_exit)
239 exit(EXIT_FAILURE);
240 }
241
242
243 /// process a spec into classes
process_spec(profile_classes & classes,list<string> const & spec)244 void process_spec(profile_classes & classes, list<string> const & spec)
245 {
246 using namespace options;
247
248 copy(spec.begin(), spec.end(),
249 ostream_iterator<string>(cverb << vsfile, " "));
250 cverb << vsfile << "\n\n";
251
252 profile_spec const pspec =
253 profile_spec::create(spec, options::image_path,
254 options::root_path);
255
256 list<string> sample_files = pspec.generate_file_list(exclude_dependent,
257 !options::callgraph);
258
259 cverb << vsfile << "Archive: " << pspec.get_archive_path() << endl;
260
261 cverb << vsfile << "Matched sample files: " << sample_files.size()
262 << endl;
263 copy(sample_files.begin(), sample_files.end(),
264 ostream_iterator<string>(cverb << vsfile, "\n"));
265
266 classes = arrange_profiles(sample_files, merge_by,
267 pspec.extra_found_images);
268
269 cverb << vsfile << "profile_classes:\n" << classes << endl;
270
271 if (classes.v.empty()) {
272 cerr << "error: no sample files found: profile specification "
273 "too strict ?" << endl;
274 exit(EXIT_FAILURE);
275 }
276 }
277
278
279 } // namespace anon
280
281
handle_options(options::spec const & spec)282 void handle_options(options::spec const & spec)
283 {
284 using namespace options;
285
286 if (details) {
287 symbols = true;
288 show_address = true;
289 }
290
291 if (options::xml) {
292 if (spec.common.size() != 0)
293 xml_utils::add_option(SESSION, spec.common);
294 if (debug_info)
295 xml_utils::add_option(DEBUG_INFO, true);
296 if (details)
297 xml_utils::add_option(DETAILS, true);
298 if (!image_path.empty())
299 xml_utils::add_option(IMAGE_PATH, image_path);
300 if (!mergespec.empty())
301 xml_utils::add_option(MERGE, mergespec);
302 if (exclude_dependent)
303 xml_utils::add_option(EXCLUDE_DEPENDENT, true);
304 if (!exclude_symbols.empty())
305 xml_utils::add_option(EXCLUDE_SYMBOLS, exclude_symbols);
306 if (!include_symbols.empty())
307 xml_utils::add_option(INCLUDE_SYMBOLS, include_symbols);
308 }
309
310 handle_sort_option();
311 merge_by = handle_merge_option(mergespec, true, exclude_dependent);
312 handle_output_file();
313 demangle = handle_demangle_option(demangle_option);
314 check_options(spec.first.size());
315
316 symbol_filter = string_filter(include_symbols, exclude_symbols);
317
318 if (!spec.first.size()) {
319 process_spec(classes, spec.common);
320 } else {
321 if (options::xml) {
322 cerr << "differential profiles are incompatible with --xml" << endl;
323 exit(EXIT_FAILURE);
324 }
325 cverb << vsfile << "profile spec 1:" << endl;
326 process_spec(classes, spec.first);
327 cverb << vsfile << "profile spec 2:" << endl;
328 process_spec(classes2, spec.second);
329
330 if (!classes.matches(classes2)) {
331 cerr << "profile classes are incompatible" << endl;
332 exit(EXIT_FAILURE);
333 }
334 }
335 }
336