HPCToolkit
Struct-Output.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 // This file writes an hpcstruct file directly from the internal
48 // TreeNode format (Struct-Inline.hpp) to an output stream without
49 // using the Prof::Struct objects (prof/Struct-Tree.hpp).
50 //
51 // Notes:
52 // 1. All output to the hpcstruct file should come from this file.
53 //
54 // 2. Opening the file and creating the ostream is handled in
55 // tool/hpcstruct/main.c and lib/support/IOUtil.hpp.
56 //
57 // 3. We allow ostream = NULL to mean that we don't want output.
58 
59 // FIXME and TODO:
60 //
61 // 5. Add full vma ranges for <P> proc tags.
62 // ---> is this needed ?
63 //
64 // 14. Deal with alien ln fields.
65 // ---> is this needed ?
66 
67 //***************************************************************************
68 
69 #include <limits.h>
70 
71 #include <list>
72 #include <map>
73 #include <ostream>
74 #include <string>
75 
77 #include <lib/support/FileUtil.hpp>
79 #include <lib/support/dictionary.h>
80 
81 #include <lib/xml/xml.hpp>
82 
83 #include "Struct-Inline.hpp"
84 #include "Struct-Output.hpp"
85 #include "Struct-Skel.hpp"
86 
87 #define INDENT " "
88 #define INIT_LM_INDEX 2
89 
90 using namespace Inline;
91 using namespace std;
92 
93 static long next_index;
94 static long gaps_line;
95 
96 static const char * hpcstruct_xml_head =
98  ;
99 
100 //----------------------------------------------------------------------
101 
102 // Helpers to generate fields inside tags. The macros are designed to
103 // fit within << operators.
104 
105 // this generates pre-order
106 #define INDEX \
107  " i=\"" << next_index++ << "\""
108 
109 #define NUMBER(label, num) \
110  " " << label << "=\"" << num << "\""
111 
112 #define STRING(label, str) \
113  " " << label << "=\"" << xml::EscapeStr(str) << "\""
114 
115 #define VRANGE(vma, len) \
116  " v=\"{[0x" << hex << vma << "-0x" << vma + len << dec << ")}\""
117 
118 static void
119 doIndent(ostream * os, int depth)
120 {
121  for (int n = 1; n <= depth; n++) {
122  *os << INDENT;
123  }
124 }
125 
126 //----------------------------------------------------------------------
127 
128 namespace BAnal {
129 namespace Output {
130 
131 typedef map <long, TreeNode *> AlienMap;
132 typedef map <long, VMAIntervalSet *> LineNumberMap;
133 
134 class ScopeInfo {
135 public:
138  long line_num;
139 
140  ScopeInfo(long file, long base, long line = 0)
141  {
142  file_index = file;
143  base_index = base;
144  line_num = line;
145  }
146 };
147 
148 static void
149 doGaps(ostream *, ostream *, string, FileInfo *, GroupInfo *, ProcInfo *);
150 
151 static void
152 doTreeNode(ostream *, int, TreeNode *, ScopeInfo, HPC::StringTable &);
153 
154 static void
155 doStmtList(ostream *, int, TreeNode *);
156 
157 static void
158 doLoopList(ostream *, int, TreeNode *, HPC::StringTable &);
159 
160 static void
161 locateTree(TreeNode *, ScopeInfo &, HPC::StringTable &, bool = false);
162 
163 //----------------------------------------------------------------------
164 
165 // DOCTYPE header and <HPCToolkitStructure> tag.
166 void
167 printStructFileBegin(ostream * os, ostream * gaps, string filenm)
168 {
169  if (os == NULL) {
170  return;
171  }
172 
173  *os << "<?xml version=\"1.0\"?>\n"
174  << "<!DOCTYPE HPCToolkitStructure [\n"
176  << "]>\n"
177  << "<HPCToolkitStructure i=\"0\" version=\"4.7\" n=\"\">\n";
178 
179  if (gaps != NULL) {
180  *gaps << "This file describes the unclaimed vma ranges (gaps) in the control\n"
181  << "flow graph for the following file. This is mostly for debugging and\n"
182  << "improving ParseAPI.\n\n"
183  << filenm << "\n";
184  gaps_line = 5;
185  }
186 }
187 
188 // Closing tag.
189 void
190 printStructFileEnd(ostream * os, ostream * gaps)
191 {
192  if (os == NULL) {
193  return;
194  }
195 
196  *os << "</HPCToolkitStructure>\n";
197  os->flush();
198 
199  if (gaps != NULL) {
200  gaps->flush();
201  }
202 }
203 
204 //----------------------------------------------------------------------
205 
206 // Begin <LM> load module tag.
207 void
208 printLoadModuleBegin(ostream * os, string lmName)
209 {
210  if (os == NULL) {
211  return;
212  }
213 
215 
216  *os << "<LM"
217  << INDEX
218  << STRING("n", lmName)
219  << " v=\"{}\">\n";
220 }
221 
222 // Closing </LM> tag.
223 void
224 printLoadModuleEnd(ostream * os)
225 {
226  if (os == NULL) {
227  return;
228  }
229 
230  *os << "</LM>\n";
231 }
232 
233 //----------------------------------------------------------------------
234 
235 // Begin <F> file tag.
236 void
237 printFileBegin(ostream * os, FileInfo * finfo)
238 {
239  if (os == NULL || finfo == NULL) {
240  return;
241  }
242 
243  doIndent(os, 1);
244  *os << "<F"
245  << INDEX
246  << STRING("n", finfo->fileName)
247  << ">\n";
248 }
249 
250 // Closing </F> tag.
251 void
252 printFileEnd(ostream * os, FileInfo * finfo)
253 {
254  if (os == NULL || finfo == NULL) {
255  return;
256  }
257 
258  doIndent(os, 1);
259  *os << "</F>\n";
260 }
261 
262 //----------------------------------------------------------------------
263 void
264 printVariable(ostream * os, FileInfo * finfo, VariableInfo vinfo)
265 {
266  doIndent(os, 2);
267  *os << "<V"
268  << INDEX
269  << STRING("n", vinfo.prettyName)
270  << VRANGE(vinfo.entry_vma, vinfo.num_bytes)
271  << "/>\n";
272 }
273 
274 
275 //----------------------------------------------------------------------
276 
277 // Entry point for <P> proc tag and its subtree.
278 void
279 printProc(ostream * os, ostream * gaps, string gaps_file,
280  FileInfo * finfo, GroupInfo * ginfo, ProcInfo * pinfo,
281  HPC::StringTable & strTab)
282 {
283  if (os == NULL || finfo == NULL || ginfo == NULL
284  || pinfo == NULL || pinfo->root == NULL) {
285  return;
286  }
287 
288  TreeNode * root = pinfo->root;
289  long file_index = strTab.str2index(finfo->fileName);
290  long base_index = strTab.str2index(FileUtil::basename(finfo->fileName.c_str()));
291  ScopeInfo scope(file_index, base_index, pinfo->line_num);
292 
293  doIndent(os, 2);
294  *os << "<P"
295  << INDEX
296  << STRING("n", pinfo->prettyName);
297 
298  if (pinfo->linkName != pinfo->prettyName) {
299  *os << STRING("ln", pinfo->linkName);
300  }
301  if (pinfo->symbol_index != 0) {
302  *os << NUMBER("s", pinfo->symbol_index);
303  }
304  *os << NUMBER("l", pinfo->line_num)
305  << VRANGE(pinfo->entry_vma, 1)
306  << ">\n";
307 
308  // write the gaps to the first proc (low vma) of the group. this
309  // only applies to full gaps.
310  if (gaps != NULL && (! ginfo->alt_file) && pinfo == ginfo->procMap.begin()->second) {
311  doGaps(os, gaps, gaps_file, finfo, ginfo, pinfo);
312  }
313 
314  doTreeNode(os, 3, root, scope, strTab);
315 
316  doIndent(os, 2);
317  *os << "</P>\n";
318 }
319 
320 //----------------------------------------------------------------------
321 
322 // Write the unclaimed vma ranges (parseapi gaps) for one Symtab
323 // function to the .hpcstruct and .hpcstruct.gaps files. This only
324 // applies to the group leader.
325 //
326 // This is the full version -- each gap has a separate <S> stmt linked
327 // to the .gaps file, all within a alien scope. The basic version is
328 // folded into the inline tree in Struct.cpp.
329 //
330 static void
331 doGaps(ostream * os, ostream * gaps, string gaps_file,
332  FileInfo * finfo, GroupInfo * ginfo, ProcInfo * pinfo)
333 {
334  if (gaps == NULL || ginfo->gapSet.empty()) {
335  return;
336  }
337 
338  *gaps << "\nfunc: " << pinfo->prettyName << "\n"
339  << "link: " << pinfo->linkName << "\n"
340  << "file: " << finfo->fileName << " line: " << pinfo->line_num << "\n"
341  << "0x" << hex << ginfo->start << "--0x" << ginfo->end << dec << "\n\n";
342  gaps_line += 6;
343 
344  doIndent(os, 3);
345  *os << "<A"
346  << INDEX
347  << NUMBER("l", pinfo->line_num)
348  << STRING("f", finfo->fileName)
349  << STRING("n", "")
350  << " v=\"{}\""
351  << ">\n";
352 
353  doIndent(os, 4);
354  *os << "<A"
355  << INDEX
356  << NUMBER("l", gaps_line - 4)
357  << STRING("f", gaps_file)
358  << STRING("n", "unclaimed region in: " + pinfo->prettyName)
359  << " v=\"{}\""
360  << ">\n";
361 
362  for (auto git = ginfo->gapSet.begin(); git != ginfo->gapSet.end(); ++git) {
363  long start = git->beg();
364  long end = git->end();
365  long len = end - start;
366 
367  *gaps << "gap: 0x" << hex << start << "--0x" << end
368  << dec << " (" << len << ")\n";
369  gaps_line++;
370 
371  doIndent(os, 5);
372  *os << "<S"
373  << INDEX
374  << NUMBER("l", gaps_line)
375  << VRANGE(start, len)
376  << "/>\n";
377  }
378 
379  doIndent(os, 4);
380  *os << "</A>\n";
381 
382  doIndent(os, 3);
383  *os << "</A>\n";
384 }
385 
386 //----------------------------------------------------------------------
387 
388 // Print the inline tree at 'root' and its statements, loops, inline
389 // subtrees and guard aliens.
390 //
391 // Note: 'scope' is the enclosing file scope such that stmts and loops
392 // that don't match this scope require a guard alien. This includes
393 // stmts with an earlier line number (hpcprof reacts badly to this
394 // inside a proc scope).
395 //
396 static void
397 doTreeNode(ostream * os, int depth, TreeNode * root, ScopeInfo scope,
398  HPC::StringTable & strTab)
399 {
400  if (root == NULL) {
401  return;
402  }
403 
404  // partition the stmts and loops into separate trees by file (base)
405  // name. the ones that don't match the enclosing scope require a
406  // guard alien. this doesn't apply to inline subtrees.
407  //
408  // localNode contains the stmts and loops without a guard alien.
409  //
410  AlienMap alienMap;
411  TreeNode localNode;
412 
413  // divide stmts by file name
414  for (auto sit = root->stmtMap.begin(); sit != root->stmtMap.end(); ++sit) {
415  StmtInfo * sinfo = sit->second;
416  VMA vma = sinfo->vma;
417  TreeNode * node;
418 
419  // use guard alien if files don't match or if earlier line number
420  // in same file (but must be known). stmts with unknown file/line
421  // do not need a guard alien.
422  if (sinfo->line_num > 0
423  && (sinfo->base_index != scope.base_index || sinfo->line_num < scope.line_num))
424  {
425  auto ait = alienMap.find(sinfo->base_index);
426  if (ait != alienMap.end()) {
427  node = ait->second;
428  }
429  else {
430  node = new TreeNode(sinfo->file_index);
431  alienMap[sinfo->base_index] = node;
432  }
433  }
434  else {
435  // not a guard alien
436  node = &localNode;
437  }
438 
439  node->stmtMap[vma] = sinfo;
440  }
441 
442  // divide loops by file name
443  for (auto lit = root->loopList.begin(); lit != root->loopList.end(); ++lit) {
444  LoopInfo * linfo = *lit;
445  TreeNode * node;
446 
447  // use guard alien if files don't match or if earlier line number
448  // in same file (but must be known). loops with unknown file/line
449  // do not need a guard alien.
450  if (linfo->line_num > 0
451  && (linfo->base_index != scope.base_index || linfo->line_num < scope.line_num))
452  {
453  auto ait = alienMap.find(linfo->base_index);
454  if (ait != alienMap.end()) {
455  node = ait->second;
456  }
457  else {
458  node = new TreeNode(linfo->file_index);
459  alienMap[linfo->base_index] = node;
460  }
461  }
462  else {
463  // not a guard alien
464  node = &localNode;
465  }
466 
467  node->loopList.push_back(linfo);
468  }
469 
470  // first, print the stmts with no alien
471  doStmtList(os, depth, &localNode);
472 
473  // second, print the stmts and loops that do need a guard alien and
474  // delete the remaining tree nodes.
475  for (auto nit = alienMap.begin(); nit != alienMap.end(); ++nit) {
476  TreeNode * node = nit->second;
477  long file_index = node->file_index;
478  long base_index = nit->first;
479  ScopeInfo alien_scope(file_index, base_index);
480 
481  locateTree(node, alien_scope, strTab, true);
482 
483  // guard alien
484  doIndent(os, depth);
485  *os << "<A"
486  << INDEX
487  << NUMBER("l", alien_scope.line_num)
488  << STRING("f", strTab.index2str(file_index))
489  << STRING("n", GUARD_NAME)
490  << " v=\"{}\""
491  << ">\n";
492 
493  doStmtList(os, depth + 1, node);
494  doLoopList(os, depth + 1, node, strTab);
495 
496  doIndent(os, depth);
497  *os << "</A>\n";
498 
499  node->clear();
500  delete node;
501  }
502  alienMap.clear();
503 
504  // third, print the loops with no alien
505  doLoopList(os, depth, &localNode, strTab);
506  localNode.clear();
507 
508  // inline call sites, use double alien
509  for (auto nit = root->nodeMap.begin(); nit != root->nodeMap.end(); ++nit) {
510  FLPIndex flp = nit->first;
511  TreeNode * subtree = nit->second;
512  string callname = strTab.index2str(flp.pretty_index);
513  ScopeInfo subscope(0, 0);
514 
515  locateTree(subtree, subscope, strTab);
516 
517  // outer, caller alien. use file and line from flp call site, but
518  // empty proc name.
519  doIndent(os, depth);
520  *os << "<A"
521  << INDEX
522  << NUMBER("l", flp.line_num)
523  << STRING("f", strTab.index2str(flp.file_index))
524  << STRING("n", "")
525  << " v=\"{}\""
526  << ">\n";
527 
528  // inner, callee alien. use proc name from flp call site, but
529  // file and line from subtree.
530  doIndent(os, depth + 1);
531  *os << "<A"
532  << INDEX
533  << NUMBER("l", subscope.line_num)
534  << STRING("f", strTab.index2str(subscope.file_index))
535  << STRING("n", callname)
536  << " v=\"{}\""
537  << ">\n";
538 
539  doTreeNode(os, depth + 2, subtree, subscope, strTab);
540 
541  doIndent(os, depth + 1);
542  *os << "</A>\n";
543 
544  doIndent(os, depth);
545  *os << "</A>\n";
546  }
547 }
548 
549 //----------------------------------------------------------------------
550 
551 // Print the terminal statements at 'node' and compact multiple vma
552 // ranges with the same line number to a single stmt. Any guard
553 // alien, if needed, has already been printed.
554 //
555 static void
556 doStmtList(ostream * os, int depth, TreeNode * node)
557 {
558  LineNumberMap lineMap;
559 
560  // merge stmts with the same line number into a single vma set
561  for (auto sit = node->stmtMap.begin(); sit != node->stmtMap.end(); ++sit) {
562  StmtInfo * sinfo = sit->second;
563  VMAIntervalSet * vset = NULL;
564 
565  auto mit = lineMap.find(sinfo->line_num);
566  if (mit != lineMap.end()) {
567  vset = mit->second;
568  }
569  else {
570  vset = new VMAIntervalSet;
571  lineMap[sinfo->line_num] = vset;
572  }
573  vset->insert(sinfo->vma, sinfo->vma + sinfo->len);
574  }
575 
576  // print each vma set as a single <S> stmt
577  for (auto mit = lineMap.begin(); mit != lineMap.end(); ++mit) {
578  long line = mit->first;
579  VMAIntervalSet * vset = mit->second;
580 
581  doIndent(os, depth);
582  *os << "<S"
583  << INDEX
584  << NUMBER("l", line)
585  << " v=\"" << vset->toString() << "\""
586  << "/>\n";
587 
588  delete vset;
589  }
590  lineMap.clear();
591 }
592 
593 // Print the loops at 'node' and their subtrees. Any guard alien, if
594 // needed, has already been printed.
595 //
596 static void
597 doLoopList(ostream * os, int depth, TreeNode * node, HPC::StringTable & strTab)
598 {
599  for (auto lit = node->loopList.begin(); lit != node->loopList.end(); ++lit) {
600  LoopInfo * linfo = *lit;
601  ScopeInfo scope(linfo->file_index, linfo->base_index);
602 
603  doIndent(os, depth);
604  *os << "<L"
605  << INDEX
606  << NUMBER("l", linfo->line_num)
607  << STRING("f", strTab.index2str(linfo->file_index))
608  << VRANGE(linfo->entry_vma, 1)
609  << ">\n";
610 
611  doTreeNode(os, depth + 1, linfo->node, scope, strTab);
612 
613  doIndent(os, depth);
614  *os << "</L>\n";
615  }
616 }
617 
618 //----------------------------------------------------------------------
619 
620 // Try to guess the file and line location of a subtree based on info
621 // in the subtree and return the answer in 'scope'.
622 //
623 // This is used as the target location for alien nodes (both guard and
624 // double aliens). Inline subtrees are the most reliable, then loops
625 // and statements.
626 //
627 // Note: if 'use_file' is true, then use the file from 'scope',
628 // otherwise try to guess the correct file.
629 //
630 static void
631 locateTree(TreeNode * node, ScopeInfo & scope, HPC::StringTable & strTab, bool use_file)
632 {
633  const long max_line = LONG_MAX;
634  long empty_index = strTab.str2index("");
635 
636  if (node == NULL) {
637  return;
638  }
639 
640  // first, find the correct file and base. if use_file is true, then
641  // use the answer in 'scope', else try to guess the file.
642  //
643  if (! use_file) {
644 
645  // inline subtrees are the most reliable
646  for (auto nit = node->nodeMap.begin(); nit != node->nodeMap.end(); ++nit) {
647  FLPIndex flp = nit->first;
648 
649  if (flp.file_index != empty_index) {
650  scope.file_index = flp.file_index;
651  scope.base_index = flp.base_index;
652  goto found_file;
653  }
654  }
655 
656  // next, try loops
657  for (auto lit = node->loopList.begin(); lit != node->loopList.end(); ++lit) {
658  LoopInfo * linfo = *lit;
659 
660  if (linfo->file_index != empty_index) {
661  scope.file_index = linfo->file_index;
662  scope.base_index = linfo->base_index;
663  goto found_file;
664  }
665  }
666 
667  // finally, try stmts
668  for (auto sit = node->stmtMap.begin(); sit != node->stmtMap.end(); ++sit) {
669  StmtInfo * sinfo = sit->second;
670 
671  if (sinfo->file_index != empty_index) {
672  scope.file_index = sinfo->file_index;
673  scope.base_index = sinfo->base_index;
674  goto found_file;
675  }
676  }
677  }
678 found_file:
679 
680  // second, guess the line number. rescan the inline trees and loops
681  // and take the min line number among files that match.
682  //
683  scope.line_num = max_line;
684 
685  for (auto nit = node->nodeMap.begin(); nit != node->nodeMap.end(); ++nit) {
686  FLPIndex flp = nit->first;
687 
688  if (flp.base_index == scope.base_index && flp.line_num > 0
689  && flp.line_num < scope.line_num) {
690  scope.line_num = flp.line_num;
691  }
692  }
693 
694  for (auto lit = node->loopList.begin(); lit != node->loopList.end(); ++lit) {
695  LoopInfo * linfo = *lit;
696 
697  if (linfo->base_index == scope.base_index && linfo->line_num > 0
698  && linfo->line_num < scope.line_num) {
699  scope.line_num = linfo->line_num;
700  }
701  }
702 
703  // found valid line number
704  if (scope.line_num < max_line) {
705  return;
706  }
707 
708  // use stmts as a backup only if no inlines or loops
709  for (auto sit = node->stmtMap.begin(); sit != node->stmtMap.end(); ++sit) {
710  StmtInfo * sinfo = sit->second;
711 
712  if (sinfo->base_index == scope.base_index && sinfo->line_num > 0
713  && sinfo->line_num < scope.line_num) {
714  scope.line_num = sinfo->line_num;
715  }
716  }
717 
718  // if nothing matches, then 0 is the unknown line number
719  if (scope.line_num == max_line) {
720  scope.line_num = 0;
721  }
722 }
723 
724 } // namespace Output
725 } // namespace BAnal
map< long, TreeNode * > AlienMap
void printProc(ostream *os, ostream *gaps, string gaps_file, FileInfo *finfo, GroupInfo *ginfo, ProcInfo *pinfo, HPC::StringTable &strTab)
map< long, VMAIntervalSet * > LineNumberMap
void printStructFileEnd(ostream *os, ostream *gaps)
long str2index(const std::string &str)
bfd_vma VMA
Definition: ISATypes.hpp:79
#define INIT_LM_INDEX
static void doStmtList(ostream *, int, TreeNode *)
void printLoadModuleBegin(ostream *os, string lmName)
#define STRING(label, str)
cct_node_t * node
Definition: cct.c:128
#define INDEX
static void doLoopList(ostream *, int, TreeNode *, HPC::StringTable &)
#define GUARD_NAME
Definition: dictionary.h:50
static long gaps_line
ScopeInfo(long file, long base, long line=0)
void printVariable(ostream *os, FileInfo *finfo, VariableInfo vinfo)
void printLoadModuleEnd(ostream *os)
void printFileBegin(ostream *os, FileInfo *finfo)
static void doTreeNode(ostream *, int, TreeNode *, ScopeInfo, HPC::StringTable &)
const std::string & index2str(long index)
std::pair< iterator, bool > insert(const VMA beg, const VMA end)
std::string toString() const
void printFileEnd(ostream *os, FileInfo *finfo)
static void doIndent(ostream *os, int depth)
#define INDENT
#define NUMBER(label, num)
static long next_index
#define NULL
Definition: ElfHelper.cpp:85
static void doGaps(ostream *, ostream *, string, FileInfo *, GroupInfo *, ProcInfo *)
void printStructFileBegin(ostream *os, ostream *gaps, string filenm)
string basename(const char *fName)
Definition: FileUtil.cpp:90
static void locateTree(TreeNode *, ScopeInfo &, HPC::StringTable &, bool=false)
<!-- ********************************************************************--> n<!-- HPCToolkit Experiment DTD --> n<!-- Version 2.1 --> n<!-- ********************************************************************--> n<!ELEMENT HPCToolkitExperiment(Header,(SecCallPathProfile|SecFlatProfile) *)> n<!ATTLIST HPCToolkitExperiment\n version CDATA #REQUIRED > n n<!-- ******************************************************************--> n n<!-- Info/NV:flexible name-value pairs:(n) ame;(t) ype;(v) alue --> n<!ELEMENT Info(NV *)> n<!ATTLIST Info\n n CDATA #IMPLIED > n<!ELEMENT NV EMPTY > n<!ATTLIST NV\n n CDATA #REQUIRED\n t CDATA #IMPLIED\n v CDATA #REQUIRED > n n<!-- ******************************************************************--> n<!-- Header --> n<!-- ******************************************************************--> n<!ELEMENT Header(Info *)> n<!ATTLIST Header\n n CDATA #REQUIRED > n n<!-- ******************************************************************--> n<!-- Section Header --> n<!-- ******************************************************************--> n<!ELEMENT SecHeader(MetricTable?, MetricDBTable?, TraceDBTable?, LoadModuleTable?, FileTable?, ProcedureTable?, Info *)> n n<!-- MetricTable:--> n<!ELEMENT MetricTable(Metric) * > n n<!-- Metric:(i) d;(n) ame --> n<!--(v) alue-type:transient type of values --> n<!--(t) ype:persistent type of metric --> n<!-- fmt:format;show;--> n<!ELEMENT Metric(MetricFormula *, Info?)> n<!ATTLIST Metric\n i CDATA #REQUIRED\n n CDATA #REQUIRED\n es CDATA #IMPLIED\n em CDATA #IMPLIED\n ep CDATA #IMPLIED\n v(raw|final|derived-incr|derived) \"raw\\ t (inclusive|exclusive|nil) \nil\\ partner CDATA #IMPLIED\ fmt CDATA #IMPLIED\ show (1|0) \1\\ show-percent (1|0) \1> n n<!-- MetricFormula represents derived metrics: (t)ype; (frm): formula --> n<!ELEMENT MetricFormula (Info?)> n<!ATTLIST MetricFormula\ t (combine|finalize) \finalize\\ i CDATA #IMPLIED\ frm CDATA #REQUIRED> n n<!-- Metric data, used in sections: (n)ame [from Metric]; (v)alue --> n<!ELEMENT M EMPTY> n<!ATTLIST M\ n CDATA #REQUIRED\ v CDATA #REQUIRED> n n<!-- MetricDBTable: --> n<!ELEMENT MetricDBTable (MetricDB)*> n n<!-- MetricDB: (i)d; (n)ame --> n<!-- (t)ype: persistent type of metric --> n<!-- db-glob: file glob describing files in metric db --> n<!-- db-id: id within metric db --> n<!-- db-num-metrics: number of metrics in db --> n<!-- db-header-sz: size (in bytes) of a db file header --> n<!ELEMENT MetricDB EMPTY> n<!ATTLIST MetricDB\ i CDATA #REQUIRED\ n CDATA #REQUIRED\ t (inclusive|exclusive|nil) \nil\\ partner CDATA #IMPLIED\ db-glob CDATA #IMPLIED\ db-id CDATA #IMPLIED\ db-num-metrics CDATA #IMPLIED\ db-header-sz CDATA #IMPLIED> n n<!-- TraceDBTable: --> n<!ELEMENT TraceDBTable (TraceDB)> n n<!-- TraceDB: (i)d --> n<!-- db-min-time: min beginning time stamp (global) --> n<!-- db-max-time: max ending time stamp (global) --> n<!ELEMENT TraceDB EMPTY> n<!ATTLIST TraceDB\ i CDATA #REQUIRED\ db-glob CDATA #IMPLIED\ db-min-time CDATA #IMPLIED\ db-max-time CDATA #IMPLIED\ db-header-sz CDATA #IMPLIED> n n<!-- LoadModuleTable assigns a short name to a load module --> n<!ELEMENT LoadModuleTable (LoadModule)*> n n<!ELEMENT LoadModule (Info?)> n<!ATTLIST LoadModule\ i CDATA #REQUIRED\ n CDATA #REQUIRED> n n<!-- FileTable assigns a short name to a file --> n<!ELEMENT FileTable (File)*> n n<!ELEMENT File (Info?)> n<!ATTLIST File\ i CDATA #REQUIRED\ n CDATA #REQUIRED> n n<!-- ProcedureTable assigns a short name to a procedure --> n<!ELEMENT ProcedureTable (Procedure)*> n n<!-- Info/NV: flexible name-value pairs: (n)ame; (t)ype; (v)alue --> n<!-- f: family of the procedure (fake, root, ...)--> n<!ELEMENT Procedure (Info?)> n<!ATTLIST Procedure\ i CDATA #REQUIRED\ n CDATA #REQUIRED\ f CDATA #IMPLIED> n n<!-- ****************************************************************** --> n<!-- Section: Call path profile --> n<!-- ****************************************************************** --> n<!ELEMENT SecCallPathProfile (SecHeader, SecCallPathProfileData)> n<!ATTLIST SecCallPathProfile\ i CDATA #REQUIRED\ n CDATA #REQUIRED> n n<!ELEMENT SecCallPathProfileData (PF|M)*> n<!-- Procedure frame --> n<!-- (i)d: unique identifier for cross referencing --> n<!-- (s)tatic scope id --> n<!-- (n)ame: a string or an id in ProcedureTable --> n<!-- (lm) load module: a string or an id in LoadModuleTable --> n<!-- (f)ile name: a string or an id in LoadModuleTable --> n<!-- (l)ine range: \beg-end\ (inclusive range) --> n<!-- (a)lien: whether frame is alien to enclosing P --> n<!-- (str)uct: hpcstruct node id --> n<!-- (t)ype: hpcrun node type: memory access, variable declaration, ... --> n<!-- (v)ma-range-set: \{[beg-end), [beg-end)...}\ --> n<!ELEMENT PF (PF|Pr|L|C|S|M)*> n<!ATTLIST PF\ i CDATA #IMPLIED\ s CDATA #IMPLIED\ n CDATA #REQUIRED\ lm CDATA #IMPLIED\ f CDATA #IMPLIED\ l CDATA #IMPLIED\ str CDATA #IMPLIED\ v CDATA #IMPLIED> n<!-- Procedure (static): GOAL: replace with 'P' --> n<!ELEMENT Pr (Pr|L|C|S|M)*> n<!ATTLIST Pr\ i CDATA #IMPLIED\ s CDATA #IMPLIED\ n CDATA #REQUIRED\ lm CDATA #IMPLIED\ f CDATA #IMPLIED\ l CDATA #IMPLIED\ a (1|0) \0\\ str CDATA #IMPLIED\ v CDATA #IMPLIED> n<!-- Callsite (a special StatementRange) --> n<!ELEMENT C (PF|M)*> n<!ATTLIST C\ i CDATA #IMPLIED\ s CDATA #IMPLIED\ l CDATA #IMPLIED\ str CDATA #IMPLIED\ v CDATA #IMPLIED> n n<!-- ****************************************************************** --> n<!-- Section: Flat profile --> n<!-- ****************************************************************** --> n<!ELEMENT SecFlatProfile (SecHeader, SecFlatProfileData)> n<!ATTLIST SecFlatProfile\ i CDATA #REQUIRED\ n CDATA #REQUIRED> n n<!ELEMENT SecFlatProfileData (LM|M)*> n<!-- Load module: (i)d; (n)ame; (v)ma-range-set --> n<!ELEMENT LM (F|P|M)*> n<!ATTLIST LM\ i CDATA #IMPLIED\ n CDATA #REQUIRED\ v CDATA #IMPLIED> n<!-- File --> n<!ELEMENT F (P|L|S|M)*> n<!ATTLIST F\ i CDATA #IMPLIED\ n CDATA #REQUIRED> n<!-- Procedure (Note 1) --> n<!ELEMENT P (P|A|L|S|C|M)*> n<!ATTLIST P\ i CDATA #IMPLIED\ n CDATA #REQUIRED\ l CDATA #IMPLIED\ str CDATA #IMPLIED\ v CDATA #IMPLIED> n<!-- Alien (Note 1) --> n<!ELEMENT A (A|L|S|C|M)*> n<!ATTLIST A\ i CDATA #IMPLIED\ f CDATA #IMPLIED\ n CDATA #IMPLIED\ l CDATA #IMPLIED\ str CDATA #IMPLIED\ v CDATA #IMPLIED> n<!-- Loop (Note 1,2) --> n<!ELEMENT L (A|Pr|L|S|C|M)*> n<!ATTLIST L\ i CDATA #IMPLIED\ s CDATA #IMPLIED\ l CDATA #IMPLIED\ f CDATA #IMPLIED\ str CDATA #IMPLIED\ v CDATA #IMPLIED> n<!-- Statement (Note 2) --> n<!-- (it): trace record identifier --> n<!ELEMENT S (S|M)*> n<!ATTLIST S\ i CDATA #IMPLIED\ it CDATA #IMPLIED\ s CDATA #IMPLIED\ l CDATA #IMPLIED\ str CDATA #IMPLIED\ v CDATA #IMPLIED> n<!-- Note 1: Contained Cs may not contain PFs --> n<!-- Note 2: The 's' attribute is not used for flat profiles --> n
#define VRANGE(vma, len)
static const char * hpcstruct_xml_head