From: John L. <mov...@us...> - 2005-04-12 03:14:20
|
Update of /cvsroot/oprofile/oprofile/libpp In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27947/libpp Modified Files: Makefile.am format_flags.h format_output.cpp format_output.h profile_spec.cpp profile_spec.h symbol.h symbol_functors.cpp symbol_sort.cpp symbol_sort.h Added Files: diff_container.cpp diff_container.h Removed Files: count_array.cpp count_array.h Log Message: initial stab at diffing profiles --- NEW FILE: diff_container.cpp --- /** * @file diff_container.cpp * Container for diffed symbols * * @remark Copyright 2005 OProfile authors * @remark Read the file COPYING * * @author Philippe Elie * @author John Levon */ #include "diff_container.h" #include <cmath> using namespace std; namespace { /// a comparator suitable for diffing symbols bool rough_less(symbol_entry const & lhs, symbol_entry const & rhs) { if (lhs.image_name != rhs.image_name) return lhs.image_name < rhs.image_name; if (lhs.app_name != rhs.app_name) return lhs.app_name < rhs.app_name; if (lhs.name != rhs.name) return lhs.name < rhs.name; return false; } /// add a symbol not present in the new profile void symbol_old(diff_collection & syms, symbol_entry const & sym) { diff_symbol symbol(sym); size_t size = sym.sample.counts.size(); for (size_t i = 0; i != size; ++i) symbol.diffs[i] = -INFINITY; syms.push_back(symbol); } /// add a symbol not present in the old profile void symbol_new(diff_collection & syms, symbol_entry const & sym) { diff_symbol symbol(sym); size_t size = sym.sample.counts.size(); for (size_t i = 0; i != size; ++i) symbol.diffs[i] = INFINITY; syms.push_back(symbol); } /// add a diffed symbol void symbol_diff(diff_collection & syms, symbol_entry const & sym1, count_array_t const & total1, symbol_entry const & sym2, count_array_t const & total2) { diff_symbol symbol(sym2); size_t size = sym2.sample.counts.size(); for (size_t i = 0; i != size; ++i) { double percent1; double percent2; percent1 = op_ratio(sym1.sample.counts[i], total1[i]); percent2 = op_ratio(sym2.sample.counts[i], total2[i]); symbol.diffs[i] = op_ratio(percent2 - percent1, percent1); } syms.push_back(symbol); } }; // namespace anon diff_container::diff_container(profile_container const & pc1, profile_container const & pc2) { total1 = pc1.samples_count(); total2 = pc2.samples_count(); symbol_container::symbols_t::iterator it1 = pc1.begin_symbol(); symbol_container::symbols_t::iterator end1 = pc1.end_symbol(); symbol_container::symbols_t::iterator it2 = pc2.begin_symbol(); symbol_container::symbols_t::iterator end2 = pc2.end_symbol(); while (it1 != end1 && it2 != end2) { if (rough_less(*it1, *it2)) { symbol_old(syms, *it1); ++it1; } else if (rough_less(*it2, *it1)) { symbol_new(syms, *it1); ++it2; } else { symbol_diff(syms, *it1, total1, *it2, total2); ++it1; ++it2; } } for (; it1 != end1; ++it1) symbol_old(syms, *it1); for (; it2 != end2; ++it2) symbol_new(syms, *it2); } diff_collection const diff_container::get_symbols() const { return syms; } count_array_t const diff_container::samples_count() const { return total2; } --- NEW FILE: diff_container.h --- /** * @file diff_container.h * Container for diffed symbols * * @remark Copyright 2005 OProfile authors * @remark Read the file COPYING * * @author Philippe Elie * @author John Levon */ #ifndef DIFF_CONTAINER_H #define DIFF_CONTAINER_H #include "profile_container.h" #include "symbol.h" /** * Store two profiles for diffing. */ class diff_container : noncopyable { public: /// populate the collection of diffed symbols diff_container(profile_container const & pc1, profile_container const & pc2); ~diff_container() {} /// return a collection of diffed symbols diff_collection const get_symbols() const; /// total count for 'new' profile count_array_t const samples_count() const; private: /// the diffed symbols diff_collection syms; /// samples count for pc1 count_array_t total1; /// samples count for pc2 count_array_t total2; }; #endif /* !DIFF_CONTAINER_H */ Index: Makefile.am =================================================================== RCS file: /cvsroot/oprofile/oprofile/libpp/Makefile.am,v retrieving revision 1.11 retrieving revision 1.12 diff -u -p -d -r1.11 -r1.12 --- Makefile.am 29 Jan 2004 23:04:59 -0000 1.11 +++ Makefile.am 12 Apr 2005 03:14:09 -0000 1.12 @@ -15,8 +15,8 @@ libpp_a_SOURCES = \ arrange_profiles.h \ callgraph_container.h \ callgraph_container.cpp \ - count_array.cpp \ - count_array.h \ + diff_container.cpp \ + diff_container.h \ filename_spec.cpp \ filename_spec.h \ format_flags.h \ Index: format_flags.h =================================================================== RCS file: /cvsroot/oprofile/oprofile/libpp/format_flags.h,v retrieving revision 1.6 retrieving revision 1.7 diff -u -p -d -r1.6 -r1.7 --- format_flags.h 4 Apr 2005 20:18:03 -0000 1.6 +++ format_flags.h 12 Apr 2005 03:14:09 -0000 1.7 @@ -30,7 +30,7 @@ enum format_flags { /// output the (demangled) symbol name ff_symb_name = 1 << 5, - /** @name subset of flags used by opreport_formater */ + /** @name subset of flags used by opreport_formatter */ //@{ /// number of samples ff_nr_samples = 1 << 6, @@ -40,7 +40,6 @@ enum format_flags { ff_percent = 1 << 8, /// relative percentage of samples accumulated ff_percent_cumulated = 1 << 9, - /// output debug filename and line nr. /** * Output percentage for details, not relative * to symbol but relative to the total nr of samples @@ -52,6 +51,8 @@ enum format_flags { * accumulated */ ff_percent_cumulated_details = 1 << 11, + /// output diff value + ff_diff = 1 << 12, //@} }; Index: format_output.cpp =================================================================== RCS file: /cvsroot/oprofile/oprofile/libpp/format_output.cpp,v retrieving revision 1.29 retrieving revision 1.30 diff -u -p -d -r1.29 -r1.30 --- format_output.cpp 4 Apr 2005 23:46:33 -0000 1.29 +++ format_output.cpp 12 Apr 2005 03:14:09 -0000 1.30 @@ -12,12 +12,14 @@ #include <sstream> #include <iomanip> #include <iostream> +#include <cmath> #include "string_manip.h" #include "format_output.h" #include "profile_container.h" #include "callgraph_container.h" +#include "diff_container.h" using namespace std; @@ -78,17 +80,18 @@ formatter::formatter() long_filenames(false), need_header(true) { - format_map[ff_vma] = field_description(9, "vma", &opreport_formatter::format_vma); - format_map[ff_nr_samples] = field_description(9, "samples", &opreport_formatter::format_nr_samples); - format_map[ff_nr_samples_cumulated] = field_description(14, "cum. samples", &opreport_formatter::format_nr_cumulated_samples); - format_map[ff_percent] = field_description(9, "%", &opreport_formatter::format_percent); - format_map[ff_percent_cumulated] = field_description(11, "cum. %", &opreport_formatter::format_cumulated_percent); - format_map[ff_linenr_info] = field_description(28, "linenr info", &opreport_formatter::format_linenr_info); - format_map[ff_image_name] = field_description(25, "image name", &opreport_formatter::format_image_name); - format_map[ff_app_name] = field_description(25, "app name", &opreport_formatter::format_app_name); - format_map[ff_symb_name] = field_description(30, "symbol name", &opreport_formatter::format_symb_name); - format_map[ff_percent_details] = field_description(9, "%", &opreport_formatter::format_percent_details); - format_map[ff_percent_cumulated_details] = field_description(10, "cum. %", &opreport_formatter::format_cumulated_percent_details); + format_map[ff_vma] = field_description(9, "vma", &formatter::format_vma); + format_map[ff_nr_samples] = field_description(9, "samples", &formatter::format_nr_samples); + format_map[ff_nr_samples_cumulated] = field_description(14, "cum. samples", &formatter::format_nr_cumulated_samples); + format_map[ff_percent] = field_description(9, "%", &formatter::format_percent); + format_map[ff_percent_cumulated] = field_description(11, "cum. %", &formatter::format_cumulated_percent); + format_map[ff_linenr_info] = field_description(28, "linenr info", &formatter::format_linenr_info); + format_map[ff_image_name] = field_description(25, "image name", &formatter::format_image_name); + format_map[ff_app_name] = field_description(25, "app name", &formatter::format_app_name); + format_map[ff_symb_name] = field_description(30, "symbol name", &formatter::format_symb_name); + format_map[ff_percent_details] = field_description(9, "%", &formatter::format_percent_details); + format_map[ff_percent_cumulated_details] = field_description(10, "cum. %", &formatter::format_cumulated_percent_details); + format_map[ff_diff] = field_description(10, "diff %", &formatter::format_diff); } @@ -162,6 +165,10 @@ void formatter::output_header(ostream & padding = output_header_field(out, ff_percent_cumulated, padding); + if (flags & ff_diff) + padding = output_header_field(out, + ff_diff, padding); + if (flags & ff_percent_details) padding = output_header_field(out, ff_percent_details, padding); @@ -274,6 +281,8 @@ string formatter::format_nr_samples(fiel string formatter::format_nr_cumulated_samples(field_datum const & f) { + if (f.diff == -INFINITY) + return "---"; ostringstream out; f.counts.cumulated_samples[f.pclass] += f.sample.counts[f.pclass]; out << f.counts.cumulated_samples[f.pclass]; @@ -283,12 +292,16 @@ string formatter::format_nr_cumulated_sa string formatter::format_percent(field_datum const & f) { + if (f.diff == -INFINITY) + return "---"; return get_percent(f.sample.counts[f.pclass], f.counts.total[f.pclass]); } string formatter::format_cumulated_percent(field_datum const & f) { + if (f.diff == -INFINITY) + return "---"; f.counts.cumulated_percent[f.pclass] += f.sample.counts[f.pclass]; return get_percent(f.counts.cumulated_percent[f.pclass], @@ -312,9 +325,26 @@ string formatter::format_cumulated_perce } +string formatter::format_diff(field_datum const & f) +{ + if (f.diff == INFINITY) { + ostringstream out; + out << "+++"; + return out.str(); + } else if (f.diff == -INFINITY) { + ostringstream out; + out << "---"; + return out.str(); + } + + return ::format_percent(f.diff, percent_int_width, + percent_fract_width, true); +} + + void formatter:: do_output(ostream & out, symbol_entry const & symb, sample_entry const & sample, - counts_t & c, bool hide_immutable) + counts_t & c, diff_array_t const & diffs, bool hide_immutable) { size_t padding = 0; @@ -325,7 +355,7 @@ do_output(ostream & out, symbol_entry co // repeated fields for each profile class for (size_t pclass = 0 ; pclass < nr_classes; ++pclass) { - field_datum datum(symb, sample, pclass, c); + field_datum datum(symb, sample, pclass, c, diffs[pclass]); if (flags & ff_nr_samples) padding = output_field(out, datum, @@ -343,6 +373,10 @@ do_output(ostream & out, symbol_entry co padding = output_field(out, datum, ff_percent_cumulated, padding, false); + if (flags & ff_diff) + padding = output_field(out, datum, + ff_diff, padding, false); + if (flags & ff_percent_details) padding = output_field(out, datum, ff_percent_details, padding, false); @@ -425,7 +459,7 @@ output_details(ostream & out, symbol_ent sample_container::samples_iterator end = profile.end(symb); for (; it != end; ++it) { out << " "; - do_output(out, *symb, it->second, c, true); + do_output(out, *symb, it->second, c, diff_array_t(), true); } } @@ -485,4 +519,21 @@ void cg_formatter::output(ostream & out, } +diff_formatter::diff_formatter(diff_container const & profile) +{ + counts.total = profile.samples_count(); +} + + +void diff_formatter::output(ostream & out, diff_collection const & syms) +{ + output_header(out); + + diff_collection::const_iterator it = syms.begin(); + diff_collection::const_iterator end = syms.end(); + for (; it != end; ++it) + do_output(out, *it, it->sample, counts, it->diffs); +} + + } // namespace format_output Index: format_output.h =================================================================== RCS file: /cvsroot/oprofile/oprofile/libpp/format_output.h,v retrieving revision 1.18 retrieving revision 1.19 diff -u -p -d -r1.18 -r1.19 --- format_output.h 4 Apr 2005 23:25:44 -0000 1.18 +++ format_output.h 12 Apr 2005 03:14:09 -0000 1.19 @@ -25,6 +25,7 @@ class symbol_entry; class sample_entry; class callgraph_container; class profile_container; +class diff_container; namespace format_output { @@ -75,12 +76,14 @@ protected: struct field_datum { field_datum(symbol_entry const & sym, sample_entry const & s, - size_t pc, counts_t & c) - : symbol(sym), sample(s), pclass(pc), counts(c) {} + size_t pc, counts_t & c, double d = 0.0) + : symbol(sym), sample(s), pclass(pc), + counts(c), diff(d) {} symbol_entry const & symbol; sample_entry const & sample; size_t pclass; mutable counts_t & counts; + double diff; }; /// format callback type @@ -101,6 +104,7 @@ protected: std::string format_cumulated_percent(field_datum const &); std::string format_percent_details(field_datum const &); std::string format_cumulated_percent_details(field_datum const &); + std::string format_diff(field_datum const &); //@} /// decribe one field of the colummned output. @@ -119,6 +123,7 @@ protected: /// actually do output void do_output(std::ostream & out, symbol_entry const & symbol, sample_entry const & sample, counts_t & c, + diff_array_t const & = diff_array_t(), bool hide_immutable_field = false); /// returns the nr of char needed to pad this field @@ -194,6 +199,24 @@ public: void output(std::ostream & out, cg_collection const & syms); }; +/// class to output a columned format symbols plus diff values +class diff_formatter : public formatter { +public: + /// build a ready to use formatter + diff_formatter(diff_container const & profile); + + /** + * Output a vector of symbols to out according to the output + * format specifier previously set by call(s) to add_format() + */ + void output(std::ostream & out, diff_collection const & syms); + +private: + /// output a single symbol + void output(std::ostream & out, diff_symbol const & sym); + +}; + } // namespace format_output #endif /* !FORMAT_OUTPUT_H */ Index: profile_spec.cpp =================================================================== RCS file: /cvsroot/oprofile/oprofile/libpp/profile_spec.cpp,v retrieving revision 1.26 retrieving revision 1.27 diff -u -p -d -r1.26 -r1.27 --- profile_spec.cpp 6 Jul 2004 21:32:26 -0000 1.26 +++ profile_spec.cpp 12 Apr 2005 03:14:09 -0000 1.27 @@ -299,22 +299,25 @@ bool profile_spec::match(filename_spec c } -profile_spec profile_spec::create(vector<string> const & args, +profile_spec profile_spec::create(list<string> const & args, extra_images const & extra) { profile_spec spec(extra); set<string> tag_seen; - for (size_t i = 0 ; i < args.size() ; ++i) { - if (spec.is_valid_tag(args[i])) { - if (tag_seen.find(args[i]) != tag_seen.end()) { + list<string>::const_iterator it = args.begin(); + list<string>::const_iterator end = args.end(); + + for (; it != end; ++it) { + if (spec.is_valid_tag(*it)) { + if (tag_seen.find(*it) != tag_seen.end()) { throw op_runtime_error("tag specified " - "more than once: " + args[i]); + "more than once: " + *it); } - tag_seen.insert(args[i]); - spec.parse(args[i]); + tag_seen.insert(*it); + spec.parse(*it); } else { - string const file = op_realpath(args[i]); + string const file = op_realpath(*it); spec.set_image_or_lib_name(file); } } Index: profile_spec.h =================================================================== RCS file: /cvsroot/oprofile/oprofile/libpp/profile_spec.h,v retrieving revision 1.8 retrieving revision 1.9 diff -u -p -d -r1.8 -r1.9 --- profile_spec.h 6 Jul 2004 21:32:26 -0000 1.8 +++ profile_spec.h 12 Apr 2005 03:14:09 -0000 1.9 @@ -39,7 +39,7 @@ public: * substitution, non-valid tag:value options are considered * as image:value */ - static profile_spec create(std::vector<std::string> const & args, + static profile_spec create(std::list<std::string> const & args, extra_images const & extra); /** Index: symbol.h =================================================================== RCS file: /cvsroot/oprofile/oprofile/libpp/symbol.h,v retrieving revision 1.9 retrieving revision 1.10 diff -u -p -d -r1.9 -r1.10 --- symbol.h 4 Apr 2005 20:18:03 -0000 1.9 +++ symbol.h 12 Apr 2005 03:14:09 -0000 1.10 @@ -13,13 +13,19 @@ #define SYMBOL_H #include "name_storage.h" -#include "count_array.h" +#include "growable_vector.h" #include "format_flags.h" +#include "op_types.h" #include <bfd.h> #include <list> + +/// for storing sample counts +typedef growable_vector<u32> count_array_t; + + /// A simple container for a fileno:linenr location. struct file_location { file_location() : linenr(0) {} @@ -105,4 +111,23 @@ struct cg_symbol : public symbol_entry { typedef std::vector<cg_symbol> cg_collection; +/// for storing diff %ages +typedef growable_vector<double> diff_array_t; + + +/** + * Data for a diffed symbol. + */ +struct diff_symbol : public symbol_entry { + diff_symbol(symbol_entry const & sym) : symbol_entry(sym) {} + + /// diff %age values for each profile class + diff_array_t diffs; +}; + + +/// a collection of diffed symbols +typedef std::vector<diff_symbol> diff_collection; + + #endif /* !SYMBOL_H */ Index: symbol_functors.cpp =================================================================== RCS file: /cvsroot/oprofile/oprofile/libpp/symbol_functors.cpp,v retrieving revision 1.3 retrieving revision 1.4 diff -u -p -d -r1.3 -r1.4 --- symbol_functors.cpp 8 Jun 2003 03:44:13 -0000 1.3 +++ symbol_functors.cpp 12 Apr 2005 03:14:09 -0000 1.4 @@ -20,11 +20,11 @@ bool less_symbol::operator()(symbol_entr if (lhs.app_name != rhs.app_name) return lhs.app_name < rhs.app_name; - if (lhs.sample.vma != rhs.sample.vma) - return lhs.sample.vma < rhs.sample.vma; - if (lhs.name != rhs.name) return lhs.name < rhs.name; + if (lhs.sample.vma != rhs.sample.vma) + return lhs.sample.vma < rhs.sample.vma; + return lhs.size < rhs.size; } Index: symbol_sort.cpp =================================================================== RCS file: /cvsroot/oprofile/oprofile/libpp/symbol_sort.cpp,v retrieving revision 1.12 retrieving revision 1.13 diff -u -p -d -r1.12 -r1.13 --- symbol_sort.cpp 4 Apr 2005 20:18:03 -0000 1.12 +++ symbol_sort.cpp 12 Apr 2005 03:14:09 -0000 1.13 @@ -146,6 +146,32 @@ bool cg_symbol_compare::operator()(symbo } +struct diff_symbol_compare : public symbol_compare { + diff_symbol_compare(vector<sort_options::sort_order> const & order, + bool reverse) + : symbol_compare(order, reverse) {} + + bool operator()(symbol_entry const & lhs, + symbol_entry const & rhs) const; +}; + + +// FIXME: why do we need this +bool diff_symbol_compare::operator()(symbol_entry const & lhs, + symbol_entry const & rhs) const +{ + for (size_t i = 0; i < compare_order.size(); ++i) { + int ret = compare_by(compare_order[i], &lhs, &rhs); + + if (reverse_sort) + ret = -ret; + if (ret != 0) + return ret < 0; + } + return false; +} + + } // anonymous namespace @@ -183,6 +209,23 @@ sort(cg_collection & syms, bool reverse_ } +void sort_options:: +sort(diff_collection & syms, bool reverse_sort, bool lf) const +{ + long_filenames = lf; + + vector<sort_order> sort_option(options); + for (sort_order cur = first; cur != last; cur = sort_order(cur + 1)) { + if (find(sort_option.begin(), sort_option.end(), cur) == + sort_option.end()) + sort_option.push_back(cur); + } + + stable_sort(syms.begin(), syms.end(), + diff_symbol_compare(sort_option, reverse_sort)); +} + + void sort_options::add_sort_option(string const & name) { if (name == "vma") { Index: symbol_sort.h =================================================================== RCS file: /cvsroot/oprofile/oprofile/libpp/symbol_sort.h,v retrieving revision 1.5 retrieving revision 1.6 diff -u -p -d -r1.5 -r1.6 --- symbol_sort.h 4 Apr 2005 20:18:03 -0000 1.5 +++ symbol_sort.h 12 Apr 2005 03:14:09 -0000 1.6 @@ -47,6 +47,12 @@ struct sort_options { void sort(cg_collection & syms, bool reverse_sort, bool long_filenames) const; + /** + * Sort the given container by the given criteria. + */ + void sort(diff_collection & syms, bool reverse_sort, + bool long_filenames) const; + std::vector<sort_order> options; }; --- count_array.cpp DELETED --- --- count_array.h DELETED --- |