static void makeDerivedMetrics(Prof::Metric::Mgr& metricMgr, uint /*Analysis::Args::MetricFlg*/ metrics) { if (Analysis::Args::MetricFlg_isSum(metrics)) { bool needAllStats = Analysis::Args::MetricFlg_isSet(metrics, Analysis::Args::MetricFlg_StatsAll); bool needMultiOccurance = Analysis::Args::MetricFlg_isThread(metrics); metricMgr.makeSummaryMetrics(needAllStats, needMultiOccurance); } if (!Analysis::Args::MetricFlg_isThread(metrics)) { using namespace Prof; for (uint i = 0; i < metricMgr.size(); i++) { Metric::ADesc* m = metricMgr.metric(i); Metric::SampledDesc* mm = dynamic_cast<Metric::SampledDesc*>(m); if (mm) { mm->isVisible(false); mm->isSortKey(false); } } for (uint i = 0; i < metricMgr.size(); i++) { Metric::ADesc* m = metricMgr.metric(i); Metric::DerivedDesc* mm = dynamic_cast<Metric::DerivedDesc*>(m); if (mm) { mm->isSortKey(true); break; } } } }
Prof::CallPath::Profile* read(const char* prof_fnm, uint groupId, uint rFlags) { // ------------------------------------------------------- // // ------------------------------------------------------- Prof::CallPath::Profile* prof = NULL; try { DIAG_MsgIf(0, "Reading: '" << prof_fnm << "'"); prof = Prof::CallPath::Profile::make(prof_fnm, rFlags, /*outfs*/ NULL); } catch (...) { DIAG_EMsg("While reading profile '" << prof_fnm << "'..."); throw; } // ------------------------------------------------------- // Potentially update the profile's metrics // ------------------------------------------------------- if (groupId > 0) { Prof::Metric::Mgr* metricMgr = prof->metricMgr(); for (uint i = 0; i < metricMgr->size(); ++i) { Prof::Metric::ADesc* m = metricMgr->metric(i); m->namePfx(StrUtil::toStr(groupId)); } metricMgr->recomputeMaps(); } return prof; }
MetricCursor::MetricCursor(const Prof::Metric::Mgr& metricMgr, const Prof::Flat::LM& proflm, const BinUtil::LM& lm) { m_loadAddr = (VMA)proflm.load_addr(); m_doUnrelocate = lm.doUnrelocate(m_loadAddr); // -------------------------------------------------------- // Find all metrics for load module and compute totals for each metric // For now we have one metric per sampled event. // -------------------------------------------------------- // NOTE: only handles raw events for (uint i = 0; i < metricMgr.size(); ++i) { const Prof::Metric::ADesc* m = metricMgr.metric(i); const Prof::Metric::SampledDesc* mm = dynamic_cast<const Prof::Metric::SampledDesc*>(m); if (mm) { uint mIdx = (uint)StrUtil::toUInt64(mm->profileRelId()); const Prof::Flat::EventData& profevent = proflm.event(mIdx); m_metricDescs.push_back(&profevent); } } m_metricTots.resize(m_metricDescs.size()); for (uint i = 0; i < m_metricDescs.size(); ++i) { const Prof::Flat::EventData& profevent = *(m_metricDescs[i]); uint64_t& metricTotal = m_metricTots[i]; metricTotal = 0; for (uint j = 0; j < profevent.num_data(); ++j) { const Prof::Flat::Datum& evdat = profevent.datum(j); uint32_t count = evdat.second; metricTotal += count; } } m_curMetricIdx.resize(m_metricDescs.size()); for (uint i = 0; i < m_curMetricIdx.size(); ++i) { m_curMetricIdx[i] = 0; } m_metricValAtVMA.resize(m_metricDescs.size()); }
// makeReturnCountMetric: A return count refers to the number of times // a given CCT node is called by its parent context. However, when // hpcrun records return counts, there is no structure (e.g. procedure // frames) in the CCT. An an example, in the CCT fragment below, the // return count [3] at 0xc means that 0xc returned to 0xbeef 3 times. // Simlarly, 0xbeef returned to its caller 5 times. // // | | // ip: 0xbeef [5] | // / | \ | // 0xa [1] 0xb [2] 0xc [3] | // | | | | // // To be able to say procedure F is called by procedure G x times // within this context, it is necessary to aggregate these counts at // the newly added procedure frames (Struct::ProcFrm). static void makeReturnCountMetric(Prof::CallPath::Profile& prof) { std::vector<uint> retCntId; // ------------------------------------------------------- // find return count metrics, if any // ------------------------------------------------------- Prof::Metric::Mgr* metricMgr = prof.metricMgr(); for (uint i = 0; i < metricMgr->size(); ++i) { Prof::Metric::ADesc* m = metricMgr->metric(i); if (m->nameBase().find(HPCRUN_METRIC_RetCnt) != string::npos) { retCntId.push_back(m->id()); m->computedType(Prof::Metric::ADesc::ComputedTy_Final); m->type(Prof::Metric::ADesc::TyExcl); } } if (retCntId.empty()) { return; } // ------------------------------------------------------- // propagate and aggregate return counts // ------------------------------------------------------- Prof::CCT::ANode* cct_root = prof.cct()->root(); Prof::CCT::ANodeIterator it(cct_root, NULL/*filter*/, false/*leavesOnly*/, IteratorStack::PostOrder); for (Prof::CCT::ANode* n = NULL; (n = it.current()); ++it) { if (typeid(*n) != typeid(Prof::CCT::ProcFrm) && n != cct_root) { Prof::CCT::ANode* n_parent = n->parent(); for (uint i = 0; i < retCntId.size(); ++i) { uint mId = retCntId[i]; n_parent->demandMetric(mId) += n->demandMetric(mId); n->metric(mId) = 0.0; } } } }
static void ProcessMETRIC(DOMNode *node, Analysis::Args& args, Prof::Metric::Mgr& mMgr) { static XMLCh* FILE = XMLString::transcode("FILE"); static XMLCh* COMPUTE = XMLString::transcode("COMPUTE"); static XMLCh* NAMEATTR = XMLString::transcode("name"); static XMLCh* DISPLAYATTR = XMLString::transcode("display"); static XMLCh* PERCENTATTR = XMLString::transcode("percent"); //static XMLCh* PROPAGATEATTR = XMLString::transcode("propagate"); static XMLCh* DISPLAYNAMEATTR = XMLString::transcode("displayName"); static XMLCh* SORTBYATTR = XMLString::transcode("sortBy"); // get metric attributes string metricNm = getAttr(node, NAMEATTR); string metricDispNm = getAttr(node, DISPLAYNAMEATTR); bool metricDoDisp = (getAttr(node, DISPLAYATTR) == "true"); bool metricDoPercent = (getAttr(node,PERCENTATTR) == "true"); bool metricDoSortBy = (getAttr(node,SORTBYATTR) == "true"); if (metricNm.empty()) { ConfigParser_Throw("METRIC: Invalid name: '" << metricNm << "'."); } else if (mMgr.metric(metricNm) != NULL) { ConfigParser_Throw("METRIC: Metric name '" << metricNm << "' was previously defined."); } if (metricDispNm.empty()) { ConfigParser_Throw("METRIC: Invalid displayName: '" << metricDispNm << "'."); } DIAG_DevMsgIf(DBG, "CONFIG: " << "METRIC: name=" << metricNm << " display=" << ((metricDoDisp) ? "true" : "false") << " doPercent=" << ((metricDoPercent) ? "true" : "false") << " sortBy=" << ((metricDoSortBy) ? "true" : "false") << " metricDispNm=" << metricDispNm); // should have exactly one child DOMNode* metricImpl = node->getFirstChild(); for ( ; metricImpl != NULL; metricImpl = metricImpl->getNextSibling()) { if (metricImpl->getNodeType() == DOMNode::TEXT_NODE) { // DTD ensures this can't contain anything but white space continue; } else if (metricImpl->getNodeType() == DOMNode::COMMENT_NODE) { continue; } const XMLCh* metricType = metricImpl->getNodeName(); if (XMLString::equals(metricType, FILE)) { ProcessFILE(metricImpl, args, mMgr, metricNm, metricDoDisp, metricDoPercent, metricDoSortBy, metricDispNm); } else if (XMLString::equals(metricType,COMPUTE)) { //bool propagateComputed = false; // tallent // (getAttr(metricImpl, PROPAGATEATTR) == "computed"); DOMNode* child = metricImpl->getFirstChild(); for (; child != NULL; child = child->getNextSibling()) { if (child->getNodeType() == DOMNode::TEXT_NODE) { // DTD ensures this can't contain anything but white space continue; } else if (child->getNodeType() == DOMNode::COMMENT_NODE) { continue; } using namespace Prof; Metric::AExpr* expr = makeMathMLExpr(metricNm.c_str(), child, mMgr); mMgr.insert(new Metric::DerivedDesc(metricNm, metricNm, expr, metricDoDisp, metricDoSortBy, metricDoPercent, false/*isPercent*/)); } } else { ConfigParser_Throw("Unexpected METRIC type '" << XMLString::transcode(metricType) << "'."); } } }