opreport_options.cpp revision cc2ee177dbb3befca43e36cfc56778b006c3d050
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 "cverb.h" 26 27using namespace std; 28 29profile_classes classes; 30profile_classes classes2; 31 32namespace options { 33 string archive_path; 34 string archive_path2; 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} 51 52 53namespace { 54 55string outfile; 56vector<string> mergespec; 57vector<string> sort; 58vector<string> exclude_symbols; 59vector<string> include_symbols; 60string demangle_option = "normal"; 61 62popt::option options_array[] = { 63 popt::option(options::callgraph, "callgraph", 'c', 64 "show call graph"), 65 popt::option(options::details, "details", 'd', 66 "output detailed samples for each symbol"), 67 popt::option(options::symbols, "symbols", 'l', 68 "list all symbols"), 69 70 popt::option(outfile, "output-file", 'o', 71 "output to the given filename", "file"), 72 73 popt::option(sort, "sort", 's', 74 "sort by", "sample,image,app-name,symbol,debug,vma"), 75 popt::option(options::reverse_sort, "reverse-sort", 'r', 76 "use reverse sort"), 77 popt::option(mergespec, "merge", 'm', 78 "comma separated list", "cpu,lib,tid,tgid,unitmask,all"), 79 popt::option(options::exclude_dependent, "exclude-dependent", 'x', 80 "exclude libs, kernel, and module samples for applications"), 81 popt::option(exclude_symbols, "exclude-symbols", 'e', 82 "exclude these comma separated symbols", "symbols"), 83 popt::option(include_symbols, "include-symbols", 'i', 84 "include these comma separated symbols", "symbols"), 85 popt::option(options::threshold_opt, "threshold", 't', 86 "minimum percentage needed to produce output", 87 "percent"), 88 89 popt::option(demangle_option, "demangle", 'D', 90 "demangle GNU C++ symbol names (default normal)", 91 "none|normal|smart"), 92 // PP:5 93 popt::option(options::debug_info, "debug-info", 'g', 94 "add source file and line number to output"), 95 popt::option(options::show_header, "no-header", 'n', 96 "remove all headers from output"), 97 popt::option(options::show_address, "show-address", 'w', 98 "show VMA address of each symbol"), 99 popt::option(options::long_filenames, "long-filenames", 'f', 100 "show the full path of filenames"), 101 popt::option(options::accumulated, "accumulated", 'a', 102 "percentage field show accumulated count"), 103 popt::option(options::global_percent, "global-percent", '%', 104 "percentage are not relative to symbol count or image " 105 "count but total sample count"), 106}; 107 108 109void handle_sort_option() 110{ 111 if (sort.empty()) { 112 // PP:5.14 sort default to sample 113 sort.push_back("sample"); 114 } 115 116 vector<string>::const_iterator cit = sort.begin(); 117 vector<string>::const_iterator end = sort.end(); 118 119 for (; cit != end; ++cit) { 120 options::sort_by.add_sort_option(*cit); 121 } 122} 123 124 125void handle_output_file() 126{ 127 if (outfile.empty()) 128 return; 129 130 static ofstream os(outfile.c_str()); 131 if (!os) { 132 cerr << "Couldn't open \"" << outfile 133 << "\" for writing." << endl; 134 exit(EXIT_FAILURE); 135 } 136 137 cout.rdbuf(os.rdbuf()); 138} 139 140 141/// Check incompatible or meaningless options. 142void check_options(bool diff) 143{ 144 using namespace options; 145 146 bool do_exit = false; 147 148 if (callgraph) { 149 symbols = true; 150 if (details) { 151 cerr << "--callgraph is incompatible with --details" << endl; 152 do_exit = true; 153 } 154 155 if (diff) { 156 cerr << "differential profiles are incompatible with --callgraph" << endl; 157 do_exit = true; 158 } 159 } 160 161 if (details && diff) { 162 cerr << "differential profiles are incompatible with --details" << endl; 163 do_exit = true; 164 } 165 166 if (!symbols) { 167 if (diff) { 168 cerr << "different profiles are meaningless " 169 "without --symbols" << endl; 170 do_exit = true; 171 } 172 173 if (show_address) { 174 cerr << "--show-address is meaningless " 175 "without --symbols" << endl; 176 do_exit = true; 177 } 178 179 if (debug_info || accumulated) { 180 cerr << "--debug-info and --accumulated are " 181 << "meaningless without --symbols" << endl; 182 do_exit = true; 183 } 184 185 if (!exclude_symbols.empty() || !include_symbols.empty()) { 186 cerr << "--exclude-symbols and --include-symbols are " 187 << "meaningless without --symbols" << endl; 188 do_exit = true; 189 } 190 191 if (find(sort_by.options.begin(), sort_by.options.end(), 192 sort_options::vma) != sort_by.options.end()) { 193 cerr << "--sort=vma is " 194 << "meaningless without --symbols" << endl; 195 do_exit = true; 196 } 197 } 198 199 if (global_percent && symbols && !(details || callgraph)) { 200 cerr << "--global-percent is meaningless with --symbols " 201 "and without --details or --callgraph" << endl; 202 do_exit = true; 203 } 204 205 if (do_exit) 206 exit(EXIT_FAILURE); 207} 208 209 210/// process a spec into classes 211string process_spec(profile_classes & classes, list<string> const & spec) 212{ 213 using namespace options; 214 215 copy(spec.begin(), spec.end(), 216 ostream_iterator<string>(cverb << vsfile, " ")); 217 cverb << vsfile << "\n\n"; 218 219 profile_spec const pspec = 220 profile_spec::create(spec, extra_found_images); 221 222 list<string> sample_files = pspec.generate_file_list(exclude_dependent, 223 !options::callgraph); 224 225 cverb << vsfile << "Archive: " << pspec.get_archive_path() << endl; 226 227 cverb << vsfile << "Matched sample files: " << sample_files.size() 228 << endl; 229 copy(sample_files.begin(), sample_files.end(), 230 ostream_iterator<string>(cverb << vsfile, "\n")); 231 232 classes = arrange_profiles(sample_files, merge_by); 233 234 cverb << vsfile << "profile_classes:\n" << classes << endl; 235 236 if (classes.v.empty()) { 237 cerr << "error: no sample files found: profile specification " 238 "too strict ?" << endl; 239 exit(EXIT_FAILURE); 240 } 241 242 return pspec.get_archive_path(); 243} 244 245 246} // namespace anon 247 248 249void handle_options(options::spec const & spec) 250{ 251 using namespace options; 252 253 if (details) { 254 symbols = true; 255 show_address = true; 256 } 257 258 handle_sort_option(); 259 merge_by = handle_merge_option(mergespec, true, exclude_dependent); 260 handle_output_file(); 261 demangle = handle_demangle_option(demangle_option); 262 check_options(spec.first.size()); 263 264 symbol_filter = string_filter(include_symbols, exclude_symbols); 265 266 if (!spec.first.size()) { 267 archive_path = process_spec(classes, spec.common); 268 } else { 269 cverb << vsfile << "profile spec 1:" << endl; 270 archive_path = process_spec(classes, spec.first); 271 cverb << vsfile << "profile spec 2:" << endl; 272 archive_path2 = process_spec(classes2, spec.second); 273 274 if (!classes.matches(classes2)) { 275 cerr << "profile classes are incompatible" << endl; 276 exit(EXIT_FAILURE); 277 } 278 } 279} 280