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
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 }
00053
00054
00055
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
00064
00065
00066
00067
00068
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 }
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
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
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
00185
00186
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
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
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
00324
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
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
00381 || (!merge_by.unitmask
00382 && it->ptemplate.unitmask != ptemplate.unitmask))
00383 changed[AXIS_EVENT] = true;
00384
00385
00386
00387
00388
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
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
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
00440
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
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
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
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 }
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
00664
00665
00666
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
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 }
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
00841
00842
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 }