HPCToolkit
ProfileReader.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 // ProfileReader.C
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::endl;
65 using std::hex;
66 using std::dec;
67 
68 #include <fstream>
69 #include <sstream>
70 #include <list>
71 #include <vector>
72 #include <algorithm>
73 
74 #include <string>
75 using std::string;
76 
77 #include <cstdlib>
78 #include <cstring>
79 
80 //*************************** User Include Files ****************************
81 
82 #include "ProfileReader.hpp"
83 #include "PCProfile.hpp"
84 #include "DCPIProfile.hpp"
85 
86 #include <lib/isa/ISA.hpp>
87 #include <lib/isa/AlphaISA.hpp>
88 
89 #include <lib/support/IOUtil.hpp>
90 
91 //*************************** Forward Declarations ***************************
92 
94 {
95  // return true if m1 < m2; false otherwise
96  bool operator()(const PCProfileMetric* m1, const PCProfileMetric* m2) const
97  { return (strcmp(m1->GetName().c_str(), m2->GetName().c_str()) < 0); }
98 };
99 
100 static bool
102 
103 
104 static DCPIProfile::PMMode
105 DeterminePMMode(const char* pmcounter);
106 
107 inline DCPIProfile::PMMode
108 DeterminePMMode(const string& pmcounter)
109 { return DeterminePMMode(pmcounter.c_str()); }
110 
111 
112 static const char*
113 GetSecondSubstring(const char* str);
114 
115 inline const char*
116 GetSecondSubstring(const string& str)
117 { return GetSecondSubstring(str.c_str()); }
118 
119 //****************************************************************************
120 // public: ReadProfileFile:
121 //****************************************************************************
122 
123 // ReadProfileFile: Given the name of a profile file 'profFile',
124 // creates a 'PCProfile' from the raw profile data. If 'profFile' is
125 // NULL or the empty string, reads from cin.
126 //
127 // Note: Guarantees that every 'PCProfileMetric' in the 'PCProfile'
128 // will have identical return values for both 'GetTxtStart' and
129 // 'GetTxtSz'.
130 PCProfile*
131 ProfileReader::ReadProfileFile(const char* profFile /* FIXME: type */)
132 {
133  PCProfile* profData = NULL;
134  std::istream* is = NULL;
135  bool usingStdin = (!profFile || profFile[0] == '\0');
136 
137  // ------------------------------------------------------------
138  // Open an input stream and determine its type
139  // ------------------------------------------------------------
140  if (!usingStdin) {
141 
142  // Attempt to open as a file
143  std::ifstream* pFile = new std::ifstream(profFile);
144  is = pFile;
145  if ( !pFile->is_open() || pFile->fail()) {
146  cerr << "Error opening file `" << profFile << "'" << endl;
147  goto ReadProfileFile_CleanupAfterError;
148  }
149 
150  } else {
151  // Read from cin
152  is = &(std::cin);
153  }
154 
155  // Figure out type (text, binary?)
156 
157  // ------------------------------------------------------------
158  // Read the data
159  // ------------------------------------------------------------
160 
161  // depending on file type, choose the correct reader
162  profData = dynamic_cast<PCProfile*>(ReadProfileFile_DCPICat(*is));
163 
164  if (!profData) {
165  if (!usingStdin) {
166  cerr << "Error reading file `" << profFile << "'" << endl;
167  } else {
168  cerr << "Error reading from stdin" << endl;
169  }
170  }
171 
172  // ------------------------------------------------------------
173  // Cleanup
174  // ------------------------------------------------------------
175  ReadProfileFile_CleanupAfterError:
176  if (!usingStdin) {
177  delete is;
178  }
179 
180  return profData;
181 }
182 
183 
184 //****************************************************************************
185 // private: DEC/Alpha/OSF1
186 //****************************************************************************
187 
188 // 'ReadProfileFile_DCPICat' reads 'dcpicat' output.
191 {
192  string str;
193  const int bufSz = 128;
194  char buf[bufSz]; // holds single tokens guaranteed not to be too big
195 
196  ISA* isa = new AlphaISA(); // we are going to reference count this
197  DCPIProfile* profData = NULL;
198  std::stringstream hdr; // header info
199  string profiledFile; // name of profiled file
200  string profiledFilePath; // path to profiled file
201  VMA txtStart = 0; // starting address of text segment
202  VMA txtSz = 0; // byte-size of text section
203 
204  // ------------------------------------------------------------
205  // Read header
206  // ------------------------------------------------------------
207 
208  hdr << std::showbase;
209 
210  // 'name' - name of profiled binary
211  str = IOUtil::GetLine(is); hdr << str << "\n";
212  profiledFile = GetSecondSubstring(str); // value of 'name'
213 
214  // 'image' - date and id information for profiled binary
215  str = IOUtil::GetLine(is); hdr << str << "\n";
216 
217  // 'label' (optional) - label for this profile file
218  if (is.peek() == 'l') {
219  str = IOUtil::GetLine(is); hdr << str << "\n";
220  }
221 
222  // 'path' - path for the profiled binary
223  // note: while the 'dcpicat' man-page does not indicate this,
224  // multiple 'path' entries are sometimes given.
225  while ( (!is.eof() && !is.fail()) && is.peek() == 'p' ) {
226  str = IOUtil::GetLine(is); hdr << str << "\n";
227  if (profiledFilePath.empty()) {
228  profiledFilePath = GetSecondSubstring(str); // value of 'path'
229  }
230  }
231 
232  // 'epoch' - date the profile was made
233  str = IOUtil::GetLine(is); hdr << str << "\n";
234 
235  // 'platform' - name of machine on which the profile was made
236  str = IOUtil::GetLine(is); hdr << str << "\n";
237 
238  // 'text_start' - starting address of text section of profiled binary (hex)
239  str = IOUtil::Get(is, '0'); hdr << str; // read until 0x
240  IOUtil::Skip(is, "0x"); // eat up '0x' prefix
241  is >> hex >> txtStart >> dec >> std::ws; // value of 'text_start'
242  hdr << hex << txtStart << dec << "\n";
243 
244  // 'text_size' - byte-size of the text section (hex)
245  str = IOUtil::Get(is, '0'); hdr << str; // read until 0x
246  IOUtil::Skip(is, "0x"); // eat up '0x' prefix
247  is >> hex >> txtSz >> dec >> std::ws; // value of 'text_size'
248  hdr << hex << txtSz << dec << "\n";
249 
250  if (is.eof() || is.fail()) { return NULL; /* error */ }
251 
252  // 'event' - one line for each event type in the profile
253  // Format: 'event W x:X:Y:Z'
254  // (The following adapted from dcpicat man page.)
255  // 'W' - sum of this event's count for all pc values recorded in profile
256  // 'x' - (only ProfileMe) profileme sample set (attriute and trap bits)
257  // 'X' - event name
258  // (or for ProfileMe) the counter name appended to the sample set
259  // 'Y' - sampling period used to sample this event (one such event
260  // occurrance is recorded every Y occurrances of the event.)
261  // 'Z' - 10000 times the fraction of the time the event was being
262  // monitored. (When multiple events are being multiplexed onto
263  // the same hardware counter, "Z" will be less than 10000.
264  //
265  // see 'dcpiprofileme' and 'dcpicat' man pages.
266 
267  // Create 'PCProfileMetric' from 'event' and collect them all into a queue
268  PCProfileMetricList mlist;
269  DCPIProfileMetric* curMetric;
271 
272  string X;
273  PCProfileDatum W, Y, Z;
274  bool invalidMetric = false;
275  unsigned int metricCount = 0;
276 
277  while ( (!is.eof() && !is.fail()) && is.peek() == 'e' ) {
278 
279  is >> buf; // read 'event' token (above: line begins with 'e')
280  is >> W >> std::ws; // read 'W' (total count)
281 
282  X = IOUtil::GetLine(is, ':'); // read 'x' or 'X' (event name)
283  if ( !isdigit(is.peek()) ) { // read 'X' (for ProfileMe)
284  string pmcounter = IOUtil::GetLine(is, ':');
285  pmmode = DeterminePMMode(pmcounter);
286  if (pmmode == DCPIProfile::PM_NONE) { invalidMetric = true; }
287  X += ":" + pmcounter;
288  }
289 
290  is >> Y; IOUtil::Skip(is, ":"); // read 'Y' (sampling period) and ':'
291  is >> Z >> std::ws; // read 'Z' (sampling time)
292 
293  curMetric = new DCPIProfileMetric(isa, X);
294  curMetric->SetTxtStart(txtStart);
295  curMetric->SetTxtSz(txtSz);
296  curMetric->SetTotalCount(W);
297  curMetric->SetName(X);
298  curMetric->SetPeriod(Y);
299  if (! curMetric->GetDCPIDesc().IsValid()) {
300  invalidMetric = true;
301  }
302 
303  mlist.push_back(curMetric);
304  metricCount++;
305  }
306 
307  // Create 'PCProfile' object and add all events
308  profData = new DCPIProfile(isa, metricCount);
309  isa->detach(); // Remove our reference
310  profData->SetHdrInfo( (hdr.str()).c_str() );
311  if (!profiledFilePath.empty()) {
312  profData->SetProfiledFile(profiledFilePath);
313  }
314  else {
315  profData->SetProfiledFile(profiledFile);
316  }
317  profData->SetPMMode(pmmode);
318 
319  while (!mlist.empty()) {
320  PCProfileMetric* m = mlist.front();
321  mlist.pop_front();
322  profData->AddMetric(m);
323  }
324 
325  if (invalidMetric || is.eof() || is.fail()) {
326  goto DCPICat_CleanupAfterError;
327  }
328 
329  // Check for duplicate 'event' names. 'event' names should be
330  // unique, but we have seen at least one instance where it seems
331  // duplicates were generated...
332  MetricNamesAreUnique(*profData); // Print warning if necessary
333 
334  // ------------------------------------------------------------
335  // Read sampling information
336  // ------------------------------------------------------------
337 
338  // There are 1 PC-column + n count-columns where n is the 'event'
339  // number; the columns are in the same order as the 'event' listing.
340  // PC's are in increasing address order. Skipped PC's have '0' for
341  // all counts. Because we are dealing with a non-VLIW architecture,
342  // the 'opIndex' argument to 'AddPC(...)' and 'Insert(...)' is always 0.
343 
344  // Note: add a dummy block to prevent compiler warnings/errors
345  // about the above 'goto' crossing the initialization of 'pcCount'
346  {
347  unsigned long pcCount = 0; // number of PC entries
348  PCProfileDatum profileDatum;
349  VMA PC;
350  is >> std::ws;
351  while ( (!is.eof() && !is.fail()) ) {
352  IOUtil::Skip(is, "0x"); // eat up '0x' prefix
353  is >> hex >> PC >> dec; // read 'PC' value, non VLIW instruction
354 
355  profData->AddPC(PC, 0); // there is some non-zero data at PC
356  for (unsigned long i = 0; i < metricCount; i++) {
357  is >> profileDatum;
358  const PCProfileMetric* m = profData->GetMetric(i);
359  const_cast<PCProfileMetric*>(m)->Insert(PC, 0, profileDatum);
360  }
361 
362  is >> std::ws;
363  pcCount++;
364  }
365  }
366 
367  if (is.fail()) { goto DCPICat_CleanupAfterError; }
368 
369  // ------------------------------------------------------------
370  // Done!
371  // ------------------------------------------------------------
372  return profData;
373 
374  DCPICat_CleanupAfterError:
375  delete profData;
376  return NULL;
377 }
378 
379 // Check to see if there are duplicates in 'mlist' while preserving order.
380 static bool
382 {
383  bool STATUS = true;
384 
385  if (mset.GetSz() > 1) {
386  // Collect all metrics (pointers) into a temporary vector and sort it
387  PCProfileMetricVec mvec(mset.GetSz());
388 
389  PCProfileMetricSetIterator setIt(mset);
390  for (unsigned int i = 0; setIt.IsValid(); ++setIt, ++i) {
391  mvec[i] = setIt.Current();
392  }
393 
394  std::sort(mvec.begin(), mvec.end(), lt_PCProfileMetric()); // ascending
395 
396  // Check for duplicates. 'mvec.size' is guaranteed to be >= 2
397  PCProfileMetric* cur1, *cur2 = NULL;
398  PCProfileMetricVecIt it = mvec.begin();
399  do {
400  cur1 = *it;
401  cur2 = *(++it); // increment
402  if (cur1->GetName() == cur2->GetName()) {
403  STATUS = false;
404  cerr << "Warning: Duplicate metric names exist: '"
405  << cur1->GetName() << "'." << endl;
406  }
407  } while (it+1 != mvec.end());
408 
409  // Remove all metric pointers from 'mvec' to ensure they are not deleted
410  for (it = mvec.begin(); it != mvec.end(); ++it) { *it = NULL; }
411  }
412 
413  return STATUS;
414 }
415 
416 // Given a ProfileMe counter name, determine which ProfileMe mode was used
417 static DCPIProfile::PMMode
418 DeterminePMMode(const char* pmcounter)
419 {
420  if (strncmp("m0", pmcounter, 2) == 0) {
421  return DCPIProfile::PM0;
422  } else if (strncmp("m1", pmcounter, 2) == 0) {
423  return DCPIProfile::PM1;
424  } else if (strncmp("m2", pmcounter, 2) == 0) {
425  return DCPIProfile::PM2;
426  } else if (strncmp("m3", pmcounter, 2) == 0) {
427  return DCPIProfile::PM3;
428  }
429  return DCPIProfile::PM_NONE;
430 }
431 
432 // GetSecondString: Given a string composed of substrings separated by
433 // whitespace, return a pointer to the beginning of the second
434 // substring. Ignores any whitespace at the beginning of the first
435 // substring. E.g.
436 // name hydro
437 // text_start 0x000120000000
438 static const char*
439 GetSecondSubstring(const char* str)
440 {
441  if (!str) { return NULL; }
442 
443  const char* ptr = str;
444 
445  // ignore first bit of whitespace
446  while (*ptr != '\0' && isspace(*ptr)) { ptr++; }
447 
448  // ignore first substring
449  while (*ptr != '\0' && !isspace(*ptr)) { ptr++; }
450 
451  // ignore second bit of whitespace
452  while (*ptr != '\0' && isspace(*ptr)) { ptr++; }
453 
454  return ptr; // beginning of second substring
455 }
456 
void detach()
Definition: ISA.hpp:388
bfd_vma VMA
Definition: ISATypes.hpp:79
std::list< PCProfileMetric * > PCProfileMetricList
Definition: PCProfile.hpp:81
void SetPeriod(ulong p)
void SetTxtSz(VMA a)
static DCPIProfile * ReadProfileFile_DCPICat(std::istream &pFile)
static PCProfile * ReadProfileFile(const char *profFile)
unsigned int GetSz() const
Definition: PCProfile.hpp:128
Definition: fmt.c:108
PCProfileMetricVec::iterator PCProfileMetricVecIt
Definition: PCProfile.hpp:86
void SetHdrInfo(const char *s)
Definition: PCProfile.hpp:238
bool operator()(const PCProfileMetric *m1, const PCProfileMetric *m2) const
void SetTotalCount(PCProfileDatum d)
bool Skip(std::istream &is, const char *s)
Definition: IOUtil.cpp:210
static char buf[32]
Definition: StrUtil.cpp:240
void SetName(const char *s)
void AddMetric(const PCProfileMetric *m)
Definition: PCProfile.hpp:250
Definition: ISA.hpp:106
std::vector< PCProfileMetric * > PCProfileMetricVec
Definition: PCProfile.hpp:85
std::string GetLine(std::istream &is, char end)
Definition: IOUtil.cpp:201
ulong PCProfileDatum
std::string Get(std::istream &is, char end)
Definition: IOUtil.cpp:185
void SetPMMode(PMMode x)
bool IsValid() const
static bool MetricNamesAreUnique(PCProfileMetricSet &mset)
#define NULL
Definition: ElfHelper.cpp:85
const DCPIMetricDesc & GetDCPIDesc() const
static const char * GetSecondSubstring(const char *str)
static DCPIProfile::PMMode DeterminePMMode(const char *pmcounter)
const PCProfileMetric * GetMetric(unsigned int i) const
Definition: PCProfile.hpp:248
void AddPC(VMA pc, ushort opIndex)
Definition: PCProfile.cpp:153
void SetTxtStart(VMA a)
const std::string & GetName() const
void SetProfiledFile(const char *s)
Definition: PCProfile.hpp:235