opreport.cpp

Go to the documentation of this file.
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     // first the main image
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     // now all dependent images if any
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     // sort by count
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         // gcc 2.95 doesn't know right io manipulator
00251         cout.setf(ios::right, ios::adjustfield);
00252         // gcc 2.95 doesn't honor setw() for std::string
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         // gcc 2.95 doesn't know right io manipulator
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     // the app summary itself is *always* present
00289     // (perhaps with zero counts) so this test
00290     // is correct
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         // for XML always output long filenames
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     // With diff profile we output only filename coming from the first
00430     // profile session, internally we use only name derived from the sample
00431     // filename so image name can match.
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         // for XML always output long filenames
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 }  // anonymous namespace
00585 
00586 
00587 int main(int argc, char const * argv[])
00588 {
00589     cout.tie(0);
00590     return run_pp_tool(argc, argv, opreport);
00591 }

Generated on 8 Nov 2012 for Oprofile by  doxygen 1.6.1