summaryrefslogtreecommitdiffstats
path: root/tdecachegrind/tdecachegrind/coverage.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tdecachegrind/tdecachegrind/coverage.cpp')
-rw-r--r--tdecachegrind/tdecachegrind/coverage.cpp329
1 files changed, 329 insertions, 0 deletions
diff --git a/tdecachegrind/tdecachegrind/coverage.cpp b/tdecachegrind/tdecachegrind/coverage.cpp
new file mode 100644
index 00000000..86e6f7ff
--- /dev/null
+++ b/tdecachegrind/tdecachegrind/coverage.cpp
@@ -0,0 +1,329 @@
+/* This file is part of KCachegrind.
+ Copyright (C) 2002 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
+
+ KCachegrind is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation, version 2.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/*
+ * Function Coverage Analysis
+ */
+
+#include "coverage.h"
+
+//#define DEBUG_COVERAGE 1
+
+TraceCostType* Coverage::_costType;
+
+const int Coverage::maxHistogramDepth = maxHistogramDepthValue;
+const int Coverage::Rtti = 1;
+
+Coverage::Coverage()
+{
+}
+
+void Coverage::init()
+{
+ _self = 0.0;
+ _incl = 0.0;
+ _callCount = 0.0;
+ // should always be overwritten before usage
+ _firstPercentage = 1.0;
+ _minDistance = 9999;
+ _maxDistance = 0;
+ _active = false;
+ _inRecursion = false;
+ for (int i = 0;i<maxHistogramDepth;i++) {
+ _selfHisto[i] = 0.0;
+ _inclHisto[i] = 0.0;
+ }
+
+ _valid = true;
+}
+
+int Coverage::inclusiveMedian()
+{
+ double maxP = _inclHisto[0];
+ int medD = 0;
+ for (int i = 1;i<maxHistogramDepth;i++)
+ if (_inclHisto[i]>maxP) {
+ maxP = _inclHisto[i];
+ medD = i;
+ }
+
+ return medD;
+}
+
+int Coverage::selfMedian()
+{
+ double maxP = _selfHisto[0];
+ int medD = 0;
+ for (int i = 1;i<maxHistogramDepth;i++)
+ if (_selfHisto[i]>maxP) {
+ maxP = _selfHisto[i];
+ medD = i;
+ }
+
+ return medD;
+}
+
+TraceFunctionList Coverage::coverage(TraceFunction* f, CoverageMode m,
+ TraceCostType* ct)
+{
+ invalidate(f->data(), Coverage::Rtti);
+
+ _costType = ct;
+
+ // function f takes ownership over c!
+ Coverage* c = new Coverage();
+ c->setFunction(f);
+ c->init();
+
+ TraceFunctionList l;
+
+ if (m == Caller)
+ c->addCallerCoverage(l, 1.0, 0);
+ else
+ c->addCallingCoverage(l, 1.0, 1.0, 0);
+
+ return l;
+}
+
+void Coverage::addCallerCoverage(TraceFunctionList& fList,
+ double pBack, int d)
+{
+ TraceCallList cList;
+ TraceCall* call;
+ Coverage* c;
+
+ if (_inRecursion) return;
+
+ double incl;
+ incl = (double) (_function->inclusive()->subCost(_costType));
+
+ if (_active) {
+#ifdef DEBUG_COVERAGE
+ qDebug("CallerCov: D %d, %s (was active, incl %f, self %f): newP %f", d,
+ _function->prettyName().ascii(), _incl, _self, pBack);
+#endif
+ _inRecursion = true;
+ }
+ else {
+ _active = true;
+
+ // only add cost if this is no recursion
+
+ _incl += pBack;
+ _firstPercentage = pBack;
+
+ if (_minDistance > d) _minDistance = d;
+ if (_maxDistance < d) _maxDistance = d;
+ if (d<maxHistogramDepth) {
+ _inclHisto[d] += pBack;
+ }
+ else {
+ _inclHisto[maxHistogramDepth-1] += pBack;
+ }
+
+#ifdef DEBUG_COVERAGE
+ qDebug("CallerCov: D %d, %s (now active, new incl %f): newP %f",
+ d, _function->prettyName().ascii(), _incl, pBack);
+#endif
+ }
+
+ double callVal, pBackNew;
+
+ cList = _function->callers();
+ for (call=cList.first();call;call=cList.next()) {
+ if (call->inCycle()>0) continue;
+ if (call->isRecursion()) continue;
+
+ if (call->subCost(_costType)>0) {
+ TraceFunction* caller = call->caller();
+
+ c = (Coverage*) caller->assoziation(rtti());
+ if (!c) {
+ c = new Coverage();
+ c->setFunction(caller);
+ }
+ if (!c->isValid()) {
+ c->init();
+ fList.append(caller);
+ }
+
+ if (c->isActive()) continue;
+ if (c->inRecursion()) continue;
+
+ callVal = (double) call->subCost(_costType);
+ pBackNew = pBack * (callVal / incl);
+
+ // FIXME ?!?
+
+ if (!c->isActive()) {
+ if (d>=0)
+ c->callCount() += (double)call->callCount();
+ else
+ c->callCount() += _callCount;
+ }
+ else {
+ // adjust pNew by sum of geometric series of recursion factor.
+ // Thus we can avoid endless recursion here
+ pBackNew *= 1.0 / (1.0 - pBackNew / c->firstPercentage());
+ }
+
+ // Limit depth
+ if (pBackNew > 0.0001)
+ c->addCallerCoverage(fList, pBackNew, d+1);
+ }
+ }
+
+ if (_inRecursion)
+ _inRecursion = false;
+ else if (_active)
+ _active = false;
+}
+
+/**
+ * pForward is time on percent used,
+ * pBack is given to allow for calculation of call counts
+ */
+void Coverage::addCallingCoverage(TraceFunctionList& fList,
+ double pForward, double pBack, int d)
+{
+ TraceCallList cList;
+ TraceCall* call;
+ Coverage* c;
+
+ if (_inRecursion) return;
+
+#ifdef DEBUG_COVERAGE
+ static const char* spaces = " ";
+#endif
+
+ double self, incl;
+ incl = (double) (_function->inclusive()->subCost(_costType));
+
+#ifdef DEBUG_COVERAGE
+ qDebug("CngCov:%s - %s (incl %f, self %f): forward %f, back %f",
+ spaces+strlen(spaces)-d,
+ _function->prettyName().ascii(), _incl, _self, pForward, pBack);
+#endif
+
+
+ if (_active) {
+ _inRecursion = true;
+
+#ifdef DEBUG_COVERAGE
+ qDebug("CngCov:%s < %s: STOP (is active)",
+ spaces+strlen(spaces)-d,
+ _function->prettyName().ascii());
+#endif
+
+ }
+ else {
+ _active = true;
+
+ // only add cost if this is no recursion
+ self = pForward * (_function->subCost(_costType)) / incl;
+ _incl += pForward;
+ _self += self;
+ _firstPercentage = pForward;
+
+ if (_minDistance > d) _minDistance = d;
+ if (_maxDistance < d) _maxDistance = d;
+ if (d<maxHistogramDepth) {
+ _inclHisto[d] += pForward;
+ _selfHisto[d] += self;
+ }
+ else {
+ _inclHisto[maxHistogramDepth-1] += pForward;
+ _selfHisto[maxHistogramDepth-1] += self;
+ }
+
+#ifdef DEBUG_COVERAGE
+ qDebug("CngCov:%s < %s (incl %f, self %f)",
+ spaces+strlen(spaces)-d,
+ _function->prettyName().ascii(), _incl, _self);
+#endif
+ }
+
+ double callVal, pForwardNew, pBackNew;
+
+ cList = _function->callings();
+ for (call=cList.first();call;call=cList.next()) {
+ if (call->inCycle()>0) continue;
+ if (call->isRecursion()) continue;
+
+ if (call->subCost(_costType)>0) {
+ TraceFunction* calling = call->called();
+
+ c = (Coverage*) calling->assoziation(rtti());
+ if (!c) {
+ c = new Coverage();
+ c->setFunction(calling);
+ }
+ if (!c->isValid()) {
+ c->init();
+ fList.append(calling);
+ }
+
+ if (c->isActive()) continue;
+ if (c->inRecursion()) continue;
+
+ callVal = (double) call->subCost(_costType);
+ pForwardNew = pForward * (callVal / incl);
+ pBackNew = pBack * (callVal /
+ calling->inclusive()->subCost(_costType));
+
+ if (!c->isActive()) {
+ c->callCount() += pBack * call->callCount();
+
+#ifdef DEBUG_COVERAGE
+ qDebug("CngCov:%s > %s: forward %f, back %f, calls %f -> %f, now %f",
+ spaces+strlen(spaces)-d,
+ calling->prettyName().ascii(),
+ pForwardNew, pBackNew,
+ (double)call->callCount(),
+ pBack * call->callCount(),
+ c->callCount());
+#endif
+ }
+ else {
+ // adjust pNew by sum of geometric series of recursion factor.
+ // Thus we can avoid endless recursion here
+ double fFactor = 1.0 / (1.0 - pForwardNew / c->firstPercentage());
+ double bFactor = 1.0 / (1.0 - pBackNew);
+#ifdef DEBUG_COVERAGE
+ qDebug("CngCov:%s Recursion - origP %f, actP %f => factor %f, newP %f",
+ spaces+strlen(spaces)-d,
+ c->firstPercentage(), pForwardNew,
+ fFactor, pForwardNew * fFactor);
+#endif
+ pForwardNew *= fFactor;
+ pBackNew *= bFactor;
+
+ }
+
+ // Limit depth
+ if (pForwardNew > 0.0001)
+ c->addCallingCoverage(fList, pForwardNew, pBackNew, d+1);
+ }
+ }
+
+ if (_inRecursion)
+ _inRecursion = false;
+ else if (_active)
+ _active = false;
+}
+