HPCToolkit
CCT-Tree.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::ostream;
64 using std::endl;
65 using std::hex;
66 using std::dec;
67 
68 #include <string>
69 using std::string;
70 
71 #include <vector>
72 using std::vector;
73 
74 #include <set>
75 using std::set;
76 
77 #include <typeinfo>
78 
79 //*************************** User Include Files ****************************
80 
81 #include <include/gcc-attr.h>
82 #include <include/uint.h>
83 
84 #include "CCT-Tree.hpp"
85 #include "CallPath-Profile.hpp" // for CCT::Tree::metadata()
86 
87 #include <lib/xml/xml.hpp>
88 
90 #include <lib/support/Logic.hpp>
91 #include <lib/support/SrcFile.hpp>
92 using SrcFile::ln_NULL;
93 #include <lib/support/StrUtil.hpp>
94 #include <lib/support/Trace.hpp>
95 
96 #include <lib/support/dictionary.h>
97 
98 //*************************** Forward Declarations ***************************
99 
100 
101 //***************************************************************************
102 #define XML_ATTR_DATA_NODE_ALLOC "d"
103 #define XML_ATTR_DATA_START_MEM "m"
104 
105 //***************************************************************************
106 // Tree
107 //***************************************************************************
108 
109 namespace Prof {
110 
111 extern std::map<uint, uint> m_mapFileIDs; // map between file IDs
112 extern std::map<uint, uint> m_mapProcIDs; // map between proc IDs
113 
114 extern std::map<uint, uint> m_pairFakeLoadModule;
115 
116 // local function to convert from the original procedure ID into a
117 // a "compact" id to reduce redundancy if the procedure of the same
118 // file has exactly the same name.
119 // Note that this map doesn't differentiate between "foo" and "foo(int)"
120 static uint
122 {
123  uint id = proc_id;
124  if (Prof::m_mapProcIDs.find(proc_id) != Prof::m_mapProcIDs.end()) {
125  // the file ID should redirected to another file ID which has
126  // exactly the same filename
127  id = Prof::m_mapProcIDs[proc_id];
128  }
129  return id;
130 }
131 
132 // local method to convert from the original load module into
133 // a compact ID to reduce redundancy.
134 static uint
136 {
137  uint id = lm_id;
138  std::map<uint, uint>::iterator it = Prof::m_pairFakeLoadModule.find(lm_id);
139 
140  if (it != Prof::m_pairFakeLoadModule.end()) {
141  id = it->second;
142  }
143  return id;
144 }
145 
146 namespace CCT {
147 
149  : m_root(NULL), m_metadata(metadata),
150  m_maxDenseId(0), m_nodeidMap(NULL),
151  m_mergeCtxt(NULL)
152 {
153 }
154 
155 
157 {
158  delete m_root;
159  m_metadata = NULL;
160  delete m_nodeidMap;
161  delete m_mergeCtxt;
162 }
163 
164 
166 Tree::merge(const Tree* y, uint x_newMetricBegIdx, uint mrgFlag, uint oFlag)
167 {
168  Tree* x = this;
169  ANode* x_root = root();
170  ANode* y_root = y->root();
171 
172  // -------------------------------------------------------
173  // Merge pre-condition: both x and y should be "locally merged",
174  // i.e., the nodes themselves should be equal (modulo metrics & children)
175  // -------------------------------------------------------
176  bool isPrecondition = false;
177  if (typeid(*x_root) == typeid(CCT::Root)
178  && typeid(*y_root) == typeid(CCT::Root)) {
179  // Case 1
180  isPrecondition = true;
181  }
182  else {
183  ADynNode* x_dyn = dynamic_cast<ADynNode*>(x_root);
184  ADynNode* y_dyn = dynamic_cast<ADynNode*>(y_root);
185  if (x_dyn && y_dyn && ADynNode::isMergable(*x_dyn, *y_dyn)) {
186  // Case 2a
187  isPrecondition = true;
188  }
189  else if ((x_dyn->childCount() == 0 || y_dyn->childCount() == 0)
190  && x_dyn->isPrimarySynthRoot() && y_dyn->isPrimarySynthRoot()) {
191  // Case 2b (A special sub-case of Case 1): (a) Neither tree x
192  // nor y have been canonicalized (and therefore do not have a
193  // CCT::Root node); and (b) one of x or y is a single-node tree.
194  isPrecondition = true;
195  }
196  }
197  DIAG_Assert(isPrecondition, "Prof::CCT::Tree::merge: Merge precondition fails!");
198 
199  // -------------------------------------------------------
200  //
201  // -------------------------------------------------------
202 
203  if (!m_mergeCtxt) {
204  bool doTrackCPIds = !x->metadata()->traceFileNameSet().empty();
205  m_mergeCtxt = new MergeContext(x, doTrackCPIds);
206  }
207  m_mergeCtxt->flags(mrgFlag);
208 
209  MergeEffectList* mrgEffects =
210  x_root->mergeDeep(y_root, x_newMetricBegIdx, *m_mergeCtxt, oFlag);
211 
212  DIAG_If(0 /*public diag level*/) {
214  }
215 
216  return mrgEffects;
217 }
218 
219 
220 void
221 Tree::pruneCCTByNodeId(const uint8_t* prunedNodes)
222 {
223  m_root->pruneChildrenByNodeId(prunedNodes);
224  DIAG_Assert(!prunedNodes[m_root->id()], "Prof::CCT::Tree::pruneCCTByNodeId(): cannot delete root!");
225 
226  //Prof::CCT::ANode::pruneByNodeId(m_root, prunedNodes);
227  //DIAG_Assert(m_root, "Prof::CCT::Tree::pruneCCTByNodeId(): cannot delete root!");
228 }
229 
230 
231 uint
233 {
234  uint nextId = 1; // cf. s_nextUniqueId
235  nextId = m_root->makeDensePreorderIds(nextId);
236 
237  m_maxDenseId = (nextId - 1);
238  return m_maxDenseId;
239 }
240 
241 
242 ANode*
243 Tree::findNode(uint nodeId) const
244 {
245  if (!m_nodeidMap) {
247  for (ANodeIterator it(m_root); it.Current(); ++it) {
248  ANode* n = it.current();
249  m_nodeidMap->insert(std::make_pair(n->id(), n));
250  }
251  }
252  NodeIdToANodeMap::iterator it = m_nodeidMap->find(nodeId);
253  return (it != m_nodeidMap->end()) ? it->second : NULL;
254 }
255 
256 
257 bool
259 {
260  bool areAllUnique = true;
261  MergeContext::CPIdSet cpIdSet;
262 
263  for (ANodeIterator it(root()); it.Current(); ++it) {
264  ANode* n = it.current();
265 
266  ADynNode* n_dyn = dynamic_cast<ADynNode*>(n);
267  if (n_dyn && n_dyn->cpId() != HPCRUN_FMT_CCTNodeId_NULL) {
268  std::pair<MergeContext::CPIdSet::iterator, bool> ret =
269  cpIdSet.insert(n_dyn->cpId());
270  bool isInserted = ret.second;
271  areAllUnique = areAllUnique && isInserted;
272  DIAG_MsgIf(!isInserted, "CCT::Tree::verifyUniqueCPIds: Duplicate CPId: " << n_dyn->cpId());
273  }
274  }
275 
276  return areAllUnique;
277 }
278 
279 
280 std::ostream&
281 Tree::writeXML(std::ostream& os, const Metric::Mgr *metricMgr,
282  uint metricBeg, uint metricEnd,
283  uint oFlags) const
284 {
285  if (m_root) {
286  m_root->writeXML(os, metricMgr, metricBeg, metricEnd, oFlags);
287  }
288  return os;
289 }
290 
291 
292 std::ostream&
293 Tree::dump(const Metric::Mgr *metricMgr, std::ostream& os, uint oFlags) const
294 {
295  writeXML(os, metricMgr, Metric::IData::npos, Metric::IData::npos, oFlags);
296  return os;
297 }
298 
299 
300 void
301 Tree::ddump(const Metric::Mgr *metricMgr) const
302 {
303  dump(metricMgr, std::cerr, Tree::OFlg_DebugAll);
304 }
305 
306 
307 } // namespace CCT
308 
309 } // namespace Prof
310 
311 
312 
313 namespace Prof {
314 
315 namespace CCT {
316 
317 //***************************************************************************
318 // ANodeTy `methods' (could completely replace with dynamic typing)
319 //***************************************************************************
320 
321 const string ANode::NodeNames[ANode::TyNUMBER] = {
322  "Root", "PF", "Pr", "L", "C", "S", "Any"
323 };
324 
325 
326 const string&
328 {
329  return NodeNames[tp];
330 }
331 
332 
335 {
336  DIAG_Assert((i >= 0) && (i < TyNUMBER), "");
337  return (ANodeTy)i;
338 }
339 
341 
342 
343 //***************************************************************************
344 // ANode, etc: constructors/destructors
345 //***************************************************************************
346 
347 string AProcNode::BOGUS;
348 
349 
350 //***************************************************************************
351 // ANode, etc: Tree Navigation
352 //***************************************************************************
353 
354 #define dyn_cast_return(base, derived, expr) \
355  { base* ptr = expr; \
356  if (ptr == NULL) { \
357  return NULL; \
358  } else { \
359  return dynamic_cast<derived*>(ptr); \
360  } \
361  }
362 
363 
364 ANode*
366 {
367  ANode* s = const_cast<ANode*>(this);
368  while (s && s->type() != tp) {
369  s = s->parent();
370  }
371  return s;
372 }
373 
374 
375 #if 0 // is this obsolete?
376 int
377 isAncestorOf(ANode* parent, ANode* son, int difference)
378 {
379  ANode *iter = son;
380  while (iter && difference > 0 && iter != parent) {
381  iter = iter->Parent();
382  difference--;
383  }
384  if (iter && iter == parent) {
385  return 1;
386  }
387  return 0;
388 }
389 #endif
390 
391 
392 Root*
394 {
395  if (Parent() == NULL) {
396  return NULL;
397  }
398  else {
399  dyn_cast_return(ANode, Root, ancestor(TyRoot));
400  }
401 }
402 
403 
404 ProcFrm*
406 {
407  dyn_cast_return(ANode, ProcFrm, ancestor(TyProcFrm));
408 }
409 
410 
411 Proc*
413 {
414  dyn_cast_return(ANode, Proc, ancestor(TyProc));
415 }
416 
417 
418 Loop*
420 {
421  dyn_cast_return(ANode, Loop, ancestor(TyLoop));
422 }
423 
424 
425 Call*
427 {
428  dyn_cast_return(ANode, Call, ancestor(TyCall));
429 }
430 
431 
432 Stmt*
434 {
435  dyn_cast_return(ANode, Stmt, ancestor(TyStmt));
436 }
437 
438 
439 //***************************************************************************
440 // Metrics
441 //***************************************************************************
442 
443 void
445 {
446  if ( !(mBegId < mEndId) ) {
447  return; // short circuit
448  }
449 
450  for (ANodeIterator it(this); it.Current(); ++it) {
451  ANode* n = it.current();
452  n->zeroMetrics(mBegId, mEndId);
453  }
454 }
455 
456 
457 void
459 {
460  VMAIntervalSet ivalset; // TODO: cheat using a VMAInterval set
461  for (uint mId = mBegId; mId < mEndId; ++mId) {
462  ivalset.insert(VMAInterval(mId, mId + 1)); // [ )
463  }
464  aggregateMetricsIncl(ivalset);
465 }
466 
467 
468 void
470 {
471  if (ivalset.empty()) {
472  return; // short circuit
473  }
474 
475  const ANode* root = this;
476  ANodeIterator it(root, NULL/*filter*/, false/*leavesOnly*/,
478  for (ANode* n = NULL; (n = it.current()); ++it) {
479  if (n != root) {
480 
481  if (hpcrun_fmt_node_type_root(n->hpcrun_node_type())) {
482  // Special treatement for "artificial root":
483  // we don't aggregate the metrics of "artificial root" into the "invisible root"
484  // this is because the artificial root will be rendered in a separate view
485  // by the viewer
486  continue;
487  }
488  ANode* n_parent = n->parent();
489  for (VMAIntervalSet::const_iterator it1 = ivalset.begin();
490  it1 != ivalset.end(); ++it1) {
491  const VMAInterval& ival = *it1;
492  uint mBegId = (uint)ival.beg(), mEndId = (uint)ival.end();
493 
494  for (uint mId = mBegId; mId < mEndId; ++mId) {
495  double mVal = n->demandMetric(mId, mEndId/*size*/);
496  n_parent->demandMetric(mId, mEndId/*size*/) += mVal;
497  }
498  }
499  }
500  }
501 }
502 
503 
504 void
506 {
507  VMAIntervalSet ivalset; // TODO: cheat using a VMAInterval set
508  for (uint mId = mBegId; mId < mEndId; ++mId) {
509  ivalset.insert(VMAInterval(mId, mId + 1)); // [ )
510  }
511  aggregateMetricsExcl(ivalset);
512 }
513 
514 
515 void
517 {
518  if (ivalset.empty()) {
519  return; // short circuit
520  }
521 
522  AProcNode* frame = NULL; // will be set during tree traversal
523  aggregateMetricsExcl(frame, ivalset);
524 }
525 
526 
527 void
529 {
530  ANode* n = this;
531 
532  // -------------------------------------------------------
533  // Pre-order visit
534  // -------------------------------------------------------
535  //
536  // laks 2015.10.21: we don't want accumulate the exclusive cost of
537  // an inlined statement to the caller. Instead, we assume an inline
538  // function (Proc) as the same as a normal procedure (ProcFrm).
539  // And the lowest common ancestor for Proc and ProcFrm is AProcNode.
540  //
541  bool isFrame = (typeid(*n) == typeid(ProcFrm));
542  bool isProc = (typeid(*n) == typeid(Proc));
543 
544  bool isInlineMacro = false;
545  bool isInlineCall = false;
546 
547  NonUniformDegreeTreeNode *parent = n->Parent();
548  if (isProc && parent != NULL) {
549  // if this node and the parent are proc, it is possible this node is an
550  // inline procedure callsite
551  std::string myprocname = n->structure()->name();
552 
553  if (typeid(*parent) == typeid(Proc)) {
554  // check if this node is an inline procedure call.
555  // a node is an inline proc call iff its parent is an empty proc and
556  // the node itself is a non-empty proc
557 
558  // condition 1: the myprocname of the parent must be empty
559  Struct::ACodeNode *strct = ((ANode*)parent)->structure();
560  bool isEmptyNameParent = strct->name().empty();
561 
562  // condition 2: the myprocname of the inline is not empty
563  bool isFullyNamed = !myprocname.empty();
564 
565  isInlineCall = isEmptyNameParent && isFullyNamed;
566  }
567  isInlineMacro = !isInlineCall && myprocname.compare(GUARD_NAME) == 0;
568  }
569 
570  bool isLogicalProc = isFrame || isInlineCall || isInlineMacro;
571  AProcNode * frameNxt = (isLogicalProc) ? static_cast<AProcNode*>(n) : frame;
572 
573  // -------------------------------------------------------
574  // Tree traversal
575  // -------------------------------------------------------
576  for (ANodeChildIterator it(n); it.Current(); ++it) {
577  ANode* x = it.current();
578  x->aggregateMetricsExcl(frameNxt, ivalset);
579  }
580 
581  // -------------------------------------------------------
582  // Post-order visit
583  // -------------------------------------------------------
584  if (typeid(*n) == typeid(CCT::Stmt) || isInlineMacro) {
585  ANode* n_parent = n->parent();
586 
587  for (VMAIntervalSet::const_iterator it = ivalset.begin();
588  it != ivalset.end(); ++it) {
589  const VMAInterval& ival = *it;
590  uint mBegId = (uint)ival.beg(), mEndId = (uint)ival.end();
591 
592  for (uint mId = mBegId; mId < mEndId; ++mId) {
593  double mVal = n->demandMetric(mId, mEndId/*size*/);
594  n_parent->demandMetric(mId, mEndId/*size*/) += mVal;
595  if (frame && frame != n_parent) {
596  frame->demandMetric(mId, mEndId/*size*/) += mVal;
597  }
598  }
599  }
600  }
601 }
602 
603 
604 void
605 ANode::computeMetrics(const Metric::Mgr& mMgr, uint mBegId, uint mEndId,
606  bool doFinal)
607 {
608  if ( !(mBegId < mEndId) ) {
609  return;
610  }
611 
612  // N.B. pre-order walk assumes point-wise metrics
613  // Cf. Analysis::Flat::Driver::computeDerivedBatch().
614 
615  for (ANodeIterator it(this); it.Current(); ++it) {
616  ANode* n = it.current();
617  n->computeMetricsMe(mMgr, mBegId, mEndId, doFinal);
618  }
619 }
620 
621 
622 void
623 ANode::computeMetricsMe(const Metric::Mgr& mMgr, uint mBegId, uint mEndId,
624  bool doFinal)
625 {
626  uint numMetrics = mMgr.size();
627 
628  for (uint mId = mBegId; mId < mEndId; ++mId) {
629  const Metric::ADesc* m = mMgr.metric(mId);
630  const Metric::DerivedDesc* mm = dynamic_cast<const Metric::DerivedDesc*>(m);
631  if (mm && mm->expr()) {
632  const Metric::AExpr* expr = mm->expr();
633  expr->evalNF(*this);
634  if (doFinal) {
635  double val = expr->eval(*this);
636  demandMetric(mId, numMetrics/*size*/) = val;
637  }
638  }
639  }
640 }
641 
642 
643 void
644 ANode::computeMetricsIncr(const Metric::Mgr& mMgr, uint mBegId, uint mEndId,
646 {
647  if ( !(mBegId < mEndId) ) {
648  return;
649  }
650 
651  // N.B. pre-order walk assumes point-wise metrics
652  // Cf. Analysis::Flat::Driver::computeDerivedBatch().
653 
654  for (ANodeIterator it(this); it.Current(); ++it) {
655  ANode* n = it.current();
656  n->computeMetricsIncrMe(mMgr, mBegId, mEndId, fn);
657  }
658 }
659 
660 
661 void
662 ANode::computeMetricsIncrMe(const Metric::Mgr& mMgr, uint mBegId, uint mEndId,
664 {
665  for (uint mId = mBegId; mId < mEndId; ++mId) {
666  const Metric::ADesc* m = mMgr.metric(mId);
667  const Metric::DerivedIncrDesc* mm =
668  dynamic_cast<const Metric::DerivedIncrDesc*>(m);
669  if (mm && mm->expr()) {
670  const Metric::AExprIncr* expr = mm->expr();
671  switch (fn) {
673  expr->initialize(*this); break;
675  expr->initializeSrc(*this); break;
677  expr->accumulate(*this); break;
679  expr->combine(*this); break;
681  expr->finalize(*this); break;
682  default:
684  }
685  }
686  }
687 }
688 
689 
690 void
692  const ANode* root, double thresholdPct,
693  uint8_t* prunedNodes)
694 {
695  for (ANodeChildIterator it(this); it.Current(); /* */) {
696  ANode* x = it.current();
697  it++; // advance iterator -- it is pointing at 'x'
698 
699 
700  // ----------------------------------------------------------
701  // Determine whether 'x' is important: any inclusive metric >= threshold
702  // ----------------------------------------------------------
703  uint numIncl = 0;
704  bool isImportant = false;
705 
706  for (VMAIntervalSet::const_iterator it1 = ivalset.begin();
707  it1 != ivalset.end(); ++it1) {
708  const VMAInterval& ival = *it1;
709  uint mBegId = (uint)ival.beg(), mEndId = (uint)ival.end();
710 
711  for (uint mId = mBegId; mId < mEndId; ++mId) {
712  const Prof::Metric::ADesc* m = mMgr.metric(mId);
713  if (m->type() != Metric::ADesc::TyIncl) {
714  continue;
715  }
716  numIncl++;
717 
718  double total = root->metric(mId); // root->metric(m->partner()->id());
719 
720  double pct = x->metric(mId) * 100 / total;
721  if (pct >= thresholdPct) {
722  isImportant = true;
723  break;
724  }
725  }
726  if (isImportant) { break; }
727  }
728 
729  // ----------------------------------------------------------
730  //
731  // ----------------------------------------------------------
732  if (isImportant || numIncl == 0) {
733  x->pruneByMetrics(mMgr, ivalset, root, thresholdPct, prunedNodes);
734  }
735  else {
736  deleteChaff(x, prunedNodes);
737  }
738  }
739 }
740 
741 
742 #if 0
743 void
744 ANode::pruneByNodeId(ANode*& x, const uint8_t* prunedNodes)
745 {
746  // Visiting in preorder can save a little work since a whole subtree
747  // can be deleted (factoring out the destructor's recursion)
748  if (prunedNodes[x->id()]) {
749  x->unlink(); // unlink 'x' from tree
750  delete x;
751  x = NULL;
752  }
753  else {
754  for (ANodeChildIterator it(x); it.Current(); /* */) {
755  ANode* x_child = it.current();
756  it++; // advance iterator -- it is pointing at 'x_child'
757  pruneByNodeId(x_child, prunedNodes);
758  }
759  }
760 }
761 #endif
762 
763 
764 void
765 ANode::pruneChildrenByNodeId(const uint8_t* prunedNodes)
766 {
767  ANode* x = this;
768 
769  for (ANodeChildIterator it(x); it.Current(); /* */) {
770  ANode* x_child = it.current();
771  it++; // advance iterator -- it is pointing at 'x_child'
772 
773  // Visiting in preorder can save a little work since a whole subtree
774  // can be deleted (factoring out the destructor's recursion)
775  if (prunedNodes[x_child->id()]) {
776  x_child->unlink(); // unlink 'x_child' from tree
777  delete x_child;
778  }
779  else {
780  x_child->pruneChildrenByNodeId(prunedNodes);
781  }
782  }
783 }
784 
785 
786 bool
787 ANode::deleteChaff(ANode* x, uint8_t* deletedNodes)
788 {
789  bool x_isLeaf = x->isLeaf(); // N.B. must perform before below
790  uint x_id = x->id();
791 
792  bool wereAllChildrenDeleted = true;
793  for (ANodeChildIterator it(x); it.Current(); /* */) {
794  ANode* x_child = it.current();
795  it++; // advance iterator -- it is pointing at 'x_child'
796 
797  wereAllChildrenDeleted = (wereAllChildrenDeleted
798  && deleteChaff(x_child, deletedNodes));
799  }
800 
801  bool wasDeleted = false;
802  if (wereAllChildrenDeleted) {
803  Prof::CCT::ADynNode* x_dyn = dynamic_cast<Prof::CCT::ADynNode*>(x);
804  bool mustRetain = (x_dyn && hpcrun_fmt_doRetainId(x_dyn->cpId()));
805  if ((x_isLeaf && !mustRetain) || !x_isLeaf) {
806  x->unlink(); // unlink 'x' from tree
807  delete x;
808  if (deletedNodes) {
809  deletedNodes[x_id] = 1;
810  }
811  wasDeleted = true;
812  }
813  }
814 
815  return wasDeleted;
816 }
817 
818 
819 //**********************************************************************
820 // Merging
821 //**********************************************************************
822 
824 ANode::mergeDeep(ANode* y, uint x_newMetricBegIdx, MergeContext& mrgCtxt,
825  uint oFlag)
826 {
827  ANode* x = this;
828 
829  // ------------------------------------------------------------
830  // 0. If y is childless, return.
831  // ------------------------------------------------------------
832  if (y->isLeaf()) {
833  return NULL;
834  }
835 
836  // ------------------------------------------------------------
837  // 1. If a child y_child of y _does not_ appear as a child of x,
838  // then copy (subtree) y_child [fixing its metrics], make it a
839  // child of x and return.
840  // 2. If a child y_child of y _does_ have a corresponding child
841  // x_child of x, merge [the metrics of] y_child into x_child and
842  // recur.
843  // ------------------------------------------------------------
844  MergeEffectList* effctLst = new MergeEffectList;
845 
846  for (ANodeChildIterator it(y); it.Current(); /* */) {
847  ANode* y_child = it.current();
848  ADynNode* y_child_dyn = dynamic_cast<ADynNode*>(y_child);
849  DIAG_Assert(y_child_dyn, "ANode::mergeDeep");
850  it++; // advance iterator -- it is pointing at 'child'
851 
852  MergeEffectList* effctLst1 = NULL;
853 
854  ADynNode* x_child_dyn = x->findDynChild(*y_child_dyn);
855 
856 #define MERGE_ACTION 0
857 #define MERGE_ERROR 0
858 
859  if (!x_child_dyn) {
860  // case 1: insert nodes
861  if (mrgCtxt.flags() & MrgFlg_AssertCCTMergeOnly) {
862  DIAG_MsgIf(MERGE_ERROR /*(oFlag & Tree::OFlg_Debug)*/,
863  "CCT::ANode::mergeDeep: Adding not permitted:\n "
864  << y_child->toStringMe(Tree::OFlg_Debug));
865  DIAG_WMsgIf( !(mrgCtxt.flags() & MrgFlg_AssertCCTMergeOnly),
866  "CCT::ANode::mergeDeep: adding not permitted");
867  } else if (!(mrgCtxt.flags() & MrgFlg_CCTMergeOnly)) {
868  DIAG_MsgIf(MERGE_ACTION /*(oFlag & Tree::OFlg_Debug)*/,
869  "CCT::ANode::mergeDeep: Adding:\n "
870  << y_child->toStringMe(Tree::OFlg_Debug));
871  y_child->unlink();
872 
873  effctLst1 = y_child->mergeDeep_fixInsert(x_newMetricBegIdx, mrgCtxt);
874 
875  y_child->link(x);
876  }
877  }
878  else {
879  // case 2: merge nodes
880  DIAG_MsgIf(MERGE_ACTION /*(oFlag & Tree::OFlg_Debug)*/,
881  "CCT::ANode::mergeDeep: Merging x <= y:\n"
882  << " x: " << x_child_dyn->toStringMe(Tree::OFlg_Debug)
883  << "\n y: " << y_child_dyn->toStringMe(Tree::OFlg_Debug));
884  MergeEffect effct =
885  x_child_dyn->mergeMe(*y_child_dyn, &mrgCtxt, x_newMetricBegIdx);
886  if (mrgCtxt.doPropagateEffects() && !effct.isNoop()) {
887  effctLst->push_back(effct);
888  }
889 
890  effctLst1 = x_child_dyn->mergeDeep(y_child, x_newMetricBegIdx, mrgCtxt,
891  oFlag);
892  }
893 
894  if (effctLst1 && !effctLst1->empty()) {
895  effctLst->splice(effctLst->end(), *effctLst1);
896  DIAG_MsgIf(0, MergeEffect::toString(*effctLst));
897  }
898  delete effctLst1;
899  }
900 
901  return effctLst;
902 }
903 
904 
907 {
908  ANode* x = this;
909 
910  // 1. copy y's metrics into x
911  MergeEffect effct = x->mergeMe(*y);
912 
913  // 2. copy y's children into x
914  for (ANodeChildIterator it(y); it.Current(); /* */) {
915  ANode* y_child = it.current();
916  it++; // advance iterator -- it is pointing at 'y_child'
917  y_child->unlink();
918  y_child->link(x);
919  }
920 
921  y->unlink();
922  delete y;
923 
924  return effct;
925 }
926 
927 
930  uint metricBegIdx, bool mayConflict)
931 {
932  ANode* x = this;
933 
934  uint x_end = metricBegIdx + y.numMetrics(); // open upper bound
935  if ( !(x_end <= x->numMetrics()) ) {
936  ensureMetricsSize(x_end);
937  }
938 
939  for (uint x_i = metricBegIdx, y_i = 0; x_i < x_end; ++x_i, ++y_i) {
940  x->metric(x_i) += y.metric(y_i);
941  }
942 
943  MergeEffect noopEffect;
944  return noopEffect;
945 }
946 
947 
949 ADynNode::mergeMe(const ANode& y, MergeContext* mrgCtxt, uint metricBegIdx, bool mayConflict)
950 {
951  // N.B.: Assumes ADynNode::isMergable() holds
952  ADynNode* x = this;
953 
954  const ADynNode* y_dyn = dynamic_cast<const ADynNode*>(&y);
955  DIAG_Assert(y_dyn, "ADynNode::mergeMe: " << DIAG_UnexpectedInput);
956 
957  MergeEffect effct = ANode::mergeMe(y, mrgCtxt, metricBegIdx);
958 
959  // merge cp-ids
960  if (hasMergeEffects(*x, *y_dyn)) {
961  // 1. Conflicting ids:
962  // => keep x's cpId; within y, translate [y_dyn->m_cpId ==> m_cpId]
963  effct.old_cpId = y_dyn->m_cpId;
964  effct.new_cpId = m_cpId;
965  }
966  else if (y_dyn->cpId() == HPCRUN_FMT_CCTNodeId_NULL) {
967  // 2. Trivial conflict: y's cpId is NULL; x's may or may not be NULL:
968  // => keep x's cpId.
969  }
970  else if (m_cpId == HPCRUN_FMT_CCTNodeId_NULL) {
971  // 3. Semi-trivial conflict: x's cpId is NULL, but y's is not
972  // => use y's cpId *if* it does not conflict with one already
973  // in x's tree.
974 
975  // Ignore the assertion iff the caller ensures no conflicting cpi-ids by setting mayConflict to false
976  if (mayConflict) {
977  // mayConflict is true, so we need to ensure uniqueness of cp-ids
978  DIAG_Assert(mrgCtxt, "ADynNode::mergeMe: potentially introducing cp-id conflicts; cannot verify without MergeContext!");
979  MergeContext::pair ret = mrgCtxt->ensureUniqueCPId(y_dyn->cpId());
980  m_cpId = ret.cpId;
981  DIAG_Assert(effct.isNoop(), DIAG_UnexpectedInput);
982  effct = ret.effect;
983  }
984  else {
985  // Since mayConflict is false, we can set m_cpId to y_dyn->cpId()
986  m_cpId = y_dyn->cpId();
987  }
988  }
989 
990  return effct;
991 }
992 
993 
994 ADynNode*
996 {
997  for (ANodeChildIterator it(this); it.Current(); ++it) {
998  ANode* x = it.current();
999 
1000  ADynNode* x_dyn = dynamic_cast<ADynNode*>(x);
1001  if (x_dyn) {
1002  // Base case: an ADynNode descendent
1003  if (ADynNode::isMergable(*x_dyn, y_dyn)) {
1004  return x_dyn;
1005  }
1006  }
1007  else {
1008  // Inductive case: some other type; find the first ADynNode descendents.
1009  ADynNode* x_dyn_descendent = x->findDynChild(y_dyn);
1010  if (x_dyn_descendent) {
1011  return x_dyn_descendent;
1012  }
1013  }
1014  }
1015  return NULL;
1016 }
1017 
1018 
1020 ANode::mergeDeep_fixInsert(int newMetrics, MergeContext& mrgCtxt)
1021 {
1022  // Assumes: While merging CCT::Tree y into CCT::Tree x, subtree
1023  // 'this', which used to live in 'y', has just been inserted into
1024  // 'x'.
1025 
1026  MergeEffectList* effctLst = new MergeEffectList();
1027 
1028  for (ANodeIterator it(this); it.Current(); ++it) {
1029  ANode* n = it.current();
1030  DIAG_MsgIf(MERGE_ACTION /*(oFlag & Tree::OFlg_Debug)*/,
1031  "CCT:ANode::mergeDeep_fixInsert: Adding:\n "
1032  << n->toStringMe(Tree::OFlg_Debug));
1033 
1034  // -----------------------------------------------------
1035  // 1. Ensure no cpId in subtree 'this' conflicts with an existing
1036  // cpId in CCT::Tree x.
1037  // -----------------------------------------------------
1038  ADynNode* n_dyn = dynamic_cast<ADynNode*>(n);
1039  if (n_dyn) {
1040  MergeContext::pair ret = mrgCtxt.ensureUniqueCPId(n_dyn->cpId());
1041  n_dyn->cpId(ret.cpId);
1042  if (!ret.effect.isNoop()) {
1043  effctLst->push_back(ret.effect);
1044  }
1045  }
1046 
1047  // -----------------------------------------------------
1048  // 2. Make space for the metrics of CCT::Tree x
1049  // -----------------------------------------------------
1050  n->insertMetricsBefore(newMetrics);
1051  }
1052 
1053  return effctLst;
1054 }
1055 
1056 //**********************************************************************
1057 //
1058 //**********************************************************************
1059 
1060 uint
1062 {
1063  // N.B.: use a sorted iterator to support hpcprof-mpi where we need
1064  // to ensure multiple processes obtain the same numbering.
1065 
1066  id(nextId);
1067  nextId++;
1068 
1070  it.current(); it++) {
1071  CCT::ANode* n = it.current();
1072  nextId = n->makeDensePreorderIds(nextId);
1073  }
1074 
1075  return nextId;
1076 }
1077 
1078 
1079 //**********************************************************************
1080 // ANode, etc: CodeName methods
1081 //**********************************************************************
1082 
1083 // NOTE: tallent: used for lush_cilkNormalize
1084 
1085 string
1087 {
1088  string self = ANodeTyToName(type()) + " "
1089  //+ GetFile() + ":"
1090  + StrUtil::toStr(begLine()) + "-" + StrUtil::toStr(endLine());
1091  return self;
1092 }
1093 
1094 
1095 string
1097 {
1098  string self = ANodeTyToName(type()) + " "
1099  + procName() + " @ "
1100  + fileName() + ":"
1101  + StrUtil::toStr(begLine()) + "-" + StrUtil::toStr(endLine());
1102  return self;
1103 }
1104 
1105 
1106 string
1108 {
1109  string nm = procName();
1110 
1111  CCT::Call* caller = ancestorCall();
1112  if (caller) {
1113  nm += " <= " + caller->nameDyn();
1114  }
1115 
1116  return nm;
1117 }
1118 
1119 
1120 //**********************************************************************
1121 // ANode, etc: Dump contents for inspection
1122 //**********************************************************************
1123 
1124 string
1125 ANode::toString(const Metric::Mgr *metricMgr, uint oFlags, const char* pfx) const
1126 {
1127  std::ostringstream os;
1128  writeXML(os, metricMgr, Metric::IData::npos, Metric::IData::npos, oFlags, pfx);
1129  return os.str();
1130 }
1131 
1132 
1133 string
1135 {
1136  string self;
1137  ANodeTy node_type = type();
1138  self = ANodeTyToName(node_type);
1139 
1140  SrcFile::ln lnBeg = begLine();
1141  string line = StrUtil::toStr(lnBeg);
1142  //SrcFile::ln lnEnd = endLine();
1143  //if (lnBeg != lnEnd) {
1144  // line += "-" + StrUtil::toStr(lnEnd);
1145  //}
1146 
1147  uint sId = (m_strct) ? m_strct->id() : 0;
1148  if (node_type == TyProcFrm || node_type == TyProc) {
1149  sId = getProcIdFromMap(sId);
1150  }
1151 
1152  self += " i" + xml::MakeAttrNum(m_id);
1153  self += " s" + xml::MakeAttrNum(sId) + " l" + xml::MakeAttrStr(line);
1154  if ((oFlags & Tree::OFlg_Debug) || (oFlags & Tree::OFlg_DebugAll)) {
1155  self += " strct" + xml::MakeAttrNum((uintptr_t)m_strct, 16);
1156  }
1157 
1158  return self;
1159 }
1160 
1161 
1162 string
1164 {
1165  char str[LUSH_ASSOC_INFO_STR_MIN_LEN];
1166  lush_assoc_info_sprintf(str, m_as_info);
1167  return string(str);
1168 }
1169 
1170 
1171 string
1173 {
1174  char str[LUSH_LIP_STR_MIN_LEN];
1175  lush_lip_sprintf(str, m_lip);
1176  return string(str);
1177 }
1178 
1179 
1180 string
1182 {
1183  string nm = "[assoc(" + assocInfo_str() + ") ip("
1184  + StrUtil::toStr(lmId_real()) + ", "
1185  + StrUtil::toStr(lmIP_real(), 16) + ") lip(" + lip_str() + ")]";
1186  return nm;
1187 }
1188 
1189 
1190 void
1191 ADynNode::writeDyn(std::ostream& o, uint GCC_ATTR_UNUSED oFlags,
1192  const char* pfx) const
1193 {
1194  string p(pfx);
1195 
1196  o << std::showbase;
1197 
1198  o << p << assocInfo_str()
1199  << hex << " [ip " << m_lmIP << ", " << dec << m_opIdx << "] "
1200  << hex << m_lip << " [lip " << lip_str() << "]" << dec;
1201 
1202  o << p << " [metrics";
1203  for (uint i = 0; i < numMetrics(); ++i) {
1204  o << " " << metric(i);
1205  }
1206  o << "]" << endl;
1207 }
1208 
1209 
1210 string
1211 Root::toStringMe(uint oFlags) const
1212 {
1213  string self = ANode::toStringMe(oFlags) + " n" + xml::MakeAttrStr(m_name);
1214  return self;
1215 }
1216 
1217 
1218 //**********************************************************************
1219 // Goal: This function is to avoid using different ID for the same file name.
1220 // During the writing of file dictionary table (see CallPath-Profile.cpp)
1221 // if a file has the exact absolute name with a previous file,
1222 // then we redirect its ID to the existing ID
1223 //
1224 // This function will check if any nodes refer to redirected ID or not.
1225 // if this is the case, it will return the existing file ID instead of
1226 // the node's file ID.
1227 //**********************************************************************
1228 static uint
1230 {
1231  uint id = file_id;
1232  if (Prof::m_mapFileIDs.find(file_id) != Prof::m_mapFileIDs.end()) {
1233  // the file ID should redirected to another file ID which has
1234  // exactly the same filename
1235  id = Prof::m_mapFileIDs[file_id];
1236  }
1237  return id;
1238 }
1239 
1240 string
1242 {
1243  string self = ANode::toStringMe(oFlags);
1244 
1245  if (m_strct) {
1246  uint lm_id = getLoadModuleFromMap(lmId());
1247  string lm_nm = xml::MakeAttrNum(lm_id);
1248 
1249  uint file_id = getFileIdFromMap(fileId());
1250  string fnm = xml::MakeAttrNum(file_id);
1251 
1252  uint proc_id = getProcIdFromMap(procId());
1253  string pnm = xml::MakeAttrNum(proc_id);
1254 
1255  if (oFlags & Tree::OFlg_DebugAll) {
1256  lm_nm = xml::MakeAttrStr(lmName());
1257  fnm = xml::MakeAttrStr(fileName());
1258  }
1259  if ( (oFlags & Tree::OFlg_Debug) || (oFlags & Tree::OFlg_DebugAll) ) {
1260  pnm = xml::MakeAttrStr(procNameDbg());
1261  }
1262 
1263  self += " lm" + lm_nm + " f" + fnm + " n" + pnm;
1264 
1265  // print the vma for debugging purpose
1266  int dbg_level = Diagnostics_GetDiagnosticFilterLevel();
1267  if (dbg_level > 2) {
1268  VMAIntervalSet &vma = m_strct->vmaSet();
1269  self += " v=\"" + vma.toString() + "\"";
1270  }
1271 
1272  if ((oFlags & CCT::Tree::OFlg_StructId) && structure() != NULL) {
1273  self += " str" + xml::MakeAttrNum(structure()->m_origId);
1274  }
1275 
1276  if (m_hpcrun_type > 0) {
1277  self += " t" + xml::MakeAttrNum(m_hpcrun_type) ;
1278  }
1279  }
1280 
1281  return self;
1282 }
1283 
1284 
1285 string
1286 Proc::toStringMe(uint oFlags) const
1287 {
1288  string self = ANode::toStringMe(oFlags);
1289 
1290  if (m_strct) {
1291  string lm_nm = xml::MakeAttrNum(lmId());
1292 
1293  uint file_id = getFileIdFromMap(fileId());
1294  string fnm = xml::MakeAttrNum(file_id);
1295 
1296  uint proc_id = getProcIdFromMap(procId());
1297  string pnm = xml::MakeAttrNum(proc_id);
1298 
1299  if (oFlags & Tree::OFlg_DebugAll) {
1300  lm_nm = xml::MakeAttrStr(lmName());
1301  fnm = xml::MakeAttrStr(fileName());
1302  pnm = xml::MakeAttrStr(procName());
1303  }
1304 
1305  self += " lm" + lm_nm + " f" + fnm + " n" + pnm;
1306 
1307  int dbg_level = Diagnostics_GetDiagnosticFilterLevel();
1308  if (dbg_level > 2) {
1309  VMAIntervalSet &vma = m_strct->vmaSet();
1310  self += " v=\"" + vma.toString() + "\"";
1311  }
1312  if (isAlien()) {
1313  self = self + " a=\"1\"";
1314  }
1315  if ((oFlags & CCT::Tree::OFlg_StructId) && structure() != NULL) {
1316  self += " str" + xml::MakeAttrNum(structure()->m_origId);
1317  }
1318  }
1319 
1320  return self;
1321 }
1322 
1323 
1324 string
1325 Loop::toStringMe(uint oFlags) const
1326 {
1327  uint file_id = getFileIdFromMap(fileId());
1328  string fnm = xml::MakeAttrNum(file_id);
1329  string self = ANode::toStringMe(oFlags) + " f" + fnm;
1330 
1331  int dbg_level = Diagnostics_GetDiagnosticFilterLevel();
1332  if (dbg_level > 2) {
1333  VMAIntervalSet &vma = m_strct->vmaSet();
1334  self += " v=\"" + vma.toString() + "\"";
1335  }
1336  if ((oFlags & CCT::Tree::OFlg_StructId) && structure() != NULL) {
1337  self += " str" + xml::MakeAttrNum(structure()->m_origId);
1338  }
1339 
1340  return self;
1341 }
1342 
1343 
1344 string
1345 Call::toStringMe(uint oFlags) const
1346 {
1347  string self = ANode::toStringMe(oFlags);
1348 
1349  if ((oFlags & Tree::OFlg_Debug) || (oFlags & Tree::OFlg_DebugAll)) {
1350  self += " n=\"" + nameDyn() + "\"";
1351  }
1352 
1353  int dbg_level = Diagnostics_GetDiagnosticFilterLevel();
1354  if (dbg_level > 2) {
1355  VMAIntervalSet &vma = m_strct->vmaSet();
1356  self += " v=\"" + vma.toString() + "\"";
1357  }
1358  if ((oFlags & CCT::Tree::OFlg_StructId) && structure() != NULL) {
1359  self += " str" + xml::MakeAttrNum(structure()->m_origId);
1360  }
1361 
1362  return self;
1363 }
1364 
1365 
1366 string
1367 Stmt::toStringMe(uint oFlags) const
1368 {
1369  string self = ANode::toStringMe(oFlags);
1370 
1371  // additional data-centric information
1372  if (m_node_alloc != NULL) {
1373  self += " " XML_ATTR_DATA_NODE_ALLOC + xml::MakeAttrNum(m_node_alloc->id());
1374  }
1375  if (m_start_address > 0) {
1376  self += " " XML_ATTR_DATA_START_MEM + xml::MakeAttrNum(m_start_address, 16);
1377  }
1378 
1379  if ((oFlags & Tree::OFlg_Debug) || (oFlags & Tree::OFlg_DebugAll)) {
1380  self += " n=\"" + nameDyn() + "\"";
1381  }
1382  if (hpcrun_fmt_doRetainId(cpId())) {
1383  self += " it" + xml::MakeAttrNum(cpId());
1384  }
1385 
1386  int dbg_level = Diagnostics_GetDiagnosticFilterLevel();
1387  if (dbg_level > 2) {
1388  VMAIntervalSet &vma = m_strct->vmaSet();
1389  self += " v=\"" + vma.toString() + "\"";
1390  }
1391  if ((oFlags & CCT::Tree::OFlg_StructId) && structure() != NULL) {
1392  self += " str" + xml::MakeAttrNum(structure()->m_origId);
1393  }
1394 
1395  return self;
1396 }
1397 
1398 
1399 
1400 std::ostream&
1401 ANode::writeXML(ostream& os, const Metric::Mgr *metricMgr,
1402  uint metricBeg, uint metricEnd,
1403  uint oFlags, const char* pfx) const
1404 {
1405  string indent = " ";
1406  if (oFlags & CCT::Tree::OFlg_Compressed) {
1407  pfx = "";
1408  indent = "";
1409  }
1410 
1411  bool doPost = writeXML_pre(os, metricMgr, metricBeg, metricEnd, oFlags, pfx);
1412  string prefix = pfx + indent;
1414  it.current(); it++) {
1415  ANode* n = it.current();
1416  n->writeXML(os, metricMgr, metricBeg, metricEnd, oFlags, prefix.c_str());
1417  }
1418  if (doPost) {
1419  writeXML_post(os, oFlags, pfx);
1420  }
1421  return os;
1422 }
1423 
1424 
1425 std::ostream&
1427  const Metric::Mgr *metricMgr,
1428  uint metricBeg, uint metricEnd,
1429  uint oFlags, const char* pfx) const
1430 {
1431  string indent = " ";
1432  if (oFlags & CCT::Tree::OFlg_Compressed) {
1433  pfx = "";
1434  indent = "";
1435  }
1436 
1437  ANode *parent = this->parent();
1438  if (parent) {
1439  parent->writeXML_path(os, metricMgr, metricBeg, metricEnd, oFlags, pfx);
1440  }
1441 
1442  writeXML_pre(os, metricMgr, metricBeg, metricEnd, oFlags, pfx);
1443  return os;
1444 }
1445 
1446 
1447 std::ostream&
1448 ANode::dump(const Metric::Mgr *metricMgr, ostream& os, uint oFlags, const char* pfx) const
1449 {
1450  writeXML(os, metricMgr, Metric::IData::npos, Metric::IData::npos, oFlags, pfx);
1451  return os;
1452 }
1453 
1454 
1455 void
1456 ANode::adump(const Metric::Mgr *metricMgr) const
1457 {
1458  writeXML_path(std::cerr, metricMgr, Metric::IData::npos, Metric::IData::npos,
1459  Tree::OFlg_DebugAll, "");
1460 }
1461 
1462 
1463 void
1464 ANode::ddump(const Metric::Mgr *metricMgr) const
1465 {
1466  writeXML(std::cerr, metricMgr, Metric::IData::npos, Metric::IData::npos,
1467  Tree::OFlg_DebugAll, "");
1468 }
1469 
1470 
1471 void
1473 {
1474  string str = toStringMe(Tree::OFlg_DebugAll);
1475  std::cerr << str;
1476 }
1477 
1478 
1479 bool
1480 ANode::writeXML_pre(ostream& os, const Metric::Mgr *metricMgr, uint metricBeg, uint metricEnd,
1481  uint oFlags, const char* pfx) const
1482 {
1483  bool doTag = (type() != TyRoot);
1484  bool doMetrics = ((oFlags & Tree::OFlg_LeafMetricsOnly)
1485  ? isLeaf() && hasMetrics(metricBeg, metricEnd)
1486  : hasMetrics(metricBeg, metricEnd));
1487  bool isXMLLeaf = isLeaf() && !doMetrics;
1488 
1489  // 1. Write element name
1490  if (doTag) {
1491  if (isXMLLeaf) {
1492  os << pfx << "<" << toStringMe(oFlags) << "/>\n";
1493  }
1494  else {
1495  os << pfx << "<" << toStringMe(oFlags) << ">\n";
1496  }
1497  }
1498 
1499  // 2. Write associated metrics
1500  if (doMetrics) {
1501  writeMetricsXML(os, metricMgr, metricBeg, metricEnd, oFlags, pfx);
1502  os << "\n";
1503  }
1504 
1505  return !isXMLLeaf; // whether to execute writeXML_post()
1506 }
1507 
1508 
1509 void
1510 ANode::writeXML_post(ostream& os, uint GCC_ATTR_UNUSED oFlags,
1511  const char* pfx) const
1512 {
1513  bool doTag = (type() != ANode::TyRoot);
1514  if (!doTag) {
1515  return;
1516  }
1517 
1518  os << pfx << "</" << ANodeTyToName(type()) << ">\n";
1519 }
1520 
1521 
1522 //**********************************************************************
1523 //
1524 //**********************************************************************
1525 
1526 
1528 {
1529  if (x->begLine() == y->begLine()) {
1530  // Given two ANode's with identical endpoints consider two
1531  // special cases:
1532  bool endLinesEqual = (x->endLine() == y->endLine());
1533 
1534  // 1. Otherwise: rank a leaf node before a non-leaf node
1535  if (endLinesEqual && !(x->isLeaf() && y->isLeaf())) {
1536  if (x->isLeaf()) { return -1; } // x < y
1537  else if (y->isLeaf()) { return 1; } // x > y
1538  }
1539 
1540  // 2. General case
1541  return SrcFile::compare(x->endLine(), y->endLine());
1542  }
1543  else {
1544  return SrcFile::compare(x->begLine(), y->begLine());
1545  }
1546 }
1547 
1548 
1549 } // namespace CCT
1550 
1551 } // namespace Prof
1552 
bool verifyUniqueCPIds()
Definition: CCT-Tree.cpp:258
std::ostream & writeXML(std::ostream &os, const Metric::Mgr *metricMgr, uint metricBeg=Metric::IData::npos, uint metricEnd=Metric::IData::npos, uint oFlags=0, const char *pfx="") const
Struct::ACodeNode * structure() const
Definition: CCT-Tree.hpp:401
Metric::AExpr * expr() const
void aggregateMetricsIncl(uint mBegId, uint mEndId)
Definition: CCT-Tree.cpp:458
static uint getLoadModuleFromMap(uint lm_id)
Definition: CCT-Tree.cpp:135
virtual MergeEffect mergeMe(const ANode &y, MergeContext *mrgCtxt=NULL, uint metricBegIdx=0, bool mayConflict=true)
Definition: CCT-Tree.cpp:949
void pruneByMetrics(const Metric::Mgr &mMgr, const VMAIntervalSet &ivalset, const ANode *root, double thresholdPct, uint8_t *prunedNodes=NULL)
Definition: CCT-Tree.cpp:691
virtual std::string toStringMe(uint oFlags=0) const
Definition: CCT-Tree.cpp:1286
ANode * parent() const
Definition: CCT-Tree.hpp:434
std::list< MergeEffect > * mergeDeep(ANode *y, uint x_numMetrics, MergeContext &mrgCtxt, uint oFlag=0)
Definition: CCT-Tree.cpp:824
static struct perf_mem_metric metric
Definition: pmu_x86.c:114
virtual std::string toStringMe(uint oFlags=0) const
Definition: CCT-Tree.cpp:1134
static ANodeTy IntToANodeType(long i)
Definition: CCT-Tree.cpp:334
unsigned int ln
Definition: SrcFile.hpp:66
#define DIAG_If(level)
Definition: diagnostics.h:134
virtual ~Tree()
Definition: CCT-Tree.cpp:156
CCT::ADynNode * findDynChild(const ADynNode &y_dyn)
Definition: CCT-Tree.cpp:995
My_t::const_iterator const_iterator
int find(char s1[], char s2[])
Definition: CStrUtil.cpp:177
string toStr(const int x, int base)
Definition: StrUtil.cpp:243
static bool hpcrun_fmt_doRetainId(uint32_t id)
Definition: hpcrun-fmt.h:502
#define MERGE_ACTION
static uint getProcIdFromMap(uint proc_id)
Definition: CCT-Tree.cpp:121
virtual double evalNF(Metric::IData &mdata) const
std::list< MergeEffect > MergeEffectList
Definition: CCT-Merge.hpp:126
ANode * root() const
Definition: CCT-Tree.hpp:160
void computeMetricsIncrMe(const Metric::Mgr &mMgr, uint mBegId, uint mEndId, Metric::AExprIncr::FnTy fn)
Definition: CCT-Tree.cpp:662
virtual double combine(Metric::IData &mdata) const =0
SrcFile::ln endLine() const
Definition: CCT-Tree.hpp:417
static bool deleteChaff(ANode *x, uint8_t *deletedNodes=NULL)
Definition: CCT-Tree.cpp:787
static bool isMergable(const ADynNode &x, const ADynNode &y)
Definition: CCT-Tree.hpp:931
ANode * findNode(uint nodeId) const
Definition: CCT-Tree.cpp:243
#define dyn_cast_return(base, derived, expr)
Definition: CCT-Tree.cpp:354
int Diagnostics_GetDiagnosticFilterLevel()
Definition: diagnostics.cpp:87
static uint getFileIdFromMap(uint file_id)
Definition: CCT-Tree.cpp:1229
std::string nameDyn() const
Definition: CCT-Tree.cpp:1181
double metric(size_t mId) const
Call * ancestorCall() const
Definition: CCT-Tree.cpp:426
const StringSet & traceFileNameSet() const
VMA beg() const
virtual std::string toStringMe(uint oFlags=0) const
Definition: CCT-Tree.cpp:1211
bool writeXML_pre(std::ostream &os, const Metric::Mgr *metricMgr, uint metricBeg=Metric::IData::npos, uint metricEnd=Metric::IData::npos, uint oFlags=0, const char *pfx="") const
#define GUARD_NAME
Definition: dictionary.h:50
void ddump(const Metric::Mgr *metricMgr) const
Definition: CCT-Tree.cpp:1464
void pruneChildrenByNodeId(const uint8_t *prunedNodes)
Definition: CCT-Tree.cpp:765
bool isPrimarySynthRoot() const
Definition: CCT-Tree.hpp:906
static void pruneByNodeId(ANode *&x, const uint8_t *prunedNodes)
void zeroMetrics(uint mBegId, uint mEndId)
std::string procNameDbg() const
Definition: CCT-Tree.cpp:1107
void insertMetricsBefore(size_t numMetrics)
void computeMetrics(const Metric::Mgr &mMgr, uint mBegId, uint mEndId, bool doFinal)
Definition: CCT-Tree.cpp:605
int compare(SrcFile::ln x, SrcFile::ln y)
Definition: SrcFile.hpp:80
void writeDyn(std::ostream &os, uint oFlags=0, const char *prefix="") const
Definition: CCT-Tree.cpp:1191
const char * lush_assoc_info_sprintf(char *str, lush_assoc_info_t as_info)
Definition: lush-support.c:101
Proc * ancestorProc() const
Definition: CCT-Tree.cpp:412
uint numMetrics() const
virtual double accumulate(Metric::IData &mdata) const =0
std::string MakeAttrStr(const char *x, int flags=ESC_TRUE)
Definition: xml.hpp:216
virtual double finalize(Metric::IData &mdata) const =0
#define DIAG_MsgIf(ifexpr,...)
Definition: diagnostics.h:236
const char * lush_lip_sprintf(char *str, const lush_lip_t *x)
Definition: lush-support.c:122
std::string lip_str() const
Definition: CCT-Tree.cpp:1172
uint size() const
Definition: Metric-Mgr.hpp:153
static bool hpcrun_fmt_node_type_root(uint16_t type)
Definition: hpcrun-fmt.h:587
static char * prefix
Definition: common.c:164
static int cmpByStructureInfo(const void *x, const void *y)
uint makeDensePreorderIds(uint nextId)
Definition: CCT-Tree.cpp:1061
#define XML_ATTR_DATA_START_MEM
Definition: CCT-Tree.cpp:103
virtual std::string toString(const Metric::Mgr *metricMgr, uint oFlags=0, const char *pfx="") const
Definition: CCT-Tree.cpp:1125
uint cpId() const
Definition: CCT-Tree.hpp:791
std::string assocInfo_str() const
Definition: CCT-Tree.cpp:1163
MergeContext::pair ensureUniqueCPId(uint curId)
Definition: CCT-Merge.hpp:216
unsigned int uint
Definition: uint.h:124
static uint s_nextUniqueId
Definition: CCT-Tree.hpp:691
virtual std::string codeName() const
Definition: CCT-Tree.cpp:1086
#define LUSH_LIP_STR_MIN_LEN
Definition: lush-support.h:356
MergeEffectList * merge(const Tree *y, uint x_newMetricBegIdx, uint mrgFlag=0, uint oFlag=0)
Definition: CCT-Tree.cpp:166
void adump(const Metric::Mgr *metricMgr) const
Definition: CCT-Tree.cpp:1456
virtual std::string toStringMe(uint oFlags=0) const
Definition: CCT-Tree.cpp:1325
void zeroMetricsDeep(uint mBegId, uint mEndId)
Definition: CCT-Tree.cpp:444
std::ostream & dump(const Metric::Mgr *metricMgr, std::ostream &os=std::cerr, uint oFlags=0) const
Definition: CCT-Tree.cpp:293
static const std::string NodeNames[TyNUMBER]
Definition: CCT-Tree.hpp:321
virtual MergeEffect mergeMe(const ANode &y, MergeContext *mrgCtxt=NULL, uint metricBegIdx=0, bool mayConflict=true)
Definition: CCT-Tree.cpp:929
std::ostream & writeXML_path(std::ostream &os, const Metric::Mgr *metricMgr, uint metricBeg=Metric::IData::npos, uint metricEnd=Metric::IData::npos, uint oFlags=0, const char *pfx="") const
Definition: CCT-Tree.cpp:1426
std::map< uint, ANode * > NodeIdToANodeMap
Definition: CCT-Tree.hpp:248
void ddump(const Metric::Mgr *metricMgr) const
Definition: CCT-Tree.cpp:301
virtual double eval(const Metric::IData &mdata) const =0
ANode * ancestor(ANodeTy tp) const
Definition: CCT-Tree.cpp:365
void link(NonUniformDegreeTreeNode *parent)
void computeMetricsIncr(const Metric::Mgr &mMgr, uint mBegId, uint mEndId, Metric::AExprIncr::FnTy fn)
Definition: CCT-Tree.cpp:644
const CallPath::Profile * m_metadata
Definition: CCT-Tree.hpp:254
virtual const std::string & name() const
int ANodeLineComp(ANode *x, ANode *y)
Definition: CCT-Tree.cpp:1527
virtual double initializeSrc(Metric::IData &mdata) const =0
VMA end() const
std::ostream & dump(const Metric::Mgr *metricMgr, std::ostream &os=std::cerr, uint oFlags=0, const char *pfx="") const
std::pair< iterator, bool > insert(const VMA beg, const VMA end)
std::string toString() const
ProcFrm * ancestorProcFrm() const
Definition: CCT-Tree.cpp:405
std::string toString(const char *pfx="") const
Definition: CCT-Merge.cpp:121
#define MERGE_ERROR
ADescTy type() const
std::set< uint > CPIdSet
Definition: CCT-Merge.hpp:167
const char * DIAG_UnexpectedInput
void aggregateMetricsExcl(uint mBegId, uint mEndId)
Definition: CCT-Tree.cpp:505
std::map< uint, uint > m_mapProcIDs
double demandMetric(size_t mId, size_t size=0) const
const CallPath::Profile * metadata() const
Definition: CCT-Tree.hpp:172
uint makeDensePreorderIds()
Definition: CCT-Tree.cpp:232
#define XML_ATTR_DATA_NODE_ALLOC
Definition: CCT-Tree.cpp:102
virtual std::string toStringMe(uint oFlags=0) const
Definition: CCT-Tree.cpp:1367
virtual std::string codeName() const
Definition: CCT-Tree.cpp:1096
void flags(uint mrgFlag)
Definition: CCT-Merge.hpp:176
virtual std::string toStringMe(uint oFlags=0) const
Definition: CCT-Tree.cpp:1345
Tree(const CallPath::Profile *metadata)
Definition: CCT-Tree.cpp:148
#define NULL
Definition: ElfHelper.cpp:85
virtual std::string toStringMe(uint oFlags=0) const
Definition: CCT-Tree.cpp:1241
std::string MakeAttrNum(int x)
Definition: xml.hpp:228
Stmt * ancestorStmt() const
Definition: CCT-Tree.cpp:433
void pruneCCTByNodeId(const uint8_t *prunedNodes)
Definition: CCT-Tree.cpp:221
Metric::ADesc * metric(uint i)
Definition: Metric-Mgr.hpp:131
Root * ancestorRoot() const
Definition: CCT-Tree.cpp:393
uint id() const
Definition: CCT-Tree.hpp:383
std::ostream & writeXML(std::ostream &os, const Metric::Mgr *metricMgr, uint metricBeg=Metric::IData::npos, uint metricEnd=Metric::IData::npos, uint oFlags=0) const
Definition: CCT-Tree.cpp:281
void computeMetricsMe(const Metric::Mgr &mMgr, uint mBegId, uint mEndId, bool doFinal)
Definition: CCT-Tree.cpp:623
#define LUSH_ASSOC_INFO_STR_MIN_LEN
Definition: lush-support.h:295
NonUniformDegreeTreeNode * Parent() const
SrcFile::ln begLine() const
Definition: CCT-Tree.hpp:413
static std::string BOGUS
Definition: CCT-Tree.hpp:1099
#define DIAG_Die(...)
Definition: diagnostics.h:267
#define GCC_ATTR_UNUSED
Definition: gcc-attr.h:80
<!-- ********************************************************************--> 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
MergeContext * m_mergeCtxt
Definition: CCT-Tree.hpp:261
ANode * m_root
Definition: CCT-Tree.hpp:253
static const std::string & ANodeTyToName(ANodeTy tp)
Definition: CCT-Tree.cpp:327
void ddumpMe() const
Definition: CCT-Tree.cpp:1472
virtual NonUniformDegreeTreeNode * Current() const
Loop * ancestorLoop() const
Definition: CCT-Tree.cpp:419
ANodeTy type() const
Definition: CCT-Tree.hpp:374
MergeEffectList * mergeDeep_fixInsert(int newMetrics, MergeContext &mrgCtxt)
Definition: CCT-Tree.cpp:1020
void writeXML_post(std::ostream &os, uint oFlags=0, const char *pfx="") const
Metric::AExprIncr * expr() const
MergeEffect merge(ANode *y)
Definition: CCT-Tree.cpp:906
virtual double initialize(Metric::IData &mdata) const =0
NodeIdToANodeMap * m_nodeidMap
Definition: CCT-Tree.hpp:258
std::map< uint, uint > m_mapFileIDs
#define HPCRUN_FMT_CCTNodeId_NULL
Definition: hpcrun-fmt.h:497
std::map< uint, uint > m_pairFakeLoadModule
const ln ln_NULL
Definition: SrcFile.hpp:67
virtual NonUniformDegreeTreeNode * Current() const
static const uint npos