arrange_profiles.cpp

Go to the documentation of this file.
00001 
00012 #include <algorithm>
00013 #include <cstdlib>
00014 #include <iostream>
00015 #include <iterator>
00016 #include <map>
00017 #include <set>
00018 
00019 #include "string_manip.h"
00020 #include "op_header.h"
00021 #include "op_exception.h"
00022 
00023 #include "arrange_profiles.h"
00024 #include "format_output.h"
00025 #include "xml_utils.h"
00026 #include "parse_filename.h"
00027 #include "locate_images.h"
00028 
00029 using namespace std;
00030 
00031 namespace {
00032 
00033 int numeric_compare(string const & lhs, string const & rhs)
00034 {
00035     if (lhs == "all" && rhs == "all")
00036         return 0;
00037     // we choose an order arbitrarily
00038     if (lhs == "all")
00039         return 1;
00040     if (rhs == "all")
00041         return -1;
00042     unsigned int lhsval = op_lexical_cast<unsigned int>(lhs);
00043     unsigned int rhsval = op_lexical_cast<unsigned int>(rhs);
00044     if (lhsval == rhsval)
00045         return 0;
00046     if (lhsval < rhsval)
00047         return -1;
00048     return 1;
00049 }
00050 
00051 
00052 } // anonymous namespace
00053 
00054 
00055 // global to fix some C++ obscure corner case.
00056 bool operator<(profile_class const & lhs,
00057                profile_class const & rhs)
00058 {
00059     profile_template const & lt = lhs.ptemplate;
00060     profile_template const & rt = rhs.ptemplate;
00061     int comp;
00062 
00063     // The profile classes are used to traverse the sample data
00064     // arrays.  We create XML elements for <process> and <thread>
00065     // that contain the sample data that can then be divided amongst
00066     // CPU, event, mask axes so it is more convenient to have the
00067     // process and thread classes be the outermost nesting level of
00068     // the sample data arrays
00069     if (!want_xml) {
00070         comp = numeric_compare(lt.cpu, rt.cpu);
00071         if (comp)
00072             return comp < 0;
00073     }
00074 
00075     comp = numeric_compare(lt.tgid, rt.tgid);
00076     if (comp)
00077         return comp < 0;
00078 
00079     comp = numeric_compare(lt.tid, rt.tid);
00080     if (comp)
00081         return comp < 0;
00082 
00083     comp = numeric_compare(lt.unitmask, rt.unitmask);
00084     if (comp)
00085         return comp < 0;
00086 
00087     if (want_xml) {
00088         if (lt.event != rt.event)
00089             return lt.event < rt.event;
00090         if (lt.count != rt.count)
00091             return lt.count < rt.count;
00092 
00093         return numeric_compare(lt.cpu, rt.cpu) < 0;
00094     } else {
00095         if (lt.event == rt.event)
00096             return lt.count < rt.count;
00097         return lt.event < rt.event;
00098     }
00099 }
00100 
00101 namespace {
00102 
00103 struct axis_t {
00104     string name;
00105     string suggestion;
00106 } axes[AXIS_MAX] = {
00107     { "event", "specify event:, count: or unitmask: (see also --merge=unitmask)" },
00108     { "tgid", "specify tgid: or --merge tgid" },
00109     { "tid", "specify tid: or --merge tid" },
00110     { "cpu", "specify cpu: or --merge cpu" },
00111 };
00112 
00113 } // anonymous namespace
00114 
00115 
00116 bool profile_classes::matches(profile_classes const & classes)
00117 {
00118     if (v.size() != classes.v.size())
00119         return false;
00120 
00121     axis_types const axis2 = classes.axis;
00122 
00123     switch (axis) {
00124         case AXIS_EVENT:
00125             break;
00126         case AXIS_TGID:
00127         case AXIS_TID:
00128             return axis2 == AXIS_TID || axis2 == AXIS_TGID;
00129         case AXIS_CPU:
00130             return axis2 == AXIS_CPU;
00131         case AXIS_MAX:
00132             return false;
00133     }
00134 
00135     // check that the events match (same event, count)
00136 
00137     vector<profile_class>::const_iterator it1 = v.begin();
00138     vector<profile_class>::const_iterator end1 = v.end();
00139     vector<profile_class>::const_iterator it2 = classes.v.begin();
00140 
00141     while (it1 != end1) {
00142         if (it1->ptemplate.event != it2->ptemplate.event)
00143             return false;
00144         if (it1->ptemplate.count != it2->ptemplate.count)
00145             return false;
00146         // differing unit mask is considered comparable
00147         ++it1;
00148         ++it2;
00149     }
00150 
00151     return true;
00152 }
00153 
00154 namespace {
00155 
00156 typedef growable_vector<string> event_array_t;
00157 typedef growable_vector<string>::size_type event_index_t;
00158 
00159 bool new_event_index(string event, event_array_t & events, event_index_t & index)
00160 {
00161     event_index_t sz = events.size();
00162     for (event_index_t i = 0; i != sz; ++i) {
00163         if (events[i] == event) {
00164             index = i;
00165             return false;
00166         }
00167     }
00168 
00169     index = sz;
00170     events[sz] = event;
00171     return true;
00172 }
00173 
00174 
00176 void report_error(profile_classes const & classes, axis_types newaxis)
00177 {
00178     string str = "Already displaying results for parameter ";
00179     str += axes[classes.axis].name;
00180     str += " with values:\n";
00181     vector<profile_class>::const_iterator it = classes.v.begin();
00182     vector<profile_class>::const_iterator const end = classes.v.end();
00183 
00184     // We show error for the first conflicting axis but on this
00185     // axis we can get only a few different it->name, we display only
00186     // these different name.
00187     set <string> name_seen;
00188     size_t i = 5;
00189     for (; it != end && i; ++it) {
00190         if (name_seen.find(it->name) == name_seen.end()) {
00191             name_seen.insert(it->name);
00192             str += it->name + ",";
00193             --i;
00194         }
00195     }
00196 
00197     if (!i) {
00198         str += " and ";
00199         str += op_lexical_cast<string>(classes.v.size() - 5);
00200         str += " more,";
00201     }
00202 
00203     str += "\nwhich conflicts with parameter ";
00204     str += axes[newaxis].name += ".\n";
00205     str += "Suggestion: ";
00206     str += axes[classes.axis].suggestion;
00207     throw op_fatal_error(str);
00208 }
00209 
00210 
00216 bool allow_axes(profile_classes const & classes, axis_types newaxis)
00217 {
00218     // No previous axis - OK
00219     if (classes.axis == AXIS_MAX)
00220         return true;
00221 
00222     if (classes.axis != AXIS_TID && classes.axis != AXIS_TGID)
00223         return false;
00224 
00225     if (newaxis != AXIS_TID && newaxis != AXIS_TGID)
00226         return false;
00227 
00228     vector<profile_class>::const_iterator it = classes.v.begin();
00229     vector<profile_class>::const_iterator const end = classes.v.end();
00230 
00231     for (; it != end; ++it) {
00232         if (it->ptemplate.tgid != it->ptemplate.tid)
00233             return false;
00234     }
00235 
00236     return true;
00237 }
00238 
00239 
00241 opd_header const get_first_header(profile_class const & pclass)
00242 {
00243     profile_set const & profile = *(pclass.profiles.begin());
00244 
00245     string file;
00246 
00247     // could be only one main app, with no samples for the main image
00248     if (profile.files.empty()) {
00249         profile_dep_set const & dep = *(profile.deps.begin());
00250         list<profile_sample_files> const & files = dep.files;
00251         profile_sample_files const & sample_files = *(files.begin());
00252         if (!sample_files.sample_filename.empty())
00253             file = sample_files.sample_filename;
00254         else
00255             file = *sample_files.cg_files.begin();
00256     } else {
00257         profile_sample_files const & sample_files 
00258             = *(profile.files.begin());
00259         if (!sample_files.sample_filename.empty())
00260             file = sample_files.sample_filename;
00261         else
00262             file = *sample_files.cg_files.begin();
00263     }
00264 
00265     return read_header(file);
00266 }
00267 
00269 void merge_header(profile_sample_files const & files, opd_header & header)
00270 {
00271     if (!files.sample_filename.empty()) {
00272         opd_header const temp = read_header(files.sample_filename);
00273         header.ctr_um |=  temp.ctr_um;
00274     }
00275 
00276     list<string>::const_iterator it = files.cg_files.begin();
00277     list<string>::const_iterator const end = files.cg_files.end();
00278     for ( ; it != end; ++it) {
00279         opd_header const temp = read_header(*it);
00280         header.ctr_um |= temp.ctr_um;
00281     }
00282 }
00283 
00285 opd_header const get_header(profile_class const & pclass,
00286                             merge_option const & merge_by)
00287 {
00288     opd_header header = get_first_header(pclass);
00289 
00290     if (!merge_by.unitmask)
00291         return header;
00292 
00293     profile_set const & profile = *(pclass.profiles.begin());
00294 
00295     typedef list<profile_sample_files>::const_iterator citerator;
00296 
00297     citerator it = profile.files.begin();
00298     citerator const end = profile.files.end();
00299     for ( ; it != end; ++it)
00300         merge_header(*it, header);
00301 
00302     list<profile_dep_set>::const_iterator dep_it = profile.deps.begin();
00303     list<profile_dep_set>::const_iterator dep_end = profile.deps.end();
00304     for ( ; dep_it != dep_end; ++dep_it) {
00305         citerator it = dep_it->files.begin();
00306         citerator const end = dep_it->files.end();
00307         for ( ; it != end; ++it)
00308             merge_header(*it, header);
00309     }
00310 
00311     return header;
00312 }
00313 
00314 
00316 void name_classes(profile_classes & classes, merge_option const & merge_by)
00317 {
00318     opd_header header = get_header(classes.v[0], merge_by);
00319 
00320     classes.event = describe_header(header);
00321     classes.cpuinfo = describe_cpu(header);
00322 
00323     // If we're splitting on event anyway, clear out the
00324     // global event name
00325     if (classes.axis == AXIS_EVENT)
00326         classes.event.erase();
00327 
00328     vector<profile_class>::iterator it = classes.v.begin();
00329     vector<profile_class>::iterator const end = classes.v.end();
00330 
00331     for (; it != end; ++it) {
00332         it->name = axes[classes.axis].name + ":";
00333         switch (classes.axis) {
00334         case AXIS_EVENT:
00335             it->name = it->ptemplate.event
00336                 + ":" + it->ptemplate.count;
00337             header = get_header(*it, merge_by);
00338             it->longname = describe_header(header);
00339             break;
00340         case AXIS_TGID:
00341             it->name += it->ptemplate.tgid;
00342             it->longname = "Processes with a thread group ID of ";
00343             it->longname += it->ptemplate.tgid;
00344             break;
00345         case AXIS_TID:
00346             it->name += it->ptemplate.tid;
00347             it->longname = "Processes with a thread ID of ";
00348             it->longname += it->ptemplate.tid;
00349             break;
00350         case AXIS_CPU:
00351             it->name += it->ptemplate.cpu;
00352             it->longname = "Samples on CPU " + it->ptemplate.cpu;
00353             break;
00354         case AXIS_MAX:;
00355         }
00356     }
00357 }
00358 
00359 
00363 void identify_classes(profile_classes & classes,
00364                       merge_option const & merge_by)
00365 {
00366     profile_template & ptemplate = classes.v[0].ptemplate;
00367     bool changed[AXIS_MAX] = { false, };
00368 
00369     vector<profile_class>::iterator it = classes.v.begin();
00370     ++it;
00371     vector<profile_class>::iterator end = classes.v.end();
00372 
00373     // only one class, name it after the event
00374     if (it == end)
00375         changed[AXIS_EVENT] = true;
00376 
00377     for (; it != end; ++it) {
00378         if (it->ptemplate.event != ptemplate.event
00379             ||  it->ptemplate.count != ptemplate.count
00380             // unit mask are mergeable
00381             || (!merge_by.unitmask
00382             && it->ptemplate.unitmask != ptemplate.unitmask))
00383             changed[AXIS_EVENT] = true;
00384 
00385         // we need the merge checks here because each
00386         // template is filled in from the first non
00387         // matching profile, so just because they differ
00388         // doesn't mean it's the axis we care about
00389         if (!merge_by.tgid && it->ptemplate.tgid != ptemplate.tgid)
00390             changed[AXIS_TGID] = true;
00391 
00392         if (!merge_by.tid && it->ptemplate.tid != ptemplate.tid)
00393             changed[AXIS_TID] = true;
00394 
00395         if (!merge_by.cpu && it->ptemplate.cpu != ptemplate.cpu)
00396             changed[AXIS_CPU] = true;
00397     }
00398 
00399     classes.axis = AXIS_MAX;
00400 
00401     for (size_t i = 0; i < AXIS_MAX; ++i) {
00402         if (!changed[i])
00403             continue;
00404 
00405         if (!allow_axes(classes, axis_types(i)))
00406             report_error(classes, axis_types(i));
00407         classes.axis = axis_types(i);
00408         /* do this early for report_error */
00409         name_classes(classes, merge_by);
00410     }
00411 
00412     if (classes.axis == AXIS_MAX) {
00413         cerr << "Internal error - no equivalence class axis" << endl;
00414         abort();
00415     }
00416 }
00417 
00418 void identify_xml_classes(profile_classes & classes, merge_option const & merge_by)
00419 {
00420     opd_header header = get_header(classes.v[0], merge_by);
00421 
00422     vector<profile_class>::iterator it = classes.v.begin();
00423     vector<profile_class>::iterator end = classes.v.end();
00424 
00425     event_index_t event_num;
00426     event_index_t event_max = 0;
00427     event_array_t event_array;
00428     size_t nr_cpus = 0;
00429     bool has_nonzero_mask = false;
00430 
00431     ostringstream event_setup;
00432 
00433     // fill in XML identifying each event, and replace event name by event_num
00434     for (; it != end; ++it) {
00435         string mask = it->ptemplate.unitmask;
00436         if (mask.find_first_of("x123456789abcdefABCDEF") != string::npos)
00437             has_nonzero_mask = true;
00438         if (new_event_index(it->ptemplate.event, event_array, event_num)) {
00439             // replace it->ptemplate.event with the event_num string
00440             // this is the first time we've seen this event
00441             header = get_header(*it, merge_by);
00442             event_setup << describe_header(header);
00443             event_max = event_num;
00444         }
00445         if (it->ptemplate.cpu != "all") {
00446             size_t cpu = atoi(it->ptemplate.cpu.c_str());
00447             if (cpu > nr_cpus) nr_cpus = cpu;
00448         }
00449 
00450         ostringstream str;
00451         str << event_num;
00452         it->ptemplate.event = str.str();
00453     }
00454     xml_utils::set_nr_cpus(++nr_cpus);
00455     xml_utils::set_nr_events(event_max+1);
00456     if (has_nonzero_mask)
00457         xml_utils::set_has_nonzero_masks();
00458     classes.event = event_setup.str();
00459     classes.cpuinfo = describe_cpu(header);
00460 }
00461 
00463 profile_template const
00464 template_from_profile(parsed_filename const & parsed,
00465                       merge_option const & merge_by)
00466 {
00467     profile_template ptemplate;
00468 
00469     ptemplate.event = parsed.event;
00470     ptemplate.count = parsed.count;
00471 
00472     if (!merge_by.unitmask)
00473         ptemplate.unitmask = parsed.unitmask;
00474     if (!merge_by.tgid)
00475         ptemplate.tgid = parsed.tgid;
00476     if (!merge_by.tid)
00477         ptemplate.tid = parsed.tid;
00478     if (!merge_by.cpu)
00479         ptemplate.cpu = parsed.cpu;
00480     return ptemplate;
00481 }
00482 
00483 
00491 profile_class & find_class(set<profile_class> & classes,
00492                            parsed_filename const & parsed,
00493                            merge_option const & merge_by)
00494 {
00495     profile_class cls;
00496     cls.ptemplate = template_from_profile(parsed, merge_by);
00497 
00498     pair<set<profile_class>::iterator, bool> ret = classes.insert(cls);
00499 
00500     return const_cast<profile_class &>(*ret.first);
00501 }
00502 
00510 void sanitize_profile_sample_files(profile_sample_files const & sample_files,
00511     parsed_filename const & parsed)
00512 {
00513     // We can't allow to overwrite sample_filename.
00514     if (!sample_files.sample_filename.empty()) {
00515         ostringstream out;
00516         out << "sanitize_profile_sample_files(): sample file "
00517             << "parsed twice ?\nsample_filename:\n"
00518             << sample_files.sample_filename << endl
00519             << parsed << endl;
00520         throw op_fatal_error(out.str());
00521     }
00522 }
00523 
00524 
00528 void
00529 add_to_profile_sample_files(profile_sample_files & sample_files,
00530     parsed_filename const & parsed)
00531 {
00532     if (parsed.cg_image.empty()) {
00533         // We can't allow to overwrite sample_filename.
00534         sanitize_profile_sample_files(sample_files, parsed);
00535 
00536         sample_files.sample_filename = parsed.filename;
00537     } else {
00538         sample_files.cg_files.push_back(parsed.filename);
00539     }
00540 }
00541 
00542 
00547 profile_sample_files &
00548 find_profile_sample_files(list<profile_sample_files> & files,
00549               parsed_filename const & parsed,
00550               extra_images const & extra)
00551 {
00552     list<profile_sample_files>::iterator it;
00553     list<profile_sample_files>::iterator const end = files.end();
00554     for (it = files.begin(); it != end; ++it) {
00555         if (!it->sample_filename.empty()) {
00556             parsed_filename psample_filename =
00557               parse_filename(it->sample_filename, extra);
00558             if (psample_filename.lib_image == parsed.lib_image &&
00559                 psample_filename.image == parsed.image &&
00560                 psample_filename.profile_spec_equal(parsed))
00561                 return *it;
00562         }
00563 
00564         list<string>::const_iterator cit;
00565         list<string>::const_iterator const cend = it->cg_files.end();
00566         for (cit = it->cg_files.begin(); cit != cend; ++cit) {
00567             parsed_filename pcg_filename =
00568                 parse_filename(*cit, extra);
00569             if (pcg_filename.lib_image == parsed.lib_image &&
00570                 pcg_filename.image == parsed.image &&
00571                 pcg_filename.profile_spec_equal(parsed))
00572                 return *it;
00573         }
00574     }
00575 
00576     // not found, create a new one
00577     files.push_back(profile_sample_files());
00578     return files.back();
00579 }
00580 
00581 
00587 void
00588 add_to_profile_set(profile_set & set, parsed_filename const & parsed,
00589            bool merge_by_lib, extra_images const & extra)
00590 {
00591     if (parsed.image == parsed.lib_image && !merge_by_lib) {
00592         profile_sample_files & sample_files =
00593             find_profile_sample_files(set.files, parsed, extra);
00594         add_to_profile_sample_files(sample_files, parsed);
00595         return;
00596     }
00597 
00598     list<profile_dep_set>::iterator it = set.deps.begin();
00599     list<profile_dep_set>::iterator const end = set.deps.end();
00600 
00601     for (; it != end; ++it) {
00602         if (it->lib_image == parsed.lib_image && !merge_by_lib &&
00603                 parsed.jit_dumpfile_exists == false) {
00604             profile_sample_files & sample_files =
00605                 find_profile_sample_files(it->files, parsed,
00606                               extra);
00607             add_to_profile_sample_files(sample_files, parsed);
00608             return;
00609         }
00610     }
00611 
00612     profile_dep_set depset;
00613     depset.lib_image = parsed.lib_image;
00614     profile_sample_files & sample_files =
00615         find_profile_sample_files(depset.files, parsed, extra);
00616     add_to_profile_sample_files(sample_files, parsed);
00617     set.deps.push_back(depset);
00618 }
00619 
00620 
00626 void add_profile(profile_class & pclass, parsed_filename const & parsed,
00627          bool merge_by_lib, extra_images const & extra)
00628 {
00629     list<profile_set>::iterator it = pclass.profiles.begin();
00630     list<profile_set>::iterator const end = pclass.profiles.end();
00631 
00632     for (; it != end; ++it) {
00633         if (it->image == parsed.image) {
00634             add_to_profile_set(*it, parsed, merge_by_lib, extra);
00635             return;
00636         }
00637     }
00638 
00639     profile_set set;
00640     set.image = parsed.image;
00641     add_to_profile_set(set, parsed, merge_by_lib, extra);
00642     pclass.profiles.push_back(set);
00643 }
00644 
00645 }  // anon namespace
00646 
00647 
00648 profile_classes const
00649 arrange_profiles(list<string> const & files, merge_option const & merge_by,
00650          extra_images const & extra)
00651 {
00652     set<profile_class> temp_classes;
00653 
00654     list<string>::const_iterator it = files.begin();
00655     list<string>::const_iterator const end = files.end();
00656 
00657     for (; it != end; ++it) {
00658         parsed_filename parsed = parse_filename(*it, extra);
00659 
00660         if (parsed.lib_image.empty())
00661             parsed.lib_image = parsed.image;
00662 
00663         // This simplifies the add of the profile later,
00664         // if we're lib-merging, then the app_image cannot
00665         // matter. After this, any non-dependent has
00666         // image == lib_image
00667         if (merge_by.lib)
00668             parsed.image = parsed.lib_image;
00669 
00670         profile_class & pclass =
00671             find_class(temp_classes, parsed, merge_by);
00672         add_profile(pclass, parsed, merge_by.lib, extra);
00673     }
00674 
00675     profile_classes classes;
00676     copy(temp_classes.begin(), temp_classes.end(),
00677          back_inserter(classes.v));
00678 
00679     if (classes.v.empty())
00680         return classes;
00681 
00682     // sort by template for nicely ordered columns
00683     stable_sort(classes.v.begin(), classes.v.end());
00684 
00685     if (want_xml)
00686         identify_xml_classes(classes, merge_by);
00687     else
00688         identify_classes(classes, merge_by);
00689 
00690     classes.extra_found_images = extra;
00691 
00692     return classes;
00693 }
00694 
00695 
00696 ostream & operator<<(ostream & out, profile_sample_files const & sample_files)
00697 {
00698     out << "sample_filename: " << sample_files.sample_filename << endl;
00699     out << "callgraph filenames:\n";
00700     copy(sample_files.cg_files.begin(), sample_files.cg_files.end(),
00701          ostream_iterator<string>(out, "\n"));
00702     return out;
00703 }
00704 
00705 ostream & operator<<(ostream & out, profile_dep_set const & pdep_set)
00706 {
00707     out << "lib_image: " << pdep_set.lib_image << endl;
00708 
00709     list<profile_sample_files>::const_iterator it;
00710     list<profile_sample_files>::const_iterator const end =
00711         pdep_set.files.end();
00712     size_t i = 0;
00713     for (it = pdep_set.files.begin(); it != end; ++it)
00714         out << "profile_sample_files #" << i++ << ":\n" << *it;
00715 
00716     return out;
00717 }
00718 
00719 ostream & operator<<(ostream & out, profile_set const & pset)
00720 {
00721     out << "image: " << pset.image << endl;
00722 
00723     list<profile_sample_files>::const_iterator it;
00724     list<profile_sample_files>::const_iterator const end =
00725         pset.files.end();
00726     size_t i = 0;
00727     for (it = pset.files.begin(); it != end; ++it)
00728         out << "profile_sample_files #" << i++ << ":\n" << *it;
00729 
00730     list<profile_dep_set>::const_iterator cit;
00731     list<profile_dep_set>::const_iterator const cend = pset.deps.end();
00732     i = 0;
00733     for (cit = pset.deps.begin(); cit != cend; ++cit)
00734         out << "profile_dep_set #" << i++ << ":\n" << *cit;
00735 
00736     return out;
00737 }
00738 
00739 ostream & operator<<(ostream & out, profile_template const & ptemplate)
00740 {
00741     out << "event: " << ptemplate.event << endl
00742         << "count: " << ptemplate.count << endl
00743         << "unitmask: " << ptemplate.unitmask << endl
00744         << "tgid: " << ptemplate.tgid << endl
00745         << "tid: " << ptemplate.tid << endl
00746         << "cpu: " << ptemplate.cpu << endl;
00747     return out;
00748 }
00749 
00750 ostream & operator<<(ostream & out, profile_class const & pclass)
00751 {
00752     out << "name: " << pclass.name << endl
00753         << "longname: " << pclass.longname << endl
00754         << "ptemplate:\n" << pclass.ptemplate;
00755 
00756     size_t i = 0;
00757     list<profile_set>::const_iterator it;
00758     list<profile_set>::const_iterator const end = pclass.profiles.end();
00759     for (it = pclass.profiles.begin(); it != end; ++it)
00760         out << "profiles_set #" << i++ << ":\n" << *it;
00761 
00762     return out;
00763 }
00764 
00765 ostream & operator<<(ostream & out, profile_classes const & pclasses)
00766 {
00767     out << "event: " << pclasses.event << endl
00768         << "cpuinfo: " << pclasses.cpuinfo << endl;
00769 
00770     for (size_t i = 0; i < pclasses.v.size(); ++i)
00771         out << "class #" << i << ":\n" << pclasses.v[i];
00772 
00773     return out;
00774 }
00775 
00776 
00777 namespace {
00778 
00780 void add_to_group(image_group_set & group, string const & app_image,
00781                   list<profile_sample_files> const & files)
00782 {
00783     image_set set;
00784     set.app_image = app_image;
00785     set.files = files;
00786     group.push_back(set);
00787 }
00788 
00789 
00790 typedef map<string, inverted_profile> app_map_t;
00791 
00792 
00793 inverted_profile &
00794 get_iprofile(app_map_t & app_map, string const & image, size_t nr_classes)
00795 {
00796     app_map_t::iterator ait = app_map.find(image);
00797     if (ait != app_map.end())
00798         return ait->second;
00799 
00800     inverted_profile ip;
00801     ip.image = image;
00802     ip.groups.resize(nr_classes);
00803     app_map[image] = ip;
00804     return app_map[image];
00805 }
00806 
00807 
00809 void
00810 verify_and_fill(app_map_t & app_map, list<inverted_profile> & plist,
00811         extra_images const & extra)
00812 {
00813     app_map_t::iterator it = app_map.begin();
00814     app_map_t::iterator const end = app_map.end();
00815 
00816     for (; it != end; ++it) {
00817         plist.push_back(it->second);
00818         inverted_profile & ip = plist.back();
00819         extra.find_image_path(ip.image, ip.error, false);
00820     }
00821 }
00822 
00823 } // anon namespace
00824 
00825 
00826 list<inverted_profile> const
00827 invert_profiles(profile_classes const & classes)
00828 {
00829     app_map_t app_map;
00830 
00831     size_t nr_classes = classes.v.size();
00832 
00833     for (size_t i = 0; i < nr_classes; ++i) {
00834         list<profile_set>::const_iterator pit
00835             = classes.v[i].profiles.begin();
00836         list<profile_set>::const_iterator pend
00837             = classes.v[i].profiles.end();
00838 
00839         for (; pit != pend; ++pit) {
00840             // files can be empty if samples for a lib image
00841             // but none for the main image. Deal with it here
00842             // rather than later.
00843             if (pit->files.size()) {
00844                 inverted_profile & ip = get_iprofile(app_map,
00845                     pit->image, nr_classes);
00846                 add_to_group(ip.groups[i], pit->image, pit->files);
00847             }
00848 
00849             list<profile_dep_set>::const_iterator dit
00850                 = pit->deps.begin();
00851             list<profile_dep_set>::const_iterator const dend
00852                 = pit->deps.end();
00853 
00854             for (;  dit != dend; ++dit) {
00855                 inverted_profile & ip = get_iprofile(app_map,
00856                     dit->lib_image, nr_classes);
00857                 add_to_group(ip.groups[i], pit->image,
00858                              dit->files);
00859             }
00860         }
00861     }
00862 
00863     list<inverted_profile> inverted_list;
00864 
00865     verify_and_fill(app_map, inverted_list, classes.extra_found_images);
00866 
00867     return inverted_list;
00868 }

Generated on 8 Nov 2012 for Oprofile by  doxygen 1.6.1