Skip to content

[analyzer] Improve cache locality by using separate allocators #138295

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

tigbr
Copy link
Contributor

@tigbr tigbr commented May 2, 2025

This patch improves the performance of the Clang Static Analyzer by passing separate BumpPtrAllocator instances to its data structures instead of using the BumpPtrAllocator of the ExplodedGraph everywhere.

It greatly reduces the analysis time of three example translation units that are particularly affected by disabling node reclamation, as mentioned in issue #105512. It also brings a modest improvement in the general case as well, according to my testing on the vim repository with scan-build.

My measurements are in the measurements.ods file.

Pass in separate BumpPtrAllocators to the different data structures
in the analyzer, instead of reusing the BumpPtrAllocator of the
ExplodedGraph everywhere, to gain a measurable speedup in analysis.
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:static analyzer labels May 2, 2025
@llvmbot
Copy link
Member

llvmbot commented May 2, 2025

@llvm/pr-subscribers-clang-static-analyzer-1

Author: None (tigbr)

Changes

This patch improves the performance of the Clang Static Analyzer by passing separate BumpPtrAllocator instances to its data structures instead of using the BumpPtrAllocator of the ExplodedGraph everywhere.

It greatly reduces the analysis time of three example translation units that are particularly affected by disabling node reclamation, as mentioned in issue #105512. It also brings a modest improvement in the general case as well, according to my testing on the vim repository with scan-build.

My measurements are in the measurements.ods file.


Full diff: https://github.com/llvm/llvm-project/pull/138295.diff

10 Files Affected:

  • (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h (+2-1)
  • (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h (+3-1)
  • (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h (+1-1)
  • (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h (+8-5)
  • (modified) clang/lib/StaticAnalyzer/Core/CoreEngine.cpp (+2-2)
  • (modified) clang/lib/StaticAnalyzer/Core/ExprEngine.cpp (+7-4)
  • (modified) clang/lib/StaticAnalyzer/Core/ProgramState.cpp (+4-4)
  • (modified) clang/lib/StaticAnalyzer/Core/SValBuilder.cpp (+8-5)
  • (modified) clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp (+16-7)
  • (modified) clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp (+4-1)
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
index 80b79fd4e928f..6b6a28902092e 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
@@ -138,7 +138,8 @@ class CoreEngine {
   /// Construct a CoreEngine object to analyze the provided CFG.
   CoreEngine(ExprEngine &exprengine,
              FunctionSummariesTy *FS,
-             AnalyzerOptions &Opts);
+             AnalyzerOptions &Opts,
+             llvm::BumpPtrAllocator &BlockCounterFactoryAllocator);
 
   CoreEngine(const CoreEngine &) = delete;
   CoreEngine &operator=(const CoreEngine &) = delete;
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 20c446e33ef9a..4d10335d5a1fb 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -181,7 +181,9 @@ class ExprEngine {
 public:
   ExprEngine(cross_tu::CrossTranslationUnitContext &CTU, AnalysisManager &mgr,
              SetOfConstDecls *VisitedCalleesIn,
-             FunctionSummariesTy *FS, InliningModes HowToInlineIn);
+             FunctionSummariesTy *FS, InliningModes HowToInlineIn,
+             std::array<llvm::BumpPtrAllocator, 7> &ProgramStateAllocators,
+             llvm::BumpPtrAllocator &BlockCounterFactoryAllocator);
 
   virtual ~ExprEngine() = default;
 
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
index a20516b003c7d..a8403d170e896 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -530,7 +530,7 @@ class ProgramStateManager {
   ProgramStateManager(ASTContext &Ctx,
                  StoreManagerCreator CreateStoreManager,
                  ConstraintManagerCreator CreateConstraintManager,
-                 llvm::BumpPtrAllocator& alloc,
+                 std::array<llvm::BumpPtrAllocator, 7> &Allocators,
                  ExprEngine *expreng);
 
   ~ProgramStateManager();
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index 54430d426a82a..904718eae1843 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -76,8 +76,10 @@ class SValBuilder {
   const unsigned ArrayIndexWidth;
 
 public:
-  SValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context,
-              ProgramStateManager &stateMgr);
+  SValBuilder(llvm::BumpPtrAllocator &BasicValueFactoryAllocator,
+              llvm::BumpPtrAllocator &SymbolManagerAllocator,
+              llvm::BumpPtrAllocator &MemRegionManagerAllocator,
+              ASTContext &context, ProgramStateManager &stateMgr);
 
   virtual ~SValBuilder() = default;
 
@@ -409,9 +411,10 @@ class SValBuilder {
                                const StackFrameContext *SFC);
 };
 
-SValBuilder* createSimpleSValBuilder(llvm::BumpPtrAllocator &alloc,
-                                     ASTContext &context,
-                                     ProgramStateManager &stateMgr);
+SValBuilder* createSimpleSValBuilder(llvm::BumpPtrAllocator &BasicValueFactoryAllocator,
+                                     llvm::BumpPtrAllocator &SymbolManagerAllocator,
+                                     llvm::BumpPtrAllocator &MemRegionManagerAllocator,
+                                     ASTContext &context, ProgramStateManager &stateMgr);
 
 } // namespace ento
 
diff --git a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
index bf1fd7c2356dc..9fa0211abbbbc 100644
--- a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -75,10 +75,10 @@ static std::unique_ptr<WorkList> generateWorkList(AnalyzerOptions &Opts) {
 }
 
 CoreEngine::CoreEngine(ExprEngine &exprengine, FunctionSummariesTy *FS,
-                       AnalyzerOptions &Opts)
+                       AnalyzerOptions &Opts, llvm::BumpPtrAllocator &BlockCounterFactoryAllocator)
     : ExprEng(exprengine), WList(generateWorkList(Opts)),
       CTUWList(Opts.IsNaiveCTUEnabled ? generateWorkList(Opts) : nullptr),
-      BCounterFactory(G.getAllocator()), FunctionSummaries(FS) {}
+      BCounterFactory(BlockCounterFactoryAllocator), FunctionSummaries(FS) {}
 
 void CoreEngine::setBlockCounter(BlockCounter C) {
   WList->setBlockCounter(C);
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 69cf2dd6fc14e..af410ec5fea5d 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -221,12 +221,15 @@ static const char* TagProviderName = "ExprEngine";
 
 ExprEngine::ExprEngine(cross_tu::CrossTranslationUnitContext &CTU,
                        AnalysisManager &mgr, SetOfConstDecls *VisitedCalleesIn,
-                       FunctionSummariesTy *FS, InliningModes HowToInlineIn)
+                       FunctionSummariesTy *FS, InliningModes HowToInlineIn,
+                       std::array<llvm::BumpPtrAllocator, 7> &ProgramStateAllocators,
+                       llvm::BumpPtrAllocator& BlockCounterFactoryAllocator)
     : CTU(CTU), IsCTUEnabled(mgr.getAnalyzerOptions().IsNaiveCTUEnabled),
       AMgr(mgr), AnalysisDeclContexts(mgr.getAnalysisDeclContextManager()),
-      Engine(*this, FS, mgr.getAnalyzerOptions()), G(Engine.getGraph()),
-      StateMgr(getContext(), mgr.getStoreManagerCreator(),
-               mgr.getConstraintManagerCreator(), G.getAllocator(), this),
+      Engine(*this, FS, mgr.getAnalyzerOptions(), BlockCounterFactoryAllocator),
+             G(Engine.getGraph()),
+      StateMgr(getContext(), mgr.getStoreManagerCreator(), mgr.getConstraintManagerCreator(),
+               ProgramStateAllocators, this),
       SymMgr(StateMgr.getSymbolManager()), MRMgr(StateMgr.getRegionManager()),
       svalBuilder(StateMgr.getSValBuilder()), ObjCNoRet(mgr.getASTContext()),
       BR(mgr, *this), VisitedCallees(VisitedCalleesIn),
diff --git a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp
index 34ab2388cbd2f..a7709d6fc62b7 100644
--- a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp
@@ -72,11 +72,11 @@ int64_t ProgramState::getID() const {
 ProgramStateManager::ProgramStateManager(ASTContext &Ctx,
                                          StoreManagerCreator CreateSMgr,
                                          ConstraintManagerCreator CreateCMgr,
-                                         llvm::BumpPtrAllocator &alloc,
+                                         std::array<llvm::BumpPtrAllocator, 7> &Allocators,
                                          ExprEngine *ExprEng)
-  : Eng(ExprEng), EnvMgr(alloc), GDMFactory(alloc),
-    svalBuilder(createSimpleSValBuilder(alloc, Ctx, *this)),
-    CallEventMgr(new CallEventManager(alloc)), Alloc(alloc) {
+  : Eng(ExprEng), EnvMgr(Allocators[0]), GDMFactory(Allocators[1]),
+    svalBuilder(createSimpleSValBuilder(Allocators[2], Allocators[3], Allocators[4], Ctx, *this)),
+    CallEventMgr(new CallEventManager(Allocators[5])), Alloc(Allocators[6]) {
   StoreMgr = (*CreateSMgr)(*this);
   ConstraintMgr = (*CreateCMgr)(*this, ExprEng);
 }
diff --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
index 4f45b24be86c1..c1710df46d22c 100644
--- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -49,13 +49,16 @@ using namespace ento;
 
 void SValBuilder::anchor() {}
 
-SValBuilder::SValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context,
+SValBuilder::SValBuilder(llvm::BumpPtrAllocator &BasicValueFactoryAllocator,
+                         llvm::BumpPtrAllocator &SymbolManagerAllocator,
+                         llvm::BumpPtrAllocator &MemRegionManagerAllocator,
+                         ASTContext &context,
                          ProgramStateManager &stateMgr)
-    : Context(context), BasicVals(context, alloc),
-      SymMgr(context, BasicVals, alloc), MemMgr(context, alloc),
+    : Context(context), BasicVals(context, BasicValueFactoryAllocator),
+      SymMgr(context, BasicVals, SymbolManagerAllocator),
+      MemMgr(context, MemRegionManagerAllocator),
       StateMgr(stateMgr),
-      AnOpts(
-          stateMgr.getOwningEngine().getAnalysisManager().getAnalyzerOptions()),
+      AnOpts(stateMgr.getOwningEngine().getAnalysisManager().getAnalyzerOptions()),
       ArrayIndexTy(context.LongLongTy),
       ArrayIndexWidth(context.getTypeSize(ArrayIndexTy)) {}
 
diff --git a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index afb0273d23bd4..32022bd4d8e62 100644
--- a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -64,9 +64,14 @@ class SimpleSValBuilder : public SValBuilder {
   SVal simplifySValOnce(ProgramStateRef State, SVal V);
 
 public:
-  SimpleSValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context,
-                    ProgramStateManager &stateMgr)
-      : SValBuilder(alloc, context, stateMgr) {}
+  SimpleSValBuilder(llvm::BumpPtrAllocator &BasicValueFactoryAllocator,
+                    llvm::BumpPtrAllocator &SymbolManagerAllocator,
+                    llvm::BumpPtrAllocator &MemRegionManagerAllocator,
+                    ASTContext &context, ProgramStateManager &stateMgr)
+      : SValBuilder(BasicValueFactoryAllocator,
+                    SymbolManagerAllocator,
+                    MemRegionManagerAllocator,
+                    context, stateMgr) {}
   ~SimpleSValBuilder() override {}
 
   SVal evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op,
@@ -98,10 +103,14 @@ class SimpleSValBuilder : public SValBuilder {
 };
 } // end anonymous namespace
 
-SValBuilder *ento::createSimpleSValBuilder(llvm::BumpPtrAllocator &alloc,
-                                           ASTContext &context,
-                                           ProgramStateManager &stateMgr) {
-  return new SimpleSValBuilder(alloc, context, stateMgr);
+SValBuilder *ento::createSimpleSValBuilder(llvm::BumpPtrAllocator &BasicValueFactoryAllocator,
+                                           llvm::BumpPtrAllocator &SymbolManagerAllocator,
+                                           llvm::BumpPtrAllocator &MemRegionManagerAllocator,
+                                           ASTContext &context, ProgramStateManager &stateMgr) {
+  return new SimpleSValBuilder(BasicValueFactoryAllocator,
+                               SymbolManagerAllocator,
+                               MemRegionManagerAllocator,
+                               context, stateMgr);
 }
 
 // Checks if the negation the value and flipping sign preserve
diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index 189d7d6bede8e..1e0030a339ef3 100644
--- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -752,7 +752,10 @@ void AnalysisConsumer::RunPathSensitiveChecks(Decl *D,
   if (!Mgr->getAnalysisDeclContext(D)->getAnalysis<RelaxedLiveVariables>())
     return;
 
-  ExprEngine Eng(CTU, *Mgr, VisitedCallees, &FunctionSummaries, IMode);
+  std::array<llvm::BumpPtrAllocator, 7> ProgramStateManagerAllocators;
+  llvm::BumpPtrAllocator BlockCounterFactoryAllocator;
+
+  ExprEngine Eng(CTU, *Mgr, VisitedCallees, &FunctionSummaries, IMode, ProgramStateManagerAllocators, BlockCounterFactoryAllocator);
 
   // Execute the worklist algorithm.
   llvm::TimeRecord ExprEngineStartTime;

@llvmbot
Copy link
Member

llvmbot commented May 2, 2025

@llvm/pr-subscribers-clang

Author: None (tigbr)

Changes

This patch improves the performance of the Clang Static Analyzer by passing separate BumpPtrAllocator instances to its data structures instead of using the BumpPtrAllocator of the ExplodedGraph everywhere.

It greatly reduces the analysis time of three example translation units that are particularly affected by disabling node reclamation, as mentioned in issue #105512. It also brings a modest improvement in the general case as well, according to my testing on the vim repository with scan-build.

My measurements are in the measurements.ods file.


Full diff: https://github.com/llvm/llvm-project/pull/138295.diff

10 Files Affected:

  • (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h (+2-1)
  • (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h (+3-1)
  • (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h (+1-1)
  • (modified) clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h (+8-5)
  • (modified) clang/lib/StaticAnalyzer/Core/CoreEngine.cpp (+2-2)
  • (modified) clang/lib/StaticAnalyzer/Core/ExprEngine.cpp (+7-4)
  • (modified) clang/lib/StaticAnalyzer/Core/ProgramState.cpp (+4-4)
  • (modified) clang/lib/StaticAnalyzer/Core/SValBuilder.cpp (+8-5)
  • (modified) clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp (+16-7)
  • (modified) clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp (+4-1)
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
index 80b79fd4e928f..6b6a28902092e 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
@@ -138,7 +138,8 @@ class CoreEngine {
   /// Construct a CoreEngine object to analyze the provided CFG.
   CoreEngine(ExprEngine &exprengine,
              FunctionSummariesTy *FS,
-             AnalyzerOptions &Opts);
+             AnalyzerOptions &Opts,
+             llvm::BumpPtrAllocator &BlockCounterFactoryAllocator);
 
   CoreEngine(const CoreEngine &) = delete;
   CoreEngine &operator=(const CoreEngine &) = delete;
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 20c446e33ef9a..4d10335d5a1fb 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -181,7 +181,9 @@ class ExprEngine {
 public:
   ExprEngine(cross_tu::CrossTranslationUnitContext &CTU, AnalysisManager &mgr,
              SetOfConstDecls *VisitedCalleesIn,
-             FunctionSummariesTy *FS, InliningModes HowToInlineIn);
+             FunctionSummariesTy *FS, InliningModes HowToInlineIn,
+             std::array<llvm::BumpPtrAllocator, 7> &ProgramStateAllocators,
+             llvm::BumpPtrAllocator &BlockCounterFactoryAllocator);
 
   virtual ~ExprEngine() = default;
 
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
index a20516b003c7d..a8403d170e896 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -530,7 +530,7 @@ class ProgramStateManager {
   ProgramStateManager(ASTContext &Ctx,
                  StoreManagerCreator CreateStoreManager,
                  ConstraintManagerCreator CreateConstraintManager,
-                 llvm::BumpPtrAllocator& alloc,
+                 std::array<llvm::BumpPtrAllocator, 7> &Allocators,
                  ExprEngine *expreng);
 
   ~ProgramStateManager();
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index 54430d426a82a..904718eae1843 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -76,8 +76,10 @@ class SValBuilder {
   const unsigned ArrayIndexWidth;
 
 public:
-  SValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context,
-              ProgramStateManager &stateMgr);
+  SValBuilder(llvm::BumpPtrAllocator &BasicValueFactoryAllocator,
+              llvm::BumpPtrAllocator &SymbolManagerAllocator,
+              llvm::BumpPtrAllocator &MemRegionManagerAllocator,
+              ASTContext &context, ProgramStateManager &stateMgr);
 
   virtual ~SValBuilder() = default;
 
@@ -409,9 +411,10 @@ class SValBuilder {
                                const StackFrameContext *SFC);
 };
 
-SValBuilder* createSimpleSValBuilder(llvm::BumpPtrAllocator &alloc,
-                                     ASTContext &context,
-                                     ProgramStateManager &stateMgr);
+SValBuilder* createSimpleSValBuilder(llvm::BumpPtrAllocator &BasicValueFactoryAllocator,
+                                     llvm::BumpPtrAllocator &SymbolManagerAllocator,
+                                     llvm::BumpPtrAllocator &MemRegionManagerAllocator,
+                                     ASTContext &context, ProgramStateManager &stateMgr);
 
 } // namespace ento
 
diff --git a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
index bf1fd7c2356dc..9fa0211abbbbc 100644
--- a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -75,10 +75,10 @@ static std::unique_ptr<WorkList> generateWorkList(AnalyzerOptions &Opts) {
 }
 
 CoreEngine::CoreEngine(ExprEngine &exprengine, FunctionSummariesTy *FS,
-                       AnalyzerOptions &Opts)
+                       AnalyzerOptions &Opts, llvm::BumpPtrAllocator &BlockCounterFactoryAllocator)
     : ExprEng(exprengine), WList(generateWorkList(Opts)),
       CTUWList(Opts.IsNaiveCTUEnabled ? generateWorkList(Opts) : nullptr),
-      BCounterFactory(G.getAllocator()), FunctionSummaries(FS) {}
+      BCounterFactory(BlockCounterFactoryAllocator), FunctionSummaries(FS) {}
 
 void CoreEngine::setBlockCounter(BlockCounter C) {
   WList->setBlockCounter(C);
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 69cf2dd6fc14e..af410ec5fea5d 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -221,12 +221,15 @@ static const char* TagProviderName = "ExprEngine";
 
 ExprEngine::ExprEngine(cross_tu::CrossTranslationUnitContext &CTU,
                        AnalysisManager &mgr, SetOfConstDecls *VisitedCalleesIn,
-                       FunctionSummariesTy *FS, InliningModes HowToInlineIn)
+                       FunctionSummariesTy *FS, InliningModes HowToInlineIn,
+                       std::array<llvm::BumpPtrAllocator, 7> &ProgramStateAllocators,
+                       llvm::BumpPtrAllocator& BlockCounterFactoryAllocator)
     : CTU(CTU), IsCTUEnabled(mgr.getAnalyzerOptions().IsNaiveCTUEnabled),
       AMgr(mgr), AnalysisDeclContexts(mgr.getAnalysisDeclContextManager()),
-      Engine(*this, FS, mgr.getAnalyzerOptions()), G(Engine.getGraph()),
-      StateMgr(getContext(), mgr.getStoreManagerCreator(),
-               mgr.getConstraintManagerCreator(), G.getAllocator(), this),
+      Engine(*this, FS, mgr.getAnalyzerOptions(), BlockCounterFactoryAllocator),
+             G(Engine.getGraph()),
+      StateMgr(getContext(), mgr.getStoreManagerCreator(), mgr.getConstraintManagerCreator(),
+               ProgramStateAllocators, this),
       SymMgr(StateMgr.getSymbolManager()), MRMgr(StateMgr.getRegionManager()),
       svalBuilder(StateMgr.getSValBuilder()), ObjCNoRet(mgr.getASTContext()),
       BR(mgr, *this), VisitedCallees(VisitedCalleesIn),
diff --git a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp
index 34ab2388cbd2f..a7709d6fc62b7 100644
--- a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp
@@ -72,11 +72,11 @@ int64_t ProgramState::getID() const {
 ProgramStateManager::ProgramStateManager(ASTContext &Ctx,
                                          StoreManagerCreator CreateSMgr,
                                          ConstraintManagerCreator CreateCMgr,
-                                         llvm::BumpPtrAllocator &alloc,
+                                         std::array<llvm::BumpPtrAllocator, 7> &Allocators,
                                          ExprEngine *ExprEng)
-  : Eng(ExprEng), EnvMgr(alloc), GDMFactory(alloc),
-    svalBuilder(createSimpleSValBuilder(alloc, Ctx, *this)),
-    CallEventMgr(new CallEventManager(alloc)), Alloc(alloc) {
+  : Eng(ExprEng), EnvMgr(Allocators[0]), GDMFactory(Allocators[1]),
+    svalBuilder(createSimpleSValBuilder(Allocators[2], Allocators[3], Allocators[4], Ctx, *this)),
+    CallEventMgr(new CallEventManager(Allocators[5])), Alloc(Allocators[6]) {
   StoreMgr = (*CreateSMgr)(*this);
   ConstraintMgr = (*CreateCMgr)(*this, ExprEng);
 }
diff --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
index 4f45b24be86c1..c1710df46d22c 100644
--- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -49,13 +49,16 @@ using namespace ento;
 
 void SValBuilder::anchor() {}
 
-SValBuilder::SValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context,
+SValBuilder::SValBuilder(llvm::BumpPtrAllocator &BasicValueFactoryAllocator,
+                         llvm::BumpPtrAllocator &SymbolManagerAllocator,
+                         llvm::BumpPtrAllocator &MemRegionManagerAllocator,
+                         ASTContext &context,
                          ProgramStateManager &stateMgr)
-    : Context(context), BasicVals(context, alloc),
-      SymMgr(context, BasicVals, alloc), MemMgr(context, alloc),
+    : Context(context), BasicVals(context, BasicValueFactoryAllocator),
+      SymMgr(context, BasicVals, SymbolManagerAllocator),
+      MemMgr(context, MemRegionManagerAllocator),
       StateMgr(stateMgr),
-      AnOpts(
-          stateMgr.getOwningEngine().getAnalysisManager().getAnalyzerOptions()),
+      AnOpts(stateMgr.getOwningEngine().getAnalysisManager().getAnalyzerOptions()),
       ArrayIndexTy(context.LongLongTy),
       ArrayIndexWidth(context.getTypeSize(ArrayIndexTy)) {}
 
diff --git a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index afb0273d23bd4..32022bd4d8e62 100644
--- a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -64,9 +64,14 @@ class SimpleSValBuilder : public SValBuilder {
   SVal simplifySValOnce(ProgramStateRef State, SVal V);
 
 public:
-  SimpleSValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context,
-                    ProgramStateManager &stateMgr)
-      : SValBuilder(alloc, context, stateMgr) {}
+  SimpleSValBuilder(llvm::BumpPtrAllocator &BasicValueFactoryAllocator,
+                    llvm::BumpPtrAllocator &SymbolManagerAllocator,
+                    llvm::BumpPtrAllocator &MemRegionManagerAllocator,
+                    ASTContext &context, ProgramStateManager &stateMgr)
+      : SValBuilder(BasicValueFactoryAllocator,
+                    SymbolManagerAllocator,
+                    MemRegionManagerAllocator,
+                    context, stateMgr) {}
   ~SimpleSValBuilder() override {}
 
   SVal evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op,
@@ -98,10 +103,14 @@ class SimpleSValBuilder : public SValBuilder {
 };
 } // end anonymous namespace
 
-SValBuilder *ento::createSimpleSValBuilder(llvm::BumpPtrAllocator &alloc,
-                                           ASTContext &context,
-                                           ProgramStateManager &stateMgr) {
-  return new SimpleSValBuilder(alloc, context, stateMgr);
+SValBuilder *ento::createSimpleSValBuilder(llvm::BumpPtrAllocator &BasicValueFactoryAllocator,
+                                           llvm::BumpPtrAllocator &SymbolManagerAllocator,
+                                           llvm::BumpPtrAllocator &MemRegionManagerAllocator,
+                                           ASTContext &context, ProgramStateManager &stateMgr) {
+  return new SimpleSValBuilder(BasicValueFactoryAllocator,
+                               SymbolManagerAllocator,
+                               MemRegionManagerAllocator,
+                               context, stateMgr);
 }
 
 // Checks if the negation the value and flipping sign preserve
diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index 189d7d6bede8e..1e0030a339ef3 100644
--- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -752,7 +752,10 @@ void AnalysisConsumer::RunPathSensitiveChecks(Decl *D,
   if (!Mgr->getAnalysisDeclContext(D)->getAnalysis<RelaxedLiveVariables>())
     return;
 
-  ExprEngine Eng(CTU, *Mgr, VisitedCallees, &FunctionSummaries, IMode);
+  std::array<llvm::BumpPtrAllocator, 7> ProgramStateManagerAllocators;
+  llvm::BumpPtrAllocator BlockCounterFactoryAllocator;
+
+  ExprEngine Eng(CTU, *Mgr, VisitedCallees, &FunctionSummaries, IMode, ProgramStateManagerAllocators, BlockCounterFactoryAllocator);
 
   // Execute the worklist algorithm.
   llvm::TimeRecord ExprEngineStartTime;

Copy link

github-actions bot commented May 2, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@steakhal
Copy link
Contributor

steakhal commented May 2, 2025

So is it about cache locality?

@tigbr
Copy link
Contributor Author

tigbr commented May 2, 2025

Yes, that is what I have hoped to improve, and based on the measurements it seems that it had positive effects.

@steakhal
Copy link
Contributor

steakhal commented May 2, 2025

FYI @necto

@steakhal
Copy link
Contributor

steakhal commented May 4, 2025

FYI, build bots suggests that this PR has build errors.

BTW, could you run this under perf stats to demonstrate the reduction of the cache-misses and page-faults? I'd suspect a measurable difference if these separate allocators really help.

@steakhal steakhal changed the title [clang][analyzer][NFC] Improve Clang Static Analyzer performance. [clang][analyzer] Improve cache locality by using separate allocators May 4, 2025
@steakhal steakhal changed the title [clang][analyzer] Improve cache locality by using separate allocators [analyzer] Improve cache locality by using separate allocators May 4, 2025
@steakhal
Copy link
Contributor

steakhal commented May 4, 2025

I had a look at the spreadsheet and the numbers for linux-topro.c looks really impressive.
However, in general, we need further investigation about why are we not getting faster e.g. in the clang-MSP430ISelDAGToDAG.cpp case. The direction seems right though.

(FYI it usually better to take the minimums of the different analysis attempts than the avg).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:static analyzer clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants