HPCToolkit
CallPath-MetricComponentsFact.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 
64 #include <string>
65 using std::string;
66 
67 #include <typeinfo>
68 
69 
70 //*************************** User Include Files ****************************
71 
73 
75 
77 #include <lib/support/Logic.hpp>
78 
79 //*************************** Forward Declarations ***************************
80 
81 
82 //****************************************************************************
83 //
84 //****************************************************************************
85 
86 namespace Analysis {
87 
88 namespace CallPath {
89 
90 //***************************************************************************
91 
92 const std::string MetricComponentsFact::s_sum = ":Sum";
93 const std::string MetricComponentsFact::s_cfvar = ":CfVar";
94 
95 
96 // Assumes: metrics are of type Metric::SampledDesc and values are
97 // only at leaves (CCT::Stmt)
98 void
100 {
101  using namespace Prof;
102 
103  // ------------------------------------------------------------
104  // Create destination metric descriptors and mapping from source
105  // metrics to destination metrics
106  // ------------------------------------------------------------
107  std::vector<uint> metricSrcIds;
108  std::vector<uint> metricDstIds;
109 
110  Metric::Mgr* metricMgr = prof.metricMgr();
111 
112  uint numMetrics_orig = metricMgr->size();
113  for (uint mId = 0; mId < numMetrics_orig; ++mId) {
114  Metric::ADesc* m = metricMgr->metric(mId);
116  DIAG_Assert(typeid(*m) == typeid(Metric::SampledDesc), DIAG_UnexpectedInput << "temporary sanity check");
117 
119  metricSrcIds.push_back(m->id());
120 
121  Metric::ADesc* m_new = m->clone();
122  m_new->nameBase("overhead");
123  m_new->description("parallel overhead");
124 
125  metricMgr->insert(m_new);
126  DIAG_Assert(m_new->id() >= numMetrics_orig, "Currently, we assume new metrics are added at the end of the metric vector.");
127 
128  metricDstIds.push_back(m_new->id());
129  }
130  }
131 
132  if (metricSrcIds.empty()) {
133  return;
134  }
135 
136  // ------------------------------------------------------------
137  // Create values for metric components
138  // ------------------------------------------------------------
139  make(prof.cct()->root(), metricSrcIds, metricDstIds, false);
140 }
141 
142 
143 // make: Assumes source metrics are of type "raw" Metric::SampledDesc,
144 // which means that metric values are exclusive and are only at leaves
145 // (CCT::Stmt).
146 //
147 // Since metric values are exclusive we effectively move metric values
148 // for whole subtrees.
149 void
151  const std::vector<uint>& m_src,
152  const std::vector<uint>& m_dst,
153  bool isSeparableCtxt)
154 {
155  if (!node) { return; }
156 
157  // ------------------------------------------------------------
158  // Visit CCT::Stmt nodes:
159  // ------------------------------------------------------------
160  if (isSeparableCtxt && (typeid(*node) == typeid(Prof::CCT::Stmt))) {
161  Prof::CCT::Stmt* stmt = static_cast<Prof::CCT::Stmt*>(node);
162  for (uint i = 0; i < m_src.size(); ++i) {
163  uint mId_src = m_src[i];
164  uint mId_dst = m_dst[i];
165 
166  if (stmt->hasMetric(mId_src)) {
167  double mval = stmt->metric(mId_src);
168  stmt->demandMetric(mId_dst) += mval;
169  stmt->metric(mId_src) = 0.0;
170  }
171  }
172  }
173 
174  // ------------------------------------------------------------
175  // Recur
176  // ------------------------------------------------------------
177 
178  // Note: once set, isSeparableCtxt should remain true for all descendents
179  bool isSeparableCtxt_nxt = isSeparableCtxt;
180  if (!isSeparableCtxt && dynamic_cast<Prof::CCT::AProcNode*>(node)) {
181  Prof::CCT::AProcNode* x = static_cast<Prof::CCT::AProcNode*>(node);
182  isSeparableCtxt_nxt = isSeparable(x);
183  }
184 
185  for (Prof::CCT::ANodeChildIterator it(node); it.Current(); ++it) {
186  Prof::CCT::ANode* x = it.current();
187  make(x, m_src, m_dst, isSeparableCtxt_nxt);
188  }
189 }
190 
191 
192 void
194 {
195  const string& nm = mdesc->name();
196  if (nm.find("PAPI_TOT_CYC") == 0) {
197  mdesc->nameBase("work (cyc)");
198  }
199  else if (nm.find("WALLCLOCK") == 0) {
200  mdesc->nameBase("work (us)");
201  }
202  else {
204  }
205 }
206 
207 
208 //***************************************************************************
209 //
210 //***************************************************************************
211 
212 // Cray XT4, XT5
213 const string MPIBlameShiftIdlenessFact::s_tag1 = "MPIDI_CRAY_Progress_wait";
214 
215 // IBM BG/P
216 const string MPIBlameShiftIdlenessFact::s_tag2 = "MPID_Progress_wait";
217 
218 // Intel/Infiniband
219 const string MPIBlameShiftIdlenessFact::s_tag3 = "MPIDI_CH3I_Progress";
220 
221 
222 static bool
224 {
225  static const string mpistr1 = "MPI";
226  static const string mpistr2 = "PMPI";
227  const string& x_nm = x->procName();
228  return (x_nm.compare(0, mpistr1.length(), mpistr1) == 0 ||
229  x_nm.compare(0, mpistr2.length(), mpistr2) == 0);
230 }
231 
232 
233 bool
235 {
236  const string& x_nm = x->procName();
237  bool fnd = (x_nm.find(s_tag1) != string::npos ||
238  x_nm.find(s_tag2) != string::npos ||
239  x_nm.find(s_tag3) != string::npos);
240  return fnd;
241 }
242 
243 
244 // make: ...temporary holding pattern...
245 void
247 {
248  using namespace Prof;
249 
250  // ------------------------------------------------------------
251  // Create destination metric descriptors and mapping from source
252  // metrics to destination metrics
253  // ------------------------------------------------------------
254  std::vector<uint> metricSrcIds;
255  std::vector<uint> metricBalanceIds;
256  std::vector<uint> metricImbalInclIds, metricImbalExclIds;
257  std::vector<uint> metricIdleInclIds;
258 
259  Metric::Mgr* metricMgr = prof.metricMgr();
260 
261  uint numMetrics_orig = metricMgr->size();
262  for (uint mId = 0; mId < numMetrics_orig; ++mId) {
263  Metric::ADesc* m = metricMgr->metric(mId);
264 
265  // find main source metric
268  && m->type() == Metric::ADesc::TyIncl
269  && m->isVisible() /* not a temporary */) {
270 
273  metricSrcIds.push_back(m->id());
274 
275  // FIXME: For now we use only Metric::ADesc::DerivedIncrDesc()
276  // We should also support Metric::ADesc::DerivedDesc()
277  DIAG_Assert(typeid(*m) == typeid(Metric::DerivedIncrDesc), DIAG_UnexpectedInput);
278 
279  Metric::DerivedIncrDesc* m_imbalIncl =
280  static_cast<Metric::DerivedIncrDesc*>(m->clone());
281  m_imbalIncl->nameBase("imbalance" + s_sum);
282  m_imbalIncl->description("imbalance for MPI SPMD executions");
283  m_imbalIncl->expr(new Metric::SumIncr(Metric::IData::npos, // FIXME:Sum
284  Metric::IData::npos));
285 
286  Metric::DerivedIncrDesc* m_imbalExcl =
287  static_cast<Metric::DerivedIncrDesc*>(m_imbalIncl->clone());
288  m_imbalExcl->type(Metric::ADesc::TyExcl);
289  m_imbalExcl->expr(new Metric::SumIncr(Metric::IData::npos,
290  Metric::IData::npos));
291  m_imbalIncl->partner(m_imbalExcl);
292  m_imbalExcl->partner(m_imbalIncl);
293 
294  Metric::DerivedIncrDesc* m_idleIncl =
295  static_cast<Metric::DerivedIncrDesc*>(m->clone());
296  m_idleIncl->nameBase("idleness" + s_sum);
297  m_idleIncl->description("idleness for MPI executions");
298  m_idleIncl->partner(NULL);
299  m_idleIncl->expr(new Metric::SumIncr(Metric::IData::npos, // FIXME:Sum
300  Metric::IData::npos));
301 
302  metricMgr->insert(m_imbalIncl);
303  metricMgr->insert(m_imbalExcl);
304  metricMgr->insert(m_idleIncl);
305 
306  m_imbalIncl->expr()->accumId(m_imbalIncl->id());
307  m_imbalExcl->expr()->accumId(m_imbalExcl->id());
308  m_idleIncl->expr()->accumId(m_idleIncl->id());
309 
310  DIAG_Assert(m_imbalIncl->id() >= numMetrics_orig && m_imbalExcl->id() >= numMetrics_orig, "Currently, we assume new metrics are added at the end of the metric vector.");
311 
312  metricImbalInclIds.push_back(m_imbalIncl->id());
313  metricImbalExclIds.push_back(m_imbalExcl->id());
314  metricIdleInclIds.push_back(m_idleIncl->id());
315  }
316 
317  // find secondary source metric
320  && m->type() == Metric::ADesc::TyIncl
321  && m->isVisible() /* not a temporary */) {
324  metricBalanceIds.push_back(m->id());
325  }
326  }
327 
328  DIAG_Assert(metricSrcIds.size() == metricBalanceIds.size(), DIAG_UnexpectedInput);
329 
330  if (metricSrcIds.empty()) {
331  return;
332  }
333 
334  // ------------------------------------------------------------
335  // Create values for metric components
336  // ------------------------------------------------------------
337 
338  // Note that metrics are non-finalized!
339  CCT::ANode* cctRoot = prof.cct()->root();
340 
341  uint metricBalancedId = metricBalanceIds[0];
342  Metric::AExprIncr* metricBalancedExpr = dynamic_cast<Metric::DerivedIncrDesc*>(metricMgr->metric(metricBalancedId))->expr();
343 
344  Metric::IData cctRoot_mdata(*cctRoot);
345  metricBalancedExpr->finalize(cctRoot_mdata);
346 
347  double balancedThreshold = 1.2 * cctRoot_mdata.demandMetric(metricBalancedId);
348 
349  makeMetrics(cctRoot, metricSrcIds,
350  metricImbalInclIds, metricImbalExclIds, metricIdleInclIds,
351  metricBalancedId, metricBalancedExpr, balancedThreshold,
352  NULL, NULL);
353 
354 
355  VMAIntervalSet metricDstInclIdSet;
356  for (uint i = 0; i < metricImbalInclIds.size(); ++i) {
357  uint mId = metricImbalInclIds[i];
358  metricDstInclIdSet.insert(VMAInterval(mId, mId + 1)); // [ )
359 
360  mId = metricIdleInclIds[i];
361  metricDstInclIdSet.insert(VMAInterval(mId, mId + 1)); // [ )
362  }
363 
364  cctRoot->aggregateMetricsIncl(metricDstInclIdSet);
365 }
366 
367 
368 void
370  const std::vector<uint>& m_src,
371  const std::vector<uint>& m_imbalIncl,
372  const std::vector<uint>& m_imbalExcl,
373  const std::vector<uint>& m_idleIncl,
374  uint mId_bal,
375  Prof::Metric::AExprIncr* balancedExpr,
376  double balancedThreshold,
377  Prof::CCT::ANode* balancedFrm,
378  Prof::CCT::ANode* balancedNode)
379 {
380  using namespace Prof;
381 
382  if (!node) { return; }
383 
384  // -------------------------------------------------------
385  // Shift blame for waiting at 'node' (use non-finalized metric values)
386  // -------------------------------------------------------
387  bool isFrame = (typeid(*node) == typeid(Prof::CCT::ProcFrm));
388 
389  if (isFrame && isSeparable(static_cast<Prof::CCT::ProcFrm*>(node))) {
390  DIAG_Assert(balancedNode, DIAG_UnexpectedInput);
391 
392  CCT::ProcFrm* balancedNodeFrm = balancedNode->ancestorProcFrm();
393 
394  for (uint i = 0; i < m_src.size(); ++i) {
395  uint mId_src = m_src[i];
396 
397  uint mId_imbalIncl = m_imbalIncl[i];
398  uint mId_imbalExcl = m_imbalExcl[i];
399  uint mId_idleIncl = m_idleIncl[i];
400 
401  double mval = node->demandMetric(mId_src);
402 
403  balancedNode->demandMetric(mId_imbalIncl) += mval; // FIXME: combine fn
404  balancedNode->demandMetric(mId_imbalExcl) += mval; // FIXME: combine fn
405 
406  if (balancedNode != balancedFrm && balancedNodeFrm == balancedFrm) {
407  balancedFrm->demandMetric(mId_imbalExcl) += mval; // FIXME: combine fn
408  }
409 
410  node->demandMetric(mId_idleIncl) += mval; // FIXME: combine fn
411  }
412 
413  return; // do not recur down this subtree
414  }
415 
416  // -------------------------------------------------------
417  // Find balanced nodes (use finalized metric values)
418  // -------------------------------------------------------
419  Metric::IData node_mdata(*node);
420  balancedExpr->finalize(node_mdata);
421 
422  bool isComp = (!isFrame ||
423  (/*isFrame &&*/
424  !isMPIFrame(static_cast<Prof::CCT::ProcFrm*>(node))));
425  bool isBalanced = (node_mdata.demandMetric(mId_bal) <= balancedThreshold);
426 
427  CCT::ANode* balancedFrmNxt = ((isFrame && isBalanced && isComp) ?
428  node : balancedFrm);
429  CCT::ANode* balancedNodeNxt = (isBalanced && isComp) ? node : balancedNode;
430 
431  // ------------------------------------------------------------
432  // Recur
433  // ------------------------------------------------------------
434  for (Prof::CCT::ANodeChildIterator it(node); it.Current(); ++it) {
435  Prof::CCT::ANode* x = it.current();
436  makeMetrics(x, m_src, m_imbalIncl, m_imbalExcl, m_idleIncl,
437  mId_bal, balancedExpr, balancedThreshold,
438  balancedFrmNxt, balancedNodeNxt);
439  }
440 }
441 
442 
443 //***************************************************************************
444 //
445 //***************************************************************************
446 
447 const string PthreadOverheadMetricFact::s_tag = "/libpthread";
448 
449 
450 bool
452 {
453  const string& x_lm_nm = x->lmName();
454  if (x_lm_nm.length() >= s_tag.length()) {
455  return (x_lm_nm.find(s_tag) != string::npos);
456  }
457  return false;
458 }
459 
460 
461 //***************************************************************************
462 //
463 //***************************************************************************
464 
465 const string CilkOverheadMetricFact::s_tag = "lush:parallel-overhead";
466 
467 
468 bool
470 {
471  const string& x_fnm = x->fileName();
472  if (x_fnm.length() >= s_tag.length()) {
473  size_t tag_beg = x_fnm.length() - s_tag.length();
474  return (x_fnm.compare(tag_beg, s_tag.length(), s_tag) == 0);
475  }
476  return false;
477 }
478 
479 
480 //***************************************************************************
481 
482 } // namespace CallPath
483 
484 } // namespace Analysis
485 
486 //***************************************************************************
static void convertToWorkMetric(Prof::Metric::ADesc *mdesc)
void aggregateMetricsIncl(uint mBegId, uint mEndId)
Definition: CCT-Tree.cpp:458
ADesc * partner() const
bool insert(Metric::ADesc *m)
Definition: Metric-Mgr.cpp:460
bool isVisible() const
const char * DIAG_Unimplemented
ANode * root() const
Definition: CCT-Tree.hpp:160
virtual void make(Prof::CallPath::Profile &prof)
static bool isTimeMetric(const Prof::Metric::ADesc *mdesc)
double metric(size_t mId) const
cct_node_t * node
Definition: cct.c:128
std::string name() const
virtual double finalize(Metric::IData &mdata) const =0
uint size() const
Definition: Metric-Mgr.hpp:153
const std::string & nameBase() const
unsigned int uint
Definition: uint.h:124
static void makeMetrics(Prof::CallPath::Profile &prof, const Analysis::Args &args, const Analysis::Util::NormalizeProfileArgs_t &nArgs)
static bool isMPIFrame(const Prof::CCT::ProcFrm *x)
ComputedTy computedType() const
static bool isDerivedMetric(const Prof::Metric::ADesc *mdesc, const std::string &type)
virtual const std::string & procName() const
Definition: CCT-Tree.hpp:1086
bool hasMetric(size_t mId) const
virtual const std::string & lmName() const
Definition: CCT-Tree.hpp:1054
virtual void make(Prof::CallPath::Profile &prof)
std::pair< iterator, bool > insert(const VMA beg, const VMA end)
ProcFrm * ancestorProcFrm() const
Definition: CCT-Tree.cpp:405
virtual ADesc * clone() const
ADescTy type() const
void makeMetrics(Prof::CCT::ANode *node, const std::vector< uint > &m_src, const std::vector< uint > &m_imbalIncl, const std::vector< uint > &m_imbalExcl, const std::vector< uint > &m_idleIncl, uint mId_bal, Prof::Metric::AExprIncr *balancedExpr, double balancedThreshold, Prof::CCT::ANode *balancedFrm, Prof::CCT::ANode *balancedNode)
const Metric::Mgr * metricMgr() const
const char * DIAG_UnexpectedInput
virtual uint accumId(int i) const
double demandMetric(size_t mId, size_t size=0) const
virtual bool isSeparable(const Prof::CCT::AProcNode *x)
virtual bool isSeparable(const Prof::CCT::AProcNode *x)=0
#define NULL
Definition: ElfHelper.cpp:85
virtual const std::string & fileName() const
Definition: CCT-Tree.hpp:1063
Metric::ADesc * metric(uint i)
Definition: Metric-Mgr.hpp:131
const std::string & description() const
virtual bool isSeparable(const Prof::CCT::AProcNode *x)
#define DIAG_Die(...)
Definition: diagnostics.h:267
virtual bool isSeparable(const Prof::CCT::AProcNode *x)
virtual DerivedIncrDesc * clone() const
Metric::AExprIncr * expr() const
CCT::Tree * cct() const
virtual NonUniformDegreeTreeNode * Current() const