00001
00012 #include <vector>
00013 #include <list>
00014 #include <iostream>
00015 #include <algorithm>
00016 #include <iterator>
00017 #include <fstream>
00018
00019 #include "op_config.h"
00020 #include "profile_spec.h"
00021 #include "arrange_profiles.h"
00022 #include "opreport_options.h"
00023 #include "popt_options.h"
00024 #include "string_filter.h"
00025 #include "file_manip.h"
00026 #include "xml_output.h"
00027 #include "xml_utils.h"
00028 #include "cverb.h"
00029
00030 using namespace std;
00031
00032 profile_classes classes;
00033 profile_classes classes2;
00034
00035 namespace options {
00036 demangle_type demangle = dmt_normal;
00037 bool symbols;
00038 bool callgraph;
00039 bool debug_info;
00040 bool details;
00041 bool exclude_dependent;
00042 string_filter symbol_filter;
00043 sort_options sort_by;
00044 merge_option merge_by;
00045 bool show_header = true;
00046 bool long_filenames;
00047 bool show_address;
00048 bool accumulated;
00049 bool reverse_sort;
00050 bool global_percent;
00051 bool xml;
00052 string xml_options;
00053 }
00054
00055
00056 namespace {
00057
00058 string outfile;
00059 vector<string> mergespec;
00060 vector<string> sort;
00061 vector<string> exclude_symbols;
00062 vector<string> include_symbols;
00063 string demangle_option = "normal";
00064
00065 popt::option options_array[] = {
00066 popt::option(options::callgraph, "callgraph", 'c',
00067 "show call graph"),
00068 popt::option(options::details, "details", 'd',
00069 "output detailed samples for each symbol"),
00070 popt::option(options::symbols, "symbols", 'l',
00071 "list all symbols"),
00072
00073 popt::option(outfile, "output-file", 'o',
00074 "output to the given filename", "file"),
00075
00076 popt::option(sort, "sort", 's',
00077 "sort by", "sample,image,app-name,symbol,debug,vma"),
00078 popt::option(options::reverse_sort, "reverse-sort", 'r',
00079 "use reverse sort"),
00080 popt::option(mergespec, "merge", 'm',
00081 "comma separated list", "cpu,lib,tid,tgid,unitmask,all"),
00082 popt::option(options::exclude_dependent, "exclude-dependent", 'x',
00083 "exclude libs, kernel, and module samples for applications"),
00084 popt::option(exclude_symbols, "exclude-symbols", 'e',
00085 "exclude these comma separated symbols", "symbols"),
00086 popt::option(include_symbols, "include-symbols", 'i',
00087 "include these comma separated symbols", "symbols"),
00088 popt::option(options::threshold_opt, "threshold", 't',
00089 "minimum percentage needed to produce output",
00090 "percent"),
00091
00092 popt::option(demangle_option, "demangle", 'D',
00093 "demangle GNU C++ symbol names (default normal)",
00094 "none|normal|smart"),
00095
00096 popt::option(options::debug_info, "debug-info", 'g',
00097 "add source file and line number to output"),
00098 popt::option(options::show_header, "no-header", 'n',
00099 "remove all headers from output"),
00100 popt::option(options::show_address, "show-address", 'w',
00101 "show VMA address of each symbol"),
00102 popt::option(options::long_filenames, "long-filenames", 'f',
00103 "show the full path of filenames"),
00104 popt::option(options::accumulated, "accumulated", 'a',
00105 "percentage field show accumulated count"),
00106 popt::option(options::global_percent, "global-percent", '%',
00107 "percentage are not relative to symbol count or image "
00108 "count but total sample count"),
00109
00110 popt::option(options::xml, "xml", 'X',
00111 "XML output"),
00112
00113 };
00114
00115
00116 void handle_sort_option()
00117 {
00118 if (options::xml && !sort.empty()) {
00119 cerr << "warning: sort options ignored because they "
00120 << "are incompatible with --xml" << endl;
00121
00122
00123 sort.clear();
00124 }
00125
00126 if (sort.empty() || options::xml) {
00127
00128 if (options::xml) {
00129
00130
00131
00132 sort.push_back("app-name");
00133 sort.push_back("image");
00134 } else
00135 sort.push_back("sample");
00136 }
00137
00138 vector<string>::const_iterator cit = sort.begin();
00139 vector<string>::const_iterator end = sort.end();
00140
00141 for (; cit != end; ++cit)
00142 options::sort_by.add_sort_option(*cit);
00143 }
00144
00145
00146 void handle_output_file()
00147 {
00148 if (outfile.empty())
00149 return;
00150
00151 static ofstream os(outfile.c_str());
00152 if (!os) {
00153 cerr << "Couldn't open \"" << outfile
00154 << "\" for writing." << endl;
00155 exit(EXIT_FAILURE);
00156 }
00157
00158 cout.rdbuf(os.rdbuf());
00159 }
00160
00161
00163 void check_options(bool diff)
00164 {
00165 using namespace options;
00166
00167 bool do_exit = false;
00168
00169 if (callgraph) {
00170 symbols = true;
00171 if (details) {
00172 cerr << "--callgraph is incompatible with --details" << endl;
00173 do_exit = true;
00174 }
00175
00176 if (diff) {
00177 cerr << "differential profiles are incompatible with --callgraph" << endl;
00178 do_exit = true;
00179 }
00180 }
00181
00182 if (xml) {
00183 if (accumulated) {
00184 cerr << "--accumulated is incompatible with --xml" << endl;
00185 do_exit = true;
00186 }
00187
00188 if (global_percent) {
00189 cerr << "--global_percent is incompatible with --xml" << endl;
00190 do_exit = true;
00191 }
00192 }
00193
00194
00195 if (details && diff) {
00196 cerr << "differential profiles are incompatible with --details" << endl;
00197 do_exit = true;
00198 }
00199
00200 if (!symbols) {
00201 if (diff) {
00202 cerr << "different profiles are meaningless "
00203 "without --symbols" << endl;
00204 do_exit = true;
00205 }
00206
00207 if (show_address) {
00208 cerr << "--show-address is meaningless "
00209 "without --symbols" << endl;
00210 do_exit = true;
00211 }
00212
00213 if (debug_info || accumulated) {
00214 cerr << "--debug-info and --accumulated are "
00215 << "meaningless without --symbols" << endl;
00216 do_exit = true;
00217 }
00218
00219 if (!exclude_symbols.empty() || !include_symbols.empty()) {
00220 cerr << "--exclude-symbols and --include-symbols are "
00221 << "meaningless without --symbols" << endl;
00222 do_exit = true;
00223 }
00224
00225 if (find(sort_by.options.begin(), sort_by.options.end(),
00226 sort_options::vma) != sort_by.options.end()) {
00227 cerr << "--sort=vma is "
00228 << "meaningless without --symbols" << endl;
00229 do_exit = true;
00230 }
00231 }
00232
00233 if (global_percent && symbols && !(details || callgraph)) {
00234 cerr << "--global-percent is meaningless with --symbols "
00235 "and without --details or --callgraph" << endl;
00236 do_exit = true;
00237 }
00238
00239 if (do_exit)
00240 exit(EXIT_FAILURE);
00241 }
00242
00243
00245 void process_spec(profile_classes & classes, list<string> const & spec)
00246 {
00247 using namespace options;
00248
00249 copy(spec.begin(), spec.end(),
00250 ostream_iterator<string>(cverb << vsfile, " "));
00251 cverb << vsfile << "\n\n";
00252
00253 profile_spec const pspec =
00254 profile_spec::create(spec, options::image_path,
00255 options::root_path);
00256
00257 if (!was_session_dir_supplied())
00258 cerr << "Using " << op_samples_dir << " for samples directory." << endl;
00259
00260 list<string> sample_files = pspec.generate_file_list(exclude_dependent,
00261 !options::callgraph);
00262
00263 cverb << vsfile << "Archive: " << pspec.get_archive_path() << endl;
00264
00265 cverb << vsfile << "Matched sample files: " << sample_files.size()
00266 << endl;
00267 copy(sample_files.begin(), sample_files.end(),
00268 ostream_iterator<string>(cverb << vsfile, "\n"));
00269
00270 classes = arrange_profiles(sample_files, merge_by,
00271 pspec.extra_found_images);
00272
00273 cverb << vsfile << "profile_classes:\n" << classes << endl;
00274
00275 if (classes.v.empty()) {
00276 cerr << "error: no sample files found: profile specification "
00277 "too strict ?" << endl;
00278 exit(EXIT_FAILURE);
00279 }
00280 }
00281
00282
00283 }
00284
00285
00286 void handle_options(options::spec const & spec)
00287 {
00288 using namespace options;
00289
00290 if (details) {
00291 symbols = true;
00292 show_address = true;
00293 }
00294
00295 if (options::xml) {
00296 if (spec.common.size() != 0)
00297 xml_utils::add_option(SESSION, spec.common);
00298 if (debug_info)
00299 xml_utils::add_option(DEBUG_INFO, true);
00300 if (details)
00301 xml_utils::add_option(DETAILS, true);
00302 if (!image_path.empty())
00303 xml_utils::add_option(IMAGE_PATH, image_path);
00304 if (!mergespec.empty())
00305 xml_utils::add_option(MERGE, mergespec);
00306 if (exclude_dependent)
00307 xml_utils::add_option(EXCLUDE_DEPENDENT, true);
00308 if (!exclude_symbols.empty())
00309 xml_utils::add_option(EXCLUDE_SYMBOLS, exclude_symbols);
00310 if (!include_symbols.empty())
00311 xml_utils::add_option(INCLUDE_SYMBOLS, include_symbols);
00312 }
00313
00314 handle_sort_option();
00315 merge_by = handle_merge_option(mergespec, true, exclude_dependent);
00316 handle_output_file();
00317 demangle = handle_demangle_option(demangle_option);
00318 check_options(spec.first.size());
00319
00320 symbol_filter = string_filter(include_symbols, exclude_symbols);
00321
00322 if (!spec.first.size()) {
00323 process_spec(classes, spec.common);
00324 } else {
00325 if (options::xml) {
00326 cerr << "differential profiles are incompatible with --xml" << endl;
00327 exit(EXIT_FAILURE);
00328 }
00329 cverb << vsfile << "profile spec 1:" << endl;
00330 process_spec(classes, spec.first);
00331 cverb << vsfile << "profile spec 2:" << endl;
00332 process_spec(classes2, spec.second);
00333
00334 if (!classes.matches(classes2)) {
00335 cerr << "profile classes are incompatible" << endl;
00336 exit(EXIT_FAILURE);
00337 }
00338 }
00339 }