diff options
author | Ted Kremenek <kremenek@apple.com> | 2010-06-25 20:59:31 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2010-06-25 20:59:31 +0000 |
commit | 9e9595b12e9b55586c4d50d370f429c7a3c92a90 (patch) | |
tree | 2afb34a0633e097dbf33ab744e835b97d6740a6d /lib/Checker/GRExprEngine.cpp | |
parent | c4a1437c15da43eb8d2601cdce13161ef41a4389 (diff) |
Add "checker caching" to GRExprEngine::CheckerVisit to progressively build
a winowed list of checkers that actually do something for a given StmtClass.
As the number of checkers grows, this may potentially significantly reduce
the number of checkers called at any one time. My own measurements show that
for the ~20 registered Checker objects, only ~5 of them respond at any one time
to a give statement. While this isn't a net performance win right now (there
is a minor slowdown on sqlite.3) this improvement does greatly improve debugging
when stepping through the checkers used to evaluate a given statement.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@106884 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Checker/GRExprEngine.cpp')
-rw-r--r-- | lib/Checker/GRExprEngine.cpp | 54 |
1 files changed, 51 insertions, 3 deletions
diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp index b7b3502ccc..4c2512dfa4 100644 --- a/lib/Checker/GRExprEngine.cpp +++ b/lib/Checker/GRExprEngine.cpp @@ -172,13 +172,37 @@ public: void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, bool isPrevisit) { - if (Checkers.empty()) { + // Determine if we already have a cached 'CheckersOrdered' vector + // specifically tailored for the provided <Stmt kind, isPrevisit>. This + // can reduce the number of checkers actually called. + CheckersOrdered *CO = &Checkers; + llvm::OwningPtr<CheckersOrdered> NewCO; + + const std::pair<unsigned, unsigned> &K = + std::make_pair((unsigned)S->getStmtClass(), isPrevisit ? 1U : 0U); + + CheckersOrdered *& CO_Ref = COCache[K]; + + if (!CO_Ref) { + // If we have no previously cached CheckersOrdered vector for this + // statement kind, then create one. + NewCO.reset(new CheckersOrdered); + } + else { + // Use the already cached set. + CO = CO_Ref; + } + + if (CO->empty()) { + // If there are no checkers, return early without doing any + // more work. Dst.insert(Src); return; } ExplodedNodeSet Tmp; ExplodedNodeSet *PrevSet = &Src; + unsigned checkersEvaluated = 0; for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E;++I){ ExplodedNodeSet *CurrSet = 0; @@ -190,12 +214,30 @@ void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, } void *tag = I->first; Checker *checker = I->second; + bool respondsToCallback = true; for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); - NI != NE; ++NI) - checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, tag, isPrevisit); + NI != NE; ++NI) { + + checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, tag, isPrevisit, + respondsToCallback); + + } + PrevSet = CurrSet; + + if (NewCO.get()) { + ++checkersEvaluated; + if (respondsToCallback) + NewCO->push_back(*I); + } } + + // If we built NewCO, check if we called all the checkers. This is important + // so that we know that we accurately determined the entire set of checkers + // that responds to this callback. + if (NewCO.get() && checkersEvaluated == Checkers.size()) + CO_Ref = NewCO.take(); // Don't autotransition. The CheckerContext objects should do this // automatically. @@ -361,8 +403,14 @@ GRExprEngine::GRExprEngine(AnalysisManager &mgr, GRTransferFuncs *tf) GRExprEngine::~GRExprEngine() { BR.FlushReports(); delete [] NSExceptionInstanceRaiseSelectors; + + // Delete the set of checkers. for (CheckersOrdered::iterator I=Checkers.begin(), E=Checkers.end(); I!=E;++I) delete I->second; + + for (CheckersOrderedCache::iterator I=COCache.begin(), E=COCache.end(); + I!=E;++I) + delete I->second; } //===----------------------------------------------------------------------===// |