00001
00012 #include <iostream>
00013 #include <iomanip>
00014 #include <vector>
00015 #include <algorithm>
00016 #include <sstream>
00017 #include <numeric>
00018
00019 #include "op_exception.h"
00020 #include "stream_util.h"
00021 #include "string_manip.h"
00022 #include "file_manip.h"
00023 #include "opreport_options.h"
00024 #include "op_header.h"
00025 #include "profile.h"
00026 #include "populate.h"
00027 #include "arrange_profiles.h"
00028 #include "profile_container.h"
00029 #include "callgraph_container.h"
00030 #include "diff_container.h"
00031 #include "symbol_sort.h"
00032 #include "format_output.h"
00033 #include "xml_utils.h"
00034 #include "image_errors.h"
00035
00036 using namespace std;
00037
00038 namespace {
00039
00040 static size_t nr_classes;
00041
00043 struct summary {
00044 count_array_t counts;
00045 string lib_image;
00046
00047 bool operator<(summary const & rhs) const {
00048 return options::reverse_sort
00049 ? counts[0] < rhs.counts[0] : rhs.counts[0] < counts[0];
00050 }
00051
00053 count_type add_files(list<profile_sample_files> const & files,
00054 size_t pclass);
00055 };
00056
00057
00058 count_type summary::
00059 add_files(list<profile_sample_files> const & files, size_t pclass)
00060 {
00061 count_type subtotal = 0;
00062
00063 list<profile_sample_files>::const_iterator it = files.begin();
00064 list<profile_sample_files>::const_iterator const end = files.end();
00065
00066 for (; it != end; ++it) {
00067 count_type count = profile_t::sample_count(it->sample_filename);
00068 counts[pclass] += count;
00069 subtotal += count;
00070
00071 if (!it->cg_files.empty()) {
00072 throw op_runtime_error("opreport.cpp::add_files(): "
00073 "unxpected non empty cg file set");
00074 }
00075 }
00076
00077 return subtotal;
00078 }
00079
00080
00086 struct app_summary {
00088 count_array_t counts;
00090 string image;
00092 vector<summary> deps;
00093
00095 count_type add_profile(profile_set const & profile, size_t pclass);
00096
00097 bool operator<(app_summary const & rhs) const {
00098 return options::reverse_sort
00099 ? counts[0] < rhs.counts[0] : rhs.counts[0] < counts[0];
00100 }
00101
00102 private:
00104 summary & find_summary(string const & image);
00105 };
00106
00107
00108 summary & app_summary::find_summary(string const & image)
00109 {
00110 vector<summary>::iterator sit = deps.begin();
00111 vector<summary>::iterator const send = deps.end();
00112 for (; sit != send; ++sit) {
00113 if (sit->lib_image == image)
00114 return *sit;
00115 }
00116
00117 summary summ;
00118 summ.lib_image = image;
00119 deps.push_back(summ);
00120 return deps.back();
00121 }
00122
00123
00124 count_type app_summary::add_profile(profile_set const & profile,
00125 size_t pclass)
00126 {
00127 count_type group_total = 0;
00128
00129
00130 summary & summ = find_summary(profile.image);
00131 count_type app_count = summ.add_files(profile.files, pclass);
00132 counts[pclass] += app_count;
00133 group_total += app_count;
00134
00135
00136 list<profile_dep_set>::const_iterator it = profile.deps.begin();
00137 list<profile_dep_set>::const_iterator const end = profile.deps.end();
00138
00139 for (; it != end; ++it) {
00140 summary & summ = find_summary(it->lib_image);
00141 count_type lib_count = summ.add_files(it->files, pclass);
00142 counts[pclass] += lib_count;
00143 group_total += lib_count;
00144 }
00145
00146 return group_total;
00147 }
00148
00149
00151 struct summary_container {
00152 summary_container(vector<profile_class> const & pclasses);
00153
00155 vector<app_summary> apps;
00157 count_array_t total_counts;
00158 };
00159
00160
00161 summary_container::
00162 summary_container(vector<profile_class> const & pclasses)
00163 {
00164 typedef map<string, app_summary> app_map_t;
00165 app_map_t app_map;
00166
00167 for (size_t i = 0; i < pclasses.size(); ++i) {
00168 list<profile_set>::const_iterator it
00169 = pclasses[i].profiles.begin();
00170 list<profile_set>::const_iterator const end
00171 = pclasses[i].profiles.end();
00172
00173 for (; it != end; ++it) {
00174 app_map_t::iterator ait = app_map.find(it->image);
00175 if (ait == app_map.end()) {
00176 app_summary app;
00177 app.image = it->image;
00178 total_counts[i] += app.add_profile(*it, i);
00179 app_map[app.image] = app;
00180 } else {
00181 total_counts[i]
00182 += ait->second.add_profile(*it, i);
00183 }
00184 }
00185 }
00186
00187 app_map_t::const_iterator it = app_map.begin();
00188 app_map_t::const_iterator const end = app_map.end();
00189
00190 for (; it != end; ++it)
00191 apps.push_back(it->second);
00192
00193
00194 stable_sort(apps.begin(), apps.end());
00195 vector<app_summary>::iterator ait = apps.begin();
00196 vector<app_summary>::iterator const aend = apps.end();
00197 for (; ait != aend; ++ait)
00198 stable_sort(ait->deps.begin(), ait->deps.end());
00199 }
00200
00201
00202 void output_header()
00203 {
00204 if (!options::show_header)
00205 return;
00206
00207 cout << classes.cpuinfo << endl;
00208 if (!classes.event.empty())
00209 cout << classes.event << endl;
00210
00211 for (vector<profile_class>::size_type i = 0;
00212 i < classes.v.size(); ++i) {
00213 cout << classes.v[i].longname << endl;
00214 }
00215 }
00216
00217
00218 string get_filename(string const & filename)
00219 {
00220 return options::long_filenames ? filename : op_basename(filename);
00221 }
00222
00223
00225 void output_count(count_type total_count, count_type count)
00226 {
00227 cout << setw(9) << count << ' ';
00228 double ratio = op_ratio(count, total_count);
00229 cout << format_percent(ratio * 100, percent_int_width,
00230 percent_fract_width) << ' ';
00231 }
00232
00233
00234 void output_col_headers(bool indent)
00235 {
00236 if (!options::show_header)
00237 return;
00238
00239 if (indent)
00240 cout << '\t';
00241
00242 size_t colwidth = 9 + 1 + percent_width;
00243
00244 for (size_t i = 0; i < classes.v.size(); ++i) {
00245 string name = classes.v[i].name;
00246 if (name.length() > colwidth)
00247 name = name.substr(0, colwidth - 3)
00248 + "...";
00249 io_state state(cout);
00250
00251 cout.setf(ios::right, ios::adjustfield);
00252
00253 cout << setw(colwidth) << name.c_str();
00254 cout << '|';
00255 }
00256 cout << '\n';
00257
00258 if (indent)
00259 cout << '\t';
00260
00261 for (size_t i = 0; i < classes.v.size(); ++i) {
00262 cout << " samples| ";
00263 io_state state(cout);
00264
00265 cout.setf(ios::right, ios::adjustfield);
00266 cout << setw(percent_width) << "%|";
00267 }
00268
00269 cout << '\n';
00270
00271 if (indent)
00272 cout << '\t';
00273
00274 for (size_t i = 0; i < classes.v.size(); ++i) {
00275 cout << "-----------";
00276 string str(percent_width, '-');
00277 cout << str;
00278 }
00279
00280 cout << '\n';
00281 }
00282
00283
00284 void
00285 output_deps(summary_container const & summaries,
00286 app_summary const & app)
00287 {
00288
00289
00290
00291 if (app.deps.size() == 1)
00292 return;
00293
00294 output_col_headers(true);
00295
00296 for (size_t j = 0 ; j < app.deps.size(); ++j) {
00297 summary const & summ = app.deps[j];
00298
00299 if (summ.counts.zero())
00300 continue;
00301
00302 cout << '\t';
00303
00304 for (size_t i = 0; i < nr_classes; ++i) {
00305 count_type tot_count = options::global_percent
00306 ? summaries.total_counts[i] : app.counts[i];
00307
00308 output_count(tot_count, summ.counts[i]);
00309 }
00310
00311 cout << get_filename(summ.lib_image);
00312 cout << '\n';
00313 }
00314 }
00315
00316
00320 void output_summaries(summary_container const & summaries)
00321 {
00322 output_col_headers(false);
00323
00324 for (size_t i = 0; i < summaries.apps.size(); ++i) {
00325 app_summary const & app = summaries.apps[i];
00326
00327 if ((app.counts[0] * 100.0) / summaries.total_counts[0]
00328 < options::threshold) {
00329 continue;
00330 }
00331
00332 for (size_t j = 0; j < nr_classes; ++j)
00333 output_count(summaries.total_counts[j], app.counts[j]);
00334
00335 cout << get_filename(app.image) << '\n';
00336
00337 output_deps(summaries, app);
00338 }
00339 }
00340
00341
00342 format_flags get_format_flags(column_flags const & cf)
00343 {
00344 format_flags flags(ff_none);
00345 flags = format_flags(flags | ff_nr_samples);
00346 flags = format_flags(flags | ff_percent | ff_symb_name);
00347
00348 if (options::show_address)
00349 flags = format_flags(flags | ff_vma);
00350
00351 if (options::debug_info)
00352 flags = format_flags(flags | ff_linenr_info);
00353
00354 if (options::accumulated) {
00355 flags = format_flags(flags | ff_nr_samples_cumulated);
00356 flags = format_flags(flags | ff_percent_cumulated);
00357 }
00358
00359 if (classes2.v.size())
00360 flags = format_flags(flags | ff_diff);
00361
00362 if (cf & cf_image_name)
00363 flags = format_flags(flags | ff_image_name);
00364
00365 return flags;
00366 }
00367
00368
00369 void output_symbols(profile_container const & pc, bool multiple_apps)
00370 {
00371 profile_container::symbol_choice choice;
00372 choice.threshold = options::threshold;
00373 symbol_collection symbols = pc.select_symbols(choice);
00374 options::sort_by.sort(symbols, options::reverse_sort,
00375 options::long_filenames);
00376 format_output::formatter * out;
00377 format_output::xml_formatter * xml_out = 0;
00378 format_output::opreport_formatter * text_out = 0;
00379
00380 if (options::xml) {
00381 xml_out = new format_output::xml_formatter(&pc, symbols,
00382 pc.extra_found_images, options::symbol_filter);
00383 xml_out->show_details(options::details);
00384 out = xml_out;
00385
00386 out->show_long_filenames(true);
00387 } else {
00388 text_out = new format_output::opreport_formatter(pc);
00389 text_out->show_details(options::details);
00390 out = text_out;
00391 out->show_long_filenames(options::long_filenames);
00392 }
00393
00394 out->set_nr_classes(nr_classes);
00395 out->show_header(options::show_header);
00396 out->vma_format_64bit(choice.hints & cf_64bit_vma);
00397 out->show_global_percent(options::global_percent);
00398
00399 format_flags flags = get_format_flags(choice.hints);
00400 if (multiple_apps)
00401 flags = format_flags(flags | ff_app_name);
00402
00403 out->add_format(flags);
00404
00405 if (options::xml) {
00406 xml_support = new xml_utils(xml_out, symbols, nr_classes,
00407 pc.extra_found_images);
00408 xml_out->output(cout);
00409 } else {
00410 text_out->output(cout, symbols);
00411 }
00412 }
00413
00414
00415 void output_diff_symbols(profile_container const & pc1,
00416 profile_container const & pc2, bool multiple_apps)
00417 {
00418 diff_container dc(pc1, pc2);
00419
00420 profile_container::symbol_choice choice;
00421 choice.threshold = options::threshold;
00422
00423 diff_collection symbols = dc.get_symbols(choice);
00424
00425 format_flags flags = get_format_flags(choice.hints);
00426 if (multiple_apps)
00427 flags = format_flags(flags | ff_app_name);
00428
00429
00430
00431
00432 format_output::diff_formatter out(dc, pc1.extra_found_images);
00433
00434 out.set_nr_classes(nr_classes);
00435 out.show_long_filenames(options::long_filenames);
00436 out.show_header(options::show_header);
00437 out.show_global_percent(options::global_percent);
00438 out.vma_format_64bit(choice.hints & cf_64bit_vma);
00439 out.add_format(flags);
00440
00441 options::sort_by.sort(symbols, options::reverse_sort,
00442 options::long_filenames);
00443
00444 out.output(cout, symbols);
00445 }
00446
00447
00448 void output_cg_symbols(callgraph_container const & cg, bool multiple_apps)
00449 {
00450 column_flags output_hints = cg.output_hint();
00451
00452 symbol_collection symbols = cg.get_symbols();
00453
00454 options::sort_by.sort(symbols, options::reverse_sort,
00455 options::long_filenames);
00456
00457 format_output::formatter * out;
00458 format_output::xml_cg_formatter * xml_out = 0;
00459 format_output::cg_formatter * text_out = 0;
00460
00461 if (options::xml) {
00462 xml_out = new format_output::xml_cg_formatter(cg, symbols,
00463 options::symbol_filter);
00464 xml_out->show_details(options::details);
00465 out = xml_out;
00466
00467 out->show_long_filenames(true);
00468 } else {
00469 text_out = new format_output::cg_formatter(cg);
00470 out = text_out;
00471 out->show_long_filenames(options::long_filenames);
00472 }
00473
00474 out->set_nr_classes(nr_classes);
00475 out->show_header(options::show_header);
00476 out->vma_format_64bit(output_hints & cf_64bit_vma);
00477 out->show_global_percent(options::global_percent);
00478
00479 format_flags flags = get_format_flags(output_hints);
00480 if (multiple_apps)
00481 flags = format_flags(flags | ff_app_name);
00482
00483 out->add_format(flags);
00484
00485 if (options::xml) {
00486 xml_support = new xml_utils(xml_out, symbols, nr_classes,
00487 cg.extra_found_images);
00488 xml_out->output(cout);
00489 } else {
00490 text_out->output(cout, symbols);
00491 }
00492
00493 }
00494
00495
00496 int opreport(options::spec const & spec)
00497 {
00498 want_xml = options::xml;
00499
00500 handle_options(spec);
00501
00502 nr_classes = classes.v.size();
00503
00504 if (!options::symbols && !options::xml) {
00505 summary_container summaries(classes.v);
00506 output_header();
00507 output_summaries(summaries);
00508 return 0;
00509 }
00510
00511 bool multiple_apps = false;
00512
00513 for (size_t i = 0; i < classes.v.size(); ++i) {
00514 if (classes.v[i].profiles.size() > 1)
00515 multiple_apps = true;
00516 }
00517
00518 list<inverted_profile> iprofiles = invert_profiles(classes);
00519
00520 report_image_errors(iprofiles, classes.extra_found_images);
00521
00522 if (options::xml) {
00523 xml_utils::output_xml_header(options::command_options,
00524 classes.cpuinfo, classes.event);
00525 } else {
00526 output_header();
00527 }
00528
00529 if (classes2.v.size()) {
00530 for (size_t i = 0; i < classes2.v.size(); ++i) {
00531 if (classes2.v[i].profiles.size() > 1)
00532 multiple_apps |= true;
00533 }
00534
00535 profile_container pc1(options::debug_info, options::details,
00536 classes.extra_found_images);
00537
00538 list<inverted_profile>::iterator it = iprofiles.begin();
00539 list<inverted_profile>::iterator const end = iprofiles.end();
00540
00541 for (; it != end; ++it)
00542 populate_for_image(pc1, *it,
00543 options::symbol_filter, 0);
00544
00545 list<inverted_profile> iprofiles2 = invert_profiles(classes2);
00546
00547 report_image_errors(iprofiles2, classes2.extra_found_images);
00548
00549 profile_container pc2(options::debug_info, options::details,
00550 classes2.extra_found_images);
00551
00552 list<inverted_profile>::iterator it2 = iprofiles2.begin();
00553 list<inverted_profile>::iterator const end2 = iprofiles2.end();
00554
00555 for (; it2 != end2; ++it2)
00556 populate_for_image(pc2, *it2,
00557 options::symbol_filter, 0);
00558
00559 output_diff_symbols(pc1, pc2, multiple_apps);
00560 } else if (options::callgraph) {
00561 callgraph_container cg_container;
00562 cg_container.populate(iprofiles, classes.extra_found_images,
00563 options::debug_info, options::threshold,
00564 options::merge_by.lib, options::symbol_filter);
00565
00566 output_cg_symbols(cg_container, multiple_apps);
00567 } else {
00568 profile_container samples(options::debug_info,
00569 options::details, classes.extra_found_images);
00570
00571 list<inverted_profile>::iterator it = iprofiles.begin();
00572 list<inverted_profile>::iterator const end = iprofiles.end();
00573
00574 for (; it != end; ++it)
00575 populate_for_image(samples, *it,
00576 options::symbol_filter, 0);
00577
00578 output_symbols(samples, multiple_apps);
00579 }
00580
00581 return 0;
00582 }
00583
00584 }
00585
00586
00587 int main(int argc, char const * argv[])
00588 {
00589 cout.tie(0);
00590 return run_pp_tool(argc, argv, opreport);
00591 }