HPCToolkit
main.cpp
Go to the documentation of this file.
1 // -*-Mode: C++;-*-
2 
3 // * BeginRiceCopyright *****************************************************
4 //
5 // $HeadURL$
6 // $Id$
7 //
8 // --------------------------------------------------------------------------
9 // Part of HPCToolkit (hpctoolkit.org)
10 //
11 // Information about sources of support for research and development of
12 // HPCToolkit is at 'hpctoolkit.org' and in 'README.Acknowledgments'.
13 // --------------------------------------------------------------------------
14 //
15 // Copyright ((c)) 2002-2019, Rice University
16 // All rights reserved.
17 //
18 // Redistribution and use in source and binary forms, with or without
19 // modification, are permitted provided that the following conditions are
20 // met:
21 //
22 // * Redistributions of source code must retain the above copyright
23 // notice, this list of conditions and the following disclaimer.
24 //
25 // * Redistributions in binary form must reproduce the above copyright
26 // notice, this list of conditions and the following disclaimer in the
27 // documentation and/or other materials provided with the distribution.
28 //
29 // * Neither the name of Rice University (RICE) nor the names of its
30 // contributors may be used to endorse or promote products derived from
31 // this software without specific prior written permission.
32 //
33 // This software is provided by RICE and contributors "as is" and any
34 // express or implied warranties, including, but not limited to, the
35 // implied warranties of merchantability and fitness for a particular
36 // purpose are disclaimed. In no event shall RICE or contributors be
37 // liable for any direct, indirect, incidental, special, exemplary, or
38 // consequential damages (including, but not limited to, procurement of
39 // substitute goods or services; loss of use, data, or profits; or
40 // business interruption) however caused and on any theory of liability,
41 // whether in contract, strict liability, or tort (including negligence
42 // or otherwise) arising in any way out of the use of this software, even
43 // if advised of the possibility of such damage.
44 //
45 // ******************************************************* EndRiceCopyright *
46 
47 //***************************************************************************
48 //
49 // File:
50 // $HeadURL$
51 //
52 // Purpose:
53 // [The purpose of this file]
54 //
55 // Description:
56 // [The set of functions, macros, etc. defined in the file]
57 //
58 //***************************************************************************
59 
60 //************************* System Include Files ****************************
61 
62 #include <iostream>
63 using std::cerr;
64 using std::cout;
65 using std::endl;
66 #include <fstream>
67 #include <new>
68 
69 #include <string>
70 using std::string;
71 
72 #include <cstring>
73 
74 //*************************** User Include Files ****************************
75 
76 #include "Args.hpp"
77 #include "ProfileReader.hpp"
78 #include "ProfileWriter.hpp"
79 #include "PCProfile.hpp"
80 #include "DerivedProfile.hpp"
81 
82 #include "DCPIProfile.hpp"
83 
84 #include <lib/binutils/LM.hpp>
85 
87 
88 //*************************** Forward Declarations ***************************
89 
90 typedef std::list<string> StringList;
91 typedef StringList::iterator StringListIt;
92 typedef StringList::const_iterator StringListCIt;
93 
94 int
95 real_main(int argc, char* argv[]);
96 
97 void
98 ListAvailPredefDCPIFilters(DCPIProfile* prof, bool longlist = false);
99 
101 GetDCPIFilters(DCPIProfile* prof, binutils::LM* lm,
102  const char* metricList, const char* excludeMList);
103 
104 //****************************************************************************
105 
106 int
107 main(int argc, char* argv[])
108 {
109  try {
110  return real_main(argc, argv);
111  }
112  catch (const Diagnostics::Exception& x) {
113  DIAG_EMsg(x.message());
114  exit(1);
115  }
116  catch (const std::bad_alloc& x) {
117  DIAG_EMsg("[std::bad_alloc] " << x.what());
118  exit(1);
119  }
120  catch (const std::exception& x) {
121  DIAG_EMsg("[std::exception] " << x.what());
122  exit(1);
123  }
124  catch (...) {
125  DIAG_EMsg("Unknown exception encountered!");
126  exit(2);
127  }
128 }
129 
130 
131 int
132 real_main(int argc, char* argv[])
133 {
134  Args args(argc, argv);
135 
136  // ------------------------------------------------------------
137  // Read 'pcprof', the raw profiling data file
138  // ------------------------------------------------------------
139  PCProfile* pcprof = NULL;
140  try {
141  pcprof = ProfileReader::ReadProfileFile(args.profFile.c_str() /*type*/);
142  if (!pcprof) { exit(1); }
143  }
144  catch (std::bad_alloc& x) {
145  cerr << "Error: Memory alloc failed while reading profile!\n";
146  exit(1);
147  }
148 
149  if (args.listAvailableMetrics > 0) {
150  // * Assume DCPI mode *
151  DCPIProfile* dcpiprof = dynamic_cast<DCPIProfile*>(pcprof);
153  return (0);
154  }
155 
156  // ------------------------------------------------------------
157  // Read executable
158  // ------------------------------------------------------------
159  binutils::LM* lm = NULL;
160  string lmNm = args.progFile;
161 
162  // Try to find lm from profile info if not given
163  if (lmNm.empty()) {
164  lmNm = pcprof->GetProfiledFile();
165 
166  std::ifstream ifile(lmNm.c_str(), std::ios::in);
167  if ( !ifile.is_open() || ifile.fail() ) {
168  cerr << "Error: Could not find associated binary '" << lmNm
169  << "'; please specify explicitly.\n";
170  exit(1);
171  }
172  }
173 
174  try {
175  lm = new binutils::LM();
176  lm->open(lmNm.c_str());
177  lm->read(binutils::LM::ReadFlg_ALL);
178  }
179  catch (...) {
180  DIAG_EMsg("Exception encountered while reading " << lmNm);
181  throw;
182  }
183 
184  lm->relocate(pcprof->GetTxtStart());
185 
186 
187  // ------------------------------------------------------------
188  // Construct some metrics, derived in some way from the raw
189  // profiling data, that we are interested in.
190  // ------------------------------------------------------------
191  // * Assume DCPI mode *
192  DerivedProfile* drvdprof = NULL;
193  PCProfileFilterList* filtList = NULL;
194  if (!args.outputRawMetrics) {
195  DCPIProfile* dcpiprof = dynamic_cast<DCPIProfile*>(pcprof);
196  filtList = GetDCPIFilters(dcpiprof, lm,
197  args.metricList.c_str(),
198  args.excludeMList.c_str());
199  if (!filtList) {
200  exit(1); // Error already printed
201  }
202  }
203 
204  drvdprof = new DerivedProfile(pcprof, filtList);
205 
206  if (filtList) { filtList->destroyContents(); }
207  delete filtList; // done with filters
208 
209  if (drvdprof->GetNumMetrics() == 0) {
210  cerr << "Error: Could not find any metrics to convert to PROFILE!\n";
211  exit(1);
212  }
213 
214  // ------------------------------------------------------------
215  // Translate the derived metrics to a PROFILE file
216  // ------------------------------------------------------------
217  // * Assume DCPI mode *
218  ProfileWriter::WriteProfile(cout, drvdprof, lm);
219 
220  delete lm;
221  delete pcprof;
222  delete drvdprof;
223  return (0);
224 }
225 
226 //****************************************************************************
227 
229 GetDCPIFilters(StringList* mlist, binutils::LM* lm);
230 
231 StringList*
232 GetAvailPredefDCPIFilterNms(DCPIProfile* prof, binutils::LM* lm);
233 
234 bool
236  const char* emsg = NULL);
237 
238 bool
241 
242 StringList*
243 ConvertColonListToStringList(const char* str);
244 
245 void
247 
248 
249 // ListAvailPredefDCPIFilters: Iterate through the DCPI predefined
250 // metric table, listing any metrics (filters) that are available for
251 // this profile.
252 void
254 {
255  // When longlist is false, a short listing is printed
256  // When longlist is true, a long listing is print (name and description)
257 
258  string out;
259  for (unsigned int i = 0; i < PredefinedDCPIMetricTable::GetSize(); ++i) {
261  if (IsPredefDCPIFilterAvail(prof, e)) {
262 
263  if (longlist) {
264  out += string(" ") + e->name + ": " + e->description + "\n";
265  } else {
266  if (!out.empty()) { out += ":"; }
267  out += e->name;
268  }
269 
270  }
271  }
272 
273  if (out.empty()) {
274  cout << "No derived metrics available for this DCPI profile.";
275  } else {
276  cout << "The following metrics are available for this DCPI profile:\n";
277  if (longlist) {
278  cout << out;
279  } else {
280  cout << " -M " << out << endl;
281  cout << "(This line may be edited and passed to xprof.)" << endl;
282  }
283  }
284 }
285 
286 
287 // GetDCPIFilters: Returns the list of DCPI filters determined by the
288 // colon-separated include list in 'metricList' and the colon-separated
289 // exclude list in 'excludeMList'. If 'metricList' is empty, a list of
290 // available metrics will automatically computed. If an error occurs
291 // during processing -- such as invalid metrics -- an error message is
292 // printed and NULL will be returned. User is responsible for memory
293 // deallocation.
295 GetDCPIFilters(DCPIProfile* prof, binutils::LM* lm,
296  const char* metricList, const char* excludeMList)
297 {
298  bool noError = true;
299  PCProfileFilterList* flist = NULL;
300 
301  // 1. Determine the initial list of metrics to compute. All metrics
302  // should be valid even if some will later be excluded. (We do not
303  // allow users to specify an unavailable metric here and then
304  // exclude it.)
305  StringList* mlist = NULL;
306  if (metricList[0] != '\0') {
307  mlist = ConvertColonListToStringList(metricList);
308  noError &= IsPredefDCPIFilterAvail(prof, mlist, "Error in -M:");
309  } else {
310  mlist = GetAvailPredefDCPIFilterNms(prof, lm);
311  }
312 
313  // 2. Remove excludes from this list. (All metrics in 'mlist' are valid.)
314  StringList* xlist = NULL;
315  if (excludeMList[0] != '\0') {
316  xlist = ConvertColonListToStringList(excludeMList);
317  noError &= IsPredefDCPIFilterAvail(prof, xlist, "Error in -X:");
318  RemoveFromList(mlist, xlist);
319  }
320 
321  // 3. Create the list of filters for the final metric list. (All should
322  // be avilable.)
323  if (noError) {
324  flist = GetDCPIFilters(mlist, lm);
325  }
326  delete mlist;
327  delete xlist;
328  return flist;
329 }
330 
331 
332 // GetDCPIFilters: Return a list of filters for the metrics in 'mlist'.
333 // User is responsible for memory deallocation of list and its contents.
334 // Note: assumes that every filter name in 'mlist' is available.
336 GetDCPIFilters(StringList* mlist, binutils::LM* lm)
337 {
339  for (StringListIt it = mlist->begin(); it != mlist->end(); ++it) {
340  const string& nm = *it;
341  flist->push_back(GetPredefinedDCPIFilter(nm.c_str(), lm));
342  }
343  return flist;
344 }
345 
346 // GetAvailPredefDCPIFilterNms: Return a list of all the filter names
347 // within the DCPI predefined metric table that are available for this
348 // profile.
349 StringList*
350 GetAvailPredefDCPIFilterNms(DCPIProfile* prof, binutils::LM* lm)
351 {
352  StringList* flist = new StringList;
353  for (unsigned int i = 0; i < PredefinedDCPIMetricTable::GetSize(); ++i) {
355  if (IsPredefDCPIFilterAvail(prof, e)) {
356  flist->push_back(string(e->name));
357  }
358  }
359  return flist;
360 }
361 
362 
363 // IsPredefDCPIFilterAvail: Given a list of filter names, determine if
364 // each one is available given this profile. If 'emsg' is non-NULL,
365 // an error message will be printed for each invalid filter name, with
366 // 'emsg' printed first on each error line.
367 bool
368 IsPredefDCPIFilterAvail(DCPIProfile* prof, StringList* flist, const char* emsg)
369 {
370  bool ret = true;
372  for (StringListIt it = flist->begin(); it != flist->end(); ++it) {
373  const string& nm = *it;
374 
375  e = PredefinedDCPIMetricTable::FindEntry(nm.c_str());
376  if ( !(e && IsPredefDCPIFilterAvail(prof, e)) ) {
377  ret = false;
378  if (emsg) {
379  cerr << emsg << " The DCPI filter '" << nm << "' is invalid for this profile.\n";
380  }
381  }
382  }
383  return ret;
384 }
385 
386 // IsPredefDCPIFilterAvail: Given the DCPIProfile and an entry in the
387 // DCPI predefined metric table, determine if the corresponding filter
388 // is available (meaningful) for this profile.
389 bool
391 {
392  DCPIProfile::PMMode pmmode = prof->GetPMMode();
393 
395 
396  // The filter may or may not be available (whether in ProfileMe
397  // mode or not): must check each metric
398  for (PCProfileMetricSetIterator it(*prof); it.IsValid(); ++it) {
399  PCProfileMetric* m = it.Current();
400  if (strcmp(e->availStr, m->GetName().c_str()) == 0) {
401  return true;
402  }
403  }
404  return false;
405 
406  } else {
407 
408  // The filter may be available in any ProfileMe mode or in only
409  // one mode.
410  bool pmavail = false;
412  if (pmmode == DCPIProfile::PM0) { pmavail |= true; }
413  }
415  if (pmmode == DCPIProfile::PM1) { pmavail |= true; }
416  }
418  if (pmmode == DCPIProfile::PM2) { pmavail |= true; }
419  }
421  if (pmmode == DCPIProfile::PM3) { pmavail |= true; }
422  }
423  return pmavail;
424  }
425 
426 }
427 
428 
429 // ConvertColonListToStringList: convert the colon-separated list of
430 // names to a StringList. Users are responsible for memory.
431 StringList*
433 {
434  StringList* l = new StringList;
435 
436  if (!str) { return l; }
437 
438  char* tok = strtok(const_cast<char*>(str), ":");
439  while (tok != NULL) {
440  l->push_back(string(tok));
441  tok = strtok((char*)NULL, ":");
442  }
443 
444  return l;
445 }
446 
447 
448 // RemoveFromList: Removes all items in l2 from l1.
449 void
451 {
452  for (StringListIt it2 = l2->begin(); it2 != l2->end(); ++it2) {
453  const string& nm2 = *it2;
454 
455  // Remove nm2 every time it occurs in l1
456  for (StringListIt it1 = l1->begin(); it1 != l1->end(); ) {
457  const string& nm1 = *it1;
458  if (nm1 == nm2) {
459  it1 = l1->erase(it1); // it1 now points at next element or end
460  } else {
461  ++it1;
462  }
463  }
464  }
465 }
Definition: Args.hpp:79
unsigned int GetNumMetrics() const
StringList::const_iterator StringListCIt
Definition: main.cpp:92
StringList * ConvertColonListToStringList(const char *str)
Definition: main.cpp:432
#define DIAG_EMsg(...)
Definition: diagnostics.h:251
static PCProfile * ReadProfileFile(const char *profFile)
std::list< string > StringList
Definition: main.cpp:90
PCProfileFilter * GetPredefinedDCPIFilter(const char *metric, binutils::LM *lm)
static Entry * FindEntry(const char *token)
StringList * GetAvailPredefDCPIFilterNms(DCPIProfile *prof, binutils::LM *lm)
Definition: main.cpp:350
std::string excludeMList
Definition: Args.hpp:105
std::string profFile
Definition: Args.hpp:110
unsigned int listAvailableMetrics
Definition: Args.hpp:103
static void WriteProfile(std::ostream &os, DerivedProfile *profData, binutils::LM *lm)
static Entry * Index(unsigned int i)
virtual std::string message() const
Definition: Exception.hpp:134
std::string metricList
Definition: Args.hpp:104
exit
Definition: names.cpp:1
bool outputRawMetrics
Definition: Args.hpp:106
bool IsPredefDCPIFilterAvail(DCPIProfile *prof, StringList *flist, const char *emsg=NULL)
Definition: main.cpp:368
PMMode GetPMMode() const
int main(int argc, char *argv[])
Definition: main.cpp:125
int real_main(int argc, char *argv[])
Definition: main.cpp:132
static unsigned int GetSize()
PCProfileFilterList * GetDCPIFilters(DCPIProfile *prof, binutils::LM *lm, const char *metricList, const char *excludeMList)
Definition: main.cpp:295
void ListAvailPredefDCPIFilters(DCPIProfile *prof, bool longlist=false)
Definition: main.cpp:253
#define NULL
Definition: ElfHelper.cpp:85
VMA GetTxtStart() const
Definition: PCProfile.hpp:244
StringList::iterator StringListIt
Definition: main.cpp:91
const std::string & GetProfiledFile() const
Definition: PCProfile.hpp:232
std::string progFile
Definition: Args.hpp:109
const std::string & GetName() const
void RemoveFromList(StringList *l1, StringList *l2)
Definition: main.cpp:450