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