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 29using namespace std; 30 31profile_classes classes; 32profile_classes classes2; 33 34namespace 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 55namespace { 56 57string outfile; 58vector<string> mergespec; 59vector<string> sort; 60vector<string> exclude_symbols; 61vector<string> include_symbols; 62string demangle_option = "normal"; 63 64popt::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 115void 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 145void 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. 162void 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 244void 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 282void 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