• 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