format_output.cpp

Go to the documentation of this file.
00001 
00012 /* older glibc has C99 INFINITY in _GNU_SOURCE */
00013 #ifndef _GNU_SOURCE
00014 #define _GNU_SOURCE
00015 #endif
00016 
00017 #include <cassert>
00018 #include <sstream>
00019 #include <iomanip>
00020 #include <iostream>
00021 #include <cmath>
00022 
00023 #include "string_manip.h"
00024 #include "string_filter.h"
00025 
00026 #include "format_output.h"
00027 #include "profile_container.h"
00028 #include "callgraph_container.h"
00029 #include "diff_container.h"
00030 #include "arrange_profiles.h"
00031 #include "xml_output.h"
00032 #include "xml_utils.h"
00033 #include "cverb.h"
00034 
00035 using namespace std;
00036 
00037 namespace {
00038 
00039 
00040 string const get_linenr_info(file_location const floc, bool lf)
00041 {
00042     ostringstream out;
00043 
00044     string const & filename = lf
00045         ? debug_names.name(floc.filename)
00046         : debug_names.basename(floc.filename);
00047 
00048     if (!filename.empty())
00049         out << filename << ":" << floc.linenr;
00050     else 
00051         out << "(no location information)";
00052 
00053     return out.str();
00054 }
00055 
00056 string get_vma(bfd_vma vma, bool vma_64)
00057 {
00058     ostringstream out;
00059     int width = vma_64 ? 16 : 8;
00060 
00061     out << hex << setw(width) << setfill('0') << vma;
00062 
00063     return out.str();
00064 }
00065 
00066 string get_percent(count_type dividend, count_type divisor)
00067 {
00068     double ratio = op_ratio(dividend, divisor);
00069 
00070     return ::format_percent(ratio * 100, percent_int_width,
00071                          percent_fract_width);
00072 }
00073 
00074 bool extract_linenr_info(string const & info, string & file, size_t & line)
00075 {
00076     line = 0;
00077     file = "";
00078     string::size_type colon_pos = info.find(":");
00079 
00080     if (colon_pos == string::npos)
00081         return false;
00082 
00083     file = info.substr(0, colon_pos);
00084     istringstream is_info(info.substr(colon_pos+1));
00085     is_info >> line;
00086     return true;
00087 }
00088 
00089 
00090 } // anonymous namespace
00091 
00092 namespace format_output {
00093 
00094 formatter::formatter(extra_images const & extra)
00095     :
00096     nr_classes(1),
00097     flags(ff_none),
00098     vma_64(false),
00099     long_filenames(false),
00100     need_header(true),
00101     extra_found_images(extra)
00102 {
00103     format_map[ff_vma] = field_description(9, "vma", &formatter::format_vma);
00104     format_map[ff_nr_samples] = field_description(9, "samples", &formatter::format_nr_samples);
00105     format_map[ff_nr_samples_cumulated] = field_description(14, "cum. samples", &formatter::format_nr_cumulated_samples);
00106     format_map[ff_percent] = field_description(9, "%", &formatter::format_percent);
00107     format_map[ff_percent_cumulated] = field_description(11, "cum. %", &formatter::format_cumulated_percent);
00108     format_map[ff_linenr_info] = field_description(28, "linenr info", &formatter::format_linenr_info);
00109     format_map[ff_image_name] = field_description(25, "image name", &formatter::format_image_name);
00110     format_map[ff_app_name] = field_description(25, "app name", &formatter::format_app_name);
00111     format_map[ff_symb_name] = field_description(30, "symbol name", &formatter::format_symb_name);
00112     format_map[ff_percent_details] = field_description(9, "%", &formatter::format_percent_details);
00113     format_map[ff_percent_cumulated_details] = field_description(10, "cum. %", &formatter::format_cumulated_percent_details);
00114     format_map[ff_diff] = field_description(10, "diff %", &formatter::format_diff);
00115 }
00116 
00117 
00118 formatter::~formatter()
00119 {
00120 }
00121 
00122 
00123 void formatter::set_nr_classes(size_t nr)
00124 {
00125     nr_classes = nr;
00126 }
00127 
00128 
00129 void formatter::add_format(format_flags flag)
00130 {
00131     flags = static_cast<format_flags>(flags | flag);
00132 }
00133 
00134 
00135 void formatter::show_header(bool on_off)
00136 {
00137     need_header = on_off;
00138 }
00139  
00140 
00141 void formatter::vma_format_64bit(bool on_off)
00142 {
00143     vma_64 = on_off;
00144 }
00145 
00146 
00147 void formatter::show_long_filenames(bool on_off)
00148 {
00149     long_filenames = on_off;
00150 }
00151 
00152 
00153 void formatter::show_global_percent(bool on_off)
00154 {
00155     global_percent = on_off;
00156 }
00157 
00158 
00159 void formatter::output_header(ostream & out)
00160 {
00161     if (!need_header)
00162         return;
00163 
00164     size_t padding = 0;
00165 
00166     // first output the vma field
00167     if (flags & ff_vma)
00168         padding = output_header_field(out, ff_vma, padding);
00169 
00170     // the field repeated for each profile class
00171     for (size_t pclass = 0 ; pclass < nr_classes; ++pclass) {
00172         if (flags & ff_nr_samples)
00173             padding = output_header_field(out,
00174                   ff_nr_samples, padding);
00175 
00176         if (flags & ff_nr_samples_cumulated)
00177             padding = output_header_field(out, 
00178                    ff_nr_samples_cumulated, padding);
00179 
00180         if (flags & ff_percent)
00181             padding = output_header_field(out,
00182                    ff_percent, padding);
00183 
00184         if (flags & ff_percent_cumulated)
00185             padding = output_header_field(out,
00186                    ff_percent_cumulated, padding);
00187 
00188         if (flags & ff_diff)
00189             padding = output_header_field(out,
00190                 ff_diff, padding);
00191 
00192         if (flags & ff_percent_details)
00193             padding = output_header_field(out,
00194                    ff_percent_details, padding);
00195 
00196         if (flags & ff_percent_cumulated_details)
00197             padding = output_header_field(out,
00198                    ff_percent_cumulated_details, padding);
00199     }
00200 
00201     // now the remaining field
00202     if (flags & ff_linenr_info)
00203         padding = output_header_field(out, ff_linenr_info, padding);
00204 
00205     if (flags & ff_image_name)
00206         padding = output_header_field(out, ff_image_name, padding);
00207 
00208     if (flags & ff_app_name)
00209         padding = output_header_field(out, ff_app_name, padding);
00210 
00211     if (flags & ff_symb_name)
00212         padding = output_header_field(out, ff_symb_name, padding);
00213 
00214     out << "\n";
00215 }
00216 
00217 
00219 // FIXME: use % of the screen width here. sum of % equal to 100, then calculate
00220 // ratio between 100 and the selected % to grow non fixed field use also
00221 // lib[n?]curses to get the console width (look info source) (so on add a fixed
00222 // field flags)
00223 size_t formatter::
00224 output_field(ostream & out, field_datum const & datum,
00225              format_flags fl, size_t padding, bool hide_immutable)
00226 {
00227     if (!hide_immutable) {
00228         out << string(padding, ' ');
00229 
00230         field_description const & field(format_map[fl]);
00231         string str = (this->*field.formatter)(datum);
00232         out << str;
00233 
00234         // at least one separator char
00235         padding = 1;
00236         if (str.length() < field.width)
00237             padding = field.width - str.length();
00238     } else {
00239         field_description const & field(format_map[fl]);
00240         padding += field.width;
00241     }
00242 
00243     return padding;
00244 }
00245 
00246  
00247 size_t formatter::
00248 output_header_field(ostream & out, format_flags fl, size_t padding)
00249 {
00250     out << string(padding, ' ');
00251 
00252     field_description const & field(format_map[fl]);
00253     out << field.header_name;
00254 
00255     // at least one separator char
00256     padding = 1;
00257     if (field.header_name.length() < field.width)
00258         padding = field.width - field.header_name.length();
00259 
00260     return padding;
00261 }
00262  
00263 
00264 string formatter::format_vma(field_datum const & f)
00265 {
00266     return get_vma(f.sample.vma, vma_64);
00267 }
00268 
00269  
00270 string formatter::format_symb_name(field_datum const & f)
00271 {
00272     return symbol_names.demangle(f.symbol.name);
00273 }
00274 
00275 
00276 string formatter::format_image_name(field_datum const & f)
00277 {
00278     return get_image_name(f.symbol.image_name, 
00279         long_filenames 
00280             ? image_name_storage::int_real_filename
00281             : image_name_storage::int_real_basename,
00282         extra_found_images);
00283 }
00284 
00285  
00286 string formatter::format_app_name(field_datum const & f)
00287 {
00288     return get_image_name(f.symbol.app_name,
00289         long_filenames 
00290             ? image_name_storage::int_real_filename
00291             : image_name_storage::int_real_basename,
00292         extra_found_images);
00293 }
00294 
00295  
00296 string formatter::format_linenr_info(field_datum const & f)
00297 {
00298     return get_linenr_info(f.sample.file_loc, long_filenames);
00299 }
00300 
00301  
00302 string formatter::format_nr_samples(field_datum const & f)
00303 {
00304     ostringstream out;
00305     out << f.sample.counts[f.pclass];
00306     return out.str();
00307 }
00308 
00309  
00310 string formatter::format_nr_cumulated_samples(field_datum const & f)
00311 {
00312     if (f.diff == -INFINITY)
00313         return "---";
00314     ostringstream out;
00315     f.counts.cumulated_samples[f.pclass] += f.sample.counts[f.pclass];
00316     out << f.counts.cumulated_samples[f.pclass];
00317     return out.str();
00318 }
00319 
00320  
00321 string formatter::format_percent(field_datum const & f)
00322 {
00323     if (f.diff == -INFINITY)
00324         return "---";
00325     return get_percent(f.sample.counts[f.pclass], f.counts.total[f.pclass]);
00326 }
00327 
00328  
00329 string formatter::format_cumulated_percent(field_datum const & f)
00330 {
00331     if (f.diff == -INFINITY)
00332         return "---";
00333     f.counts.cumulated_percent[f.pclass] += f.sample.counts[f.pclass];
00334 
00335     return get_percent(f.counts.cumulated_percent[f.pclass],
00336                        f.counts.total[f.pclass]);
00337 }
00338 
00339  
00340 string formatter::format_percent_details(field_datum const & f)
00341 {
00342     return get_percent(f.sample.counts[f.pclass],
00343         f.counts.total[f.pclass]);
00344 }
00345 
00346  
00347 string formatter::format_cumulated_percent_details(field_datum const & f)
00348 {
00349     f.counts.cumulated_percent_details[f.pclass] += f.sample.counts[f.pclass];
00350 
00351     return get_percent(f.counts.cumulated_percent_details[f.pclass],
00352                        f.counts.total[f.pclass]);
00353 }
00354 
00355 
00356 string formatter::format_diff(field_datum const & f)
00357 {
00358     if (f.diff == INFINITY)
00359         return "+++";
00360     else if (f.diff == -INFINITY)
00361         return "---";
00362 
00363     return ::format_percent(f.diff, percent_int_width,
00364                                 percent_fract_width, true);
00365 }
00366 
00367 
00368 void formatter::
00369 do_output(ostream & out, symbol_entry const & symb, sample_entry const & sample,
00370           counts_t & c, diff_array_t const & diffs, bool hide_immutable)
00371 {
00372     size_t padding = 0;
00373 
00374     // first output the vma field
00375     field_datum datum(symb, sample, 0, c, extra_found_images);
00376     if (flags & ff_vma)
00377         padding = output_field(out, datum, ff_vma, padding, false);
00378 
00379     // repeated fields for each profile class
00380     for (size_t pclass = 0 ; pclass < nr_classes; ++pclass) {
00381         field_datum datum(symb, sample, pclass, c,
00382                   extra_found_images, diffs[pclass]);
00383 
00384         if (flags & ff_nr_samples)
00385             padding = output_field(out, datum,
00386                    ff_nr_samples, padding, false);
00387 
00388         if (flags & ff_nr_samples_cumulated)
00389             padding = output_field(out, datum, 
00390                    ff_nr_samples_cumulated, padding, false);
00391 
00392         if (flags & ff_percent)
00393             padding = output_field(out, datum,
00394                    ff_percent, padding, false);
00395 
00396         if (flags & ff_percent_cumulated)
00397             padding = output_field(out, datum,
00398                    ff_percent_cumulated, padding, false);
00399 
00400         if (flags & ff_diff)
00401             padding = output_field(out, datum,
00402                 ff_diff, padding, false);
00403 
00404         if (flags & ff_percent_details)
00405             padding = output_field(out, datum,
00406                    ff_percent_details, padding, false);
00407 
00408         if (flags & ff_percent_cumulated_details)
00409             padding = output_field(out, datum,
00410                    ff_percent_cumulated_details, padding, false);
00411     }
00412 
00413     // now the remaining field
00414     if (flags & ff_linenr_info)
00415         padding = output_field(out, datum, ff_linenr_info,
00416                padding, false);
00417 
00418     if (flags & ff_image_name)
00419         padding = output_field(out, datum, ff_image_name,
00420                padding, hide_immutable);
00421 
00422     if (flags & ff_app_name)
00423         padding = output_field(out, datum, ff_app_name,
00424                padding, hide_immutable);
00425 
00426     if (flags & ff_symb_name)
00427         padding = output_field(out, datum, ff_symb_name,
00428                padding, hide_immutable);
00429 
00430     out << "\n";
00431 }
00432 
00433 
00434 opreport_formatter::opreport_formatter(profile_container const & p)
00435     :
00436     formatter(p.extra_found_images),
00437     profile(p),
00438     need_details(false)
00439 {
00440     counts.total = profile.samples_count();
00441 }
00442 
00443  
00444 void opreport_formatter::show_details(bool on_off)
00445 {
00446     need_details = on_off;
00447 }
00448 
00449 
00450 void opreport_formatter::output(ostream & out, symbol_entry const * symb)
00451 {
00452     do_output(out, *symb, symb->sample, counts);
00453 
00454     if (need_details)
00455         output_details(out, symb);
00456 }
00457 
00458 
00459 void opreport_formatter::
00460 output(ostream & out, symbol_collection const & syms)
00461 {
00462     output_header(out);
00463 
00464     symbol_collection::const_iterator it = syms.begin();
00465     symbol_collection::const_iterator end = syms.end();
00466     for (; it != end; ++it)
00467         output(out, *it);
00468 }
00469 
00470 
00471 void opreport_formatter::
00472 output_details(ostream & out, symbol_entry const * symb)
00473 {
00474     counts_t c = counts;
00475 
00476     if (!global_percent)
00477         c.total = symb->sample.counts;
00478 
00479     // cumulated percent are relative to current symbol.
00480     c.cumulated_samples = count_array_t();
00481     c.cumulated_percent = count_array_t();
00482 
00483     sample_container::samples_iterator it = profile.begin(symb);
00484     sample_container::samples_iterator end = profile.end(symb);
00485     for (; it != end; ++it) {
00486         out << "  ";
00487         do_output(out, *symb, it->second, c, diff_array_t(), true);
00488     }
00489 }
00490 
00491  
00492 cg_formatter::cg_formatter(callgraph_container const & profile)
00493     :
00494     formatter(profile.extra_found_images)
00495 {
00496     counts.total = profile.samples_count();
00497 }
00498 
00499 
00500 void cg_formatter::output(ostream & out, symbol_collection const & syms)
00501 {
00502     // amount of spacing prefixing child and parent lines
00503     string const child_parent_prefix("  ");
00504 
00505     output_header(out);
00506 
00507     out << string(79, '-') << endl;
00508 
00509     symbol_collection::const_iterator it;
00510     symbol_collection::const_iterator end = syms.end();
00511 
00512     for (it = syms.begin(); it < end; ++it) {
00513         cg_symbol const * sym = dynamic_cast<cg_symbol const *>(*it);
00514 
00515         cg_symbol::children::const_iterator cit;
00516         cg_symbol::children::const_iterator cend = sym->callers.end();
00517 
00518         counts_t c;
00519         if (global_percent)
00520             c.total = counts.total;
00521         else
00522             c.total = sym->total_caller_count;
00523 
00524         for (cit = sym->callers.begin(); cit != cend; ++cit) {
00525             out << child_parent_prefix;
00526             do_output(out, *cit, cit->sample, c);
00527         }
00528 
00529         do_output(out, *sym, sym->sample, counts);
00530 
00531         c = counts_t();
00532         if (global_percent)
00533             c.total = counts.total;
00534         else
00535             c.total = sym->total_callee_count;
00536 
00537         cend = sym->callees.end();
00538 
00539         for (cit = sym->callees.begin(); cit != cend; ++cit) {
00540             out << child_parent_prefix;
00541             do_output(out, *cit, cit->sample, c);
00542         }
00543 
00544         out << string(79, '-') << endl;
00545     }
00546 }
00547 
00548 
00549 diff_formatter::diff_formatter(diff_container const & profile,
00550                    extra_images const & extra)
00551     :
00552     formatter(extra)
00553 {
00554     counts.total = profile.samples_count();
00555 }
00556 
00557 
00558 void diff_formatter::output(ostream & out, diff_collection const & syms)
00559 {
00560     output_header(out);
00561 
00562     diff_collection::const_iterator it = syms.begin();
00563     diff_collection::const_iterator end = syms.end();
00564     for (; it != end; ++it)
00565         do_output(out, *it, it->sample, counts, it->diffs);
00566 }
00567 
00568 // local variables used in generation of XML
00569 // buffer details for output later
00570 ostringstream bytes_out;
00571 
00572 // module+symbol table for detecting duplicate symbols
00573 map<string, size_t> symbol_data_table;
00574 size_t symbol_data_index = 0;
00575 
00576 /* Return any existing index or add to the table */
00577 size_t xml_get_symbol_index(string const & name)
00578 {
00579     size_t index = symbol_data_index;
00580     map<string, size_t>::iterator it = symbol_data_table.find(name);
00581 
00582     if (it == symbol_data_table.end()) {
00583         symbol_data_table[name] = symbol_data_index++;
00584         return index;
00585     }
00586 
00587     return it->second;
00588 }
00589 
00590 
00591 class symbol_details_t {
00592 public:
00593     symbol_details_t() { size = index = 0; id = -1; }
00594     int id;
00595     size_t size;
00596     size_t index;
00597     string details;
00598 };
00599 
00600 typedef growable_vector<symbol_details_t> symbol_details_array_t;
00601 symbol_details_array_t symbol_details;
00602 size_t detail_table_index = 0;
00603 
00604 xml_formatter::
00605 xml_formatter(profile_container const * p,
00606           symbol_collection & s, extra_images const & extra,
00607           string_filter const & sf)
00608     :
00609     formatter(extra),
00610     profile(p),
00611     symbols(s),
00612     need_details(false),
00613     symbol_filter(sf)
00614 {
00615     if (profile)
00616         counts.total = profile->samples_count();
00617 }
00618 
00619 
00620 void xml_formatter::
00621 show_details(bool on_off)
00622 {
00623     need_details = on_off;
00624 }
00625 
00626 
00627 void xml_formatter::output(ostream & out)
00628 {
00629     xml_support->build_subclasses(out);
00630 
00631     xml_support->output_program_structure(out);
00632     output_symbol_data(out);
00633     if (need_details) {
00634         out << open_element(DETAIL_TABLE);
00635         for (size_t i = 0; i < symbol_details.size(); ++i) {
00636             int id = symbol_details[i].id;
00637 
00638             if (id >= 0) {
00639                 out << open_element(SYMBOL_DETAILS, true);
00640                 out << init_attr(TABLE_ID, (size_t)id);
00641                 out << close_element(NONE, true);
00642                 out << symbol_details[i].details;
00643                 out << close_element(SYMBOL_DETAILS);
00644             }
00645         }
00646         out << close_element(DETAIL_TABLE);
00647 
00648         // output bytesTable
00649         out << open_element(BYTES_TABLE);
00650         out << bytes_out.str();
00651         out << close_element(BYTES_TABLE);
00652     }
00653 
00654     out << close_element(PROFILE);
00655 }
00656 
00657 bool
00658 xml_formatter::get_bfd_object(symbol_entry const * symb, op_bfd * & abfd) const
00659 {
00660     bool ok = true;
00661 
00662     string const & image_name = get_image_name(symb->image_name,
00663         image_name_storage::int_filename, extra_found_images);
00664     if (symb->spu_offset) {
00665         // FIXME: what about archive:tmp, actually it's not supported
00666         // for spu since oparchive doesn't archive the real file but
00667         // in future it would work ?
00668         string tmp = get_image_name(symb->embedding_filename, 
00669             image_name_storage::int_filename, extra_found_images);
00670         if (abfd && abfd->get_filename() == tmp)
00671             return true;
00672         delete abfd;
00673         abfd = new op_bfd(symb->spu_offset, tmp,
00674                   symbol_filter, extra_found_images, ok);
00675     } else {
00676         if (abfd && abfd->get_filename() == image_name)
00677             return true;
00678         delete abfd;
00679         abfd = new op_bfd(image_name, symbol_filter,
00680                   extra_found_images, ok);
00681 
00682     }
00683 
00684     if (!ok) {
00685         report_image_error(image_name, image_format_failure,
00686                    false, extra_found_images);
00687         delete abfd;
00688         abfd = 0;
00689         return false;
00690     }
00691 
00692     return true;
00693 }
00694 
00695 void xml_formatter::
00696 output_the_symbol_data(ostream & out, symbol_entry const * symb, op_bfd * & abfd)
00697 {
00698     string const name = symbol_names.name(symb->name);
00699     assert(name.size() > 0);
00700 
00701     string const image = get_image_name(symb->image_name,
00702         image_name_storage::int_filename, extra_found_images);
00703     string const qname = image + ":" + name;
00704     map<string, size_t>::iterator sd_it = symbol_data_table.find(qname);
00705 
00706     if (sd_it != symbol_data_table.end()) {
00707         // first time we've seen this symbol
00708         out << open_element(SYMBOL_DATA, true);
00709         out << init_attr(TABLE_ID, sd_it->second);
00710 
00711         field_datum datum(*symb, symb->sample, 0, counts,
00712                   extra_found_images);
00713 
00714         output_attribute(out, datum, ff_symb_name, NAME);
00715 
00716         if (flags & ff_linenr_info) {
00717             output_attribute(out, datum, ff_linenr_info, SOURCE_FILE);
00718             output_attribute(out, datum, ff_linenr_info, SOURCE_LINE);
00719         }
00720 
00721         if (name.size() > 0 && name[0] != '?') {
00722             output_attribute(out, datum, ff_vma, STARTING_ADDR);
00723 
00724             if (need_details) {
00725                 get_bfd_object(symb, abfd);
00726                 if (abfd && abfd->symbol_has_contents(symb->sym_index))
00727                     xml_support->output_symbol_bytes(bytes_out, symb, sd_it->second, *abfd);
00728             }
00729         }
00730         out << close_element();
00731 
00732         // seen so remove (otherwise get several "no symbols")
00733         symbol_data_table.erase(qname);
00734     }
00735 }
00736 
00737 void xml_formatter::output_cg_children(ostream & out, 
00738     cg_symbol::children const cg_symb, op_bfd * & abfd)
00739 {
00740     cg_symbol::children::const_iterator cit;
00741     cg_symbol::children::const_iterator cend = cg_symb.end();
00742 
00743     for (cit = cg_symb.begin(); cit != cend; ++cit) {
00744         string const name = symbol_names.name(cit->name);
00745         string const image = get_image_name(cit->image_name,
00746             image_name_storage::int_filename, extra_found_images);
00747         string const qname = image + ":" + name;
00748         map<string, size_t>::iterator sd_it = symbol_data_table.find(qname);
00749 
00750         if (sd_it != symbol_data_table.end()) {
00751             symbol_entry const * child = &(*cit);
00752             output_the_symbol_data(out, child, abfd);
00753         }
00754     }
00755 }
00756 
00757 void xml_formatter::output_symbol_data(ostream & out)
00758 {
00759     op_bfd * abfd = NULL;
00760     sym_iterator it = symbols.begin();
00761     sym_iterator end = symbols.end();
00762 
00763     out << open_element(SYMBOL_TABLE);
00764     for ( ; it != end; ++it) {
00765         symbol_entry const * symb = *it;
00766         cg_symbol const * cg_symb = dynamic_cast<cg_symbol const *>(symb);
00767         output_the_symbol_data(out, symb, abfd);
00768         if (cg_symb) {
00769             /* make sure callers/callees are included in SYMBOL_TABLE */
00770             output_cg_children(out, cg_symb->callers, abfd);
00771             output_cg_children(out, cg_symb->callees, abfd);
00772         }
00773     }
00774     out << close_element(SYMBOL_TABLE);
00775 
00776     delete abfd;
00777 }
00778 
00779 string  xml_formatter::
00780 output_symbol_details(symbol_entry const * symb,
00781     size_t & detail_index, size_t const lo, size_t const hi)
00782 {
00783     if (!has_sample_counts(symb->sample.counts, lo, hi))
00784         return "";
00785 
00786     sample_container::samples_iterator it = profile->begin(symb);
00787     sample_container::samples_iterator end = profile->end(symb);
00788 
00789     ostringstream str;
00790     for (; it != end; ++it) {
00791         counts_t c;
00792 
00793         for (size_t p = lo; p <= hi; ++p)  {
00794             size_t count = it->second.counts[p];
00795 
00796             if (count == 0) continue;
00797 
00798             str << open_element(DETAIL_DATA, true);
00799             str << init_attr(TABLE_ID, detail_index++);
00800 
00801             // first output the vma field
00802             field_datum datum(*symb, it->second, 0, c, 
00803                       extra_found_images, 0.0);
00804             output_attribute(str, datum, ff_vma, VMA);
00805             if (ff_linenr_info) {
00806                 string sym_file;
00807                 size_t sym_line;
00808                 string samp_file;
00809                 size_t samp_line;
00810                 string sym_info = get_linenr_info(symb->sample.file_loc, true);
00811                 string samp_info = get_linenr_info(it->second.file_loc, true);
00812 
00813                 if (extract_linenr_info(samp_info, samp_file, samp_line)) {
00814                     if (extract_linenr_info(sym_info, sym_file, sym_line)) {
00815                         // only output source_file if it is different than the symbol's 
00816                         // source file.  this can happen with inlined functions in
00817                         // #included header files
00818                         if (sym_file != samp_file)
00819                             str << init_attr(SOURCE_FILE, samp_file);
00820                     }
00821                     str << init_attr(SOURCE_LINE, samp_line);
00822                 }
00823             }
00824             str << close_element(NONE, true);
00825 
00826             // output buffered sample data
00827             output_sample_data(str, it->second, p);
00828 
00829             str << close_element(DETAIL_DATA);
00830         }
00831     }
00832     return str.str();
00833 }
00834 
00835 void xml_formatter::
00836 output_symbol(ostream & out,
00837     symbol_entry const * symb, size_t lo, size_t hi, bool is_module)
00838 {
00839     ostringstream str;
00840     // pointless reference to is_module, remove insane compiler warning
00841     size_t indx = is_module ? 0 : 1;
00842 
00843     // output symbol's summary data for each profile class
00844     bool got_samples = false;
00845 
00846     for (size_t p = lo; p <= hi; ++p) {
00847         got_samples |= xml_support->output_summary_data(str,
00848             symb->sample.counts, p);
00849     }
00850 
00851     if (!got_samples)
00852         return;
00853 
00854     if (cverb << vxml)
00855         out << "<!-- symbol_ref=" << symbol_names.name(symb->name) <<
00856             " -->" << endl;
00857 
00858     out << open_element(SYMBOL, true);
00859 
00860     string const name = symbol_names.name(symb->name);
00861     assert(name.size() > 0);
00862     
00863     string const image = get_image_name(symb->image_name,
00864         image_name_storage::int_filename, extra_found_images);
00865     string const qname = image + ":" + name;
00866 
00867     indx = xml_get_symbol_index(qname);
00868 
00869     out << init_attr(ID_REF, indx);
00870 
00871     if (need_details) {
00872         ostringstream details;
00873         symbol_details_t & sd = symbol_details[indx];
00874         size_t const detail_lo = sd.index;
00875 
00876         string detail_str = output_symbol_details(symb, sd.index, lo, hi);
00877 
00878         if (detail_str.size() > 0) {
00879             if (sd.id < 0)
00880                 sd.id = indx;
00881             details << detail_str;
00882         }
00883 
00884         if (sd.index > detail_lo) {
00885             sd.details = sd.details + details.str();
00886             out << init_attr(DETAIL_LO, detail_lo);
00887             out << init_attr(DETAIL_HI, sd.index-1);
00888         }
00889     }
00890     out << close_element(NONE, true);
00891     // output summary
00892     out << str.str();
00893     out << close_element(SYMBOL);
00894 }
00895 
00896 
00897 void xml_formatter::
00898 output_sample_data(ostream & out, sample_entry const & sample, size_t pclass)
00899 {
00900     out << open_element(COUNT, true);
00901     out << init_attr(CLASS, classes.v[pclass].name);
00902     out << close_element(NONE, true);
00903     out << sample.counts[pclass];
00904     out << close_element(COUNT);
00905 }
00906 
00907 
00908 void xml_formatter::
00909 output_attribute(ostream & out, field_datum const & datum,
00910                  format_flags fl, tag_t tag)
00911 {
00912     field_description const & field(format_map[fl]);
00913 
00914     string str = (this->*field.formatter)(datum);
00915 
00916     if (!str.empty()) {
00917         if (fl == ff_linenr_info && (tag == SOURCE_LINE || tag == SOURCE_FILE)) {
00918             string file;
00919             size_t line;
00920 
00921             if (extract_linenr_info(str, file, line)) {
00922                 if (tag == SOURCE_LINE)
00923                     out << init_attr(tag, line);
00924                 else
00925                     out << init_attr(tag, file);
00926             }
00927         } else
00928             out << " " << init_attr(tag, str);
00929     }
00930 }
00931 
00932 xml_cg_formatter::
00933 xml_cg_formatter(callgraph_container const & cg, symbol_collection & s,
00934          string_filter const & sf)
00935     :
00936     xml_formatter(0, s, cg.extra_found_images, sf),
00937     callgraph(cg)
00938 {
00939     counts.total = callgraph.samples_count();
00940 }
00941 
00942 void xml_cg_formatter::
00943 output_symbol_core(ostream & out, cg_symbol::children const cg_symb,
00944        string const selfname, string const qname,
00945        size_t lo, size_t hi, bool is_module, tag_t tag)
00946 {
00947     cg_symbol::children::const_iterator cit;
00948     cg_symbol::children::const_iterator cend = cg_symb.end();
00949 
00950     for (cit = cg_symb.begin(); cit != cend; ++cit) {
00951         string const & module = get_image_name((cit)->image_name,
00952             image_name_storage::int_filename, extra_found_images);
00953         bool self = false;
00954         ostringstream str;
00955         size_t indx;
00956 
00957         // output symbol's summary data for each profile class
00958         for (size_t p = lo; p <= hi; ++p)
00959             xml_support->output_summary_data(str, cit->sample.counts, p);
00960 
00961         if (cverb << vxml)
00962             out << "<!-- symbol_ref=" << symbol_names.name(cit->name) <<
00963                 " -->" << endl;
00964 
00965         if (is_module) {
00966             out << open_element(MODULE, true);
00967             out << init_attr(NAME, module) << close_element(NONE, true);
00968         }
00969 
00970         out << open_element(SYMBOL, true);
00971 
00972         string const symname = symbol_names.name(cit->name);
00973         assert(symname.size() > 0);
00974 
00975         string const symqname = module + ":" + symname;
00976 
00977         // Find any self references and handle
00978         if ((symname == selfname) && (tag == CALLEES)) {
00979             self = true;
00980             indx = xml_get_symbol_index(qname);
00981         } else {
00982             indx = xml_get_symbol_index(symqname);
00983         }
00984 
00985         out << init_attr(ID_REF, indx);
00986 
00987         if (self)
00988             out << init_attr(SELFREF, "true");
00989 
00990         out << close_element(NONE, true);
00991         out << str.str();
00992         out << close_element(SYMBOL);
00993 
00994         if (is_module)
00995             out << close_element(MODULE);
00996     }
00997 }
00998 
00999 
01000 void xml_cg_formatter::
01001 output_symbol(ostream & out,
01002     symbol_entry const * symb, size_t lo, size_t hi, bool is_module)
01003 {
01004     cg_symbol const * cg_symb = dynamic_cast<cg_symbol const *>(symb);
01005     ostringstream str;
01006     size_t indx;
01007 
01008     // output symbol's summary data for each profile class
01009     for (size_t p = lo; p <= hi; ++p)
01010         xml_support->output_summary_data(str, symb->sample.counts, p);
01011 
01012     if (cverb << vxml)
01013         out << "<!-- symbol_ref=" << symbol_names.name(symb->name) <<
01014             " -->" << endl;
01015 
01016     out << open_element(SYMBOL, true);
01017 
01018     string const name = symbol_names.name(symb->name);
01019     assert(name.size() > 0);
01020 
01021     string const image = get_image_name(symb->image_name,
01022         image_name_storage::int_filename, extra_found_images);
01023     string const qname = image + ":" + name;
01024 
01025     string const selfname = symbol_names.demangle(symb->name) + " [self]";
01026 
01027     indx = xml_get_symbol_index(qname);
01028 
01029     out << init_attr(ID_REF, indx);
01030 
01031     out << close_element(NONE, true);
01032 
01033     out << open_element(CALLERS);
01034     if (cg_symb)
01035         output_symbol_core(out, cg_symb->callers, selfname, qname, lo, hi, is_module, CALLERS);
01036     out << close_element(CALLERS);
01037 
01038     out << open_element(CALLEES);
01039     if (cg_symb)
01040         output_symbol_core(out, cg_symb->callees, selfname, qname, lo, hi, is_module, CALLEES);
01041 
01042     out << close_element(CALLEES);
01043 
01044     // output summary
01045     out << str.str();
01046     out << close_element(SYMBOL);
01047 }
01048 
01049 } // namespace format_output

Generated on 8 Nov 2012 for Oprofile by  doxygen 1.6.1