Home | History | Annotate | Download | only in pp
      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 
    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 
    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.
    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
    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 
    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