• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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