[clang] f5c4f27 - [analyzer] Add -ftime-trace scopes for region-store bindings and removeDead (#125884)

via cfe-commits cfe-commits at lists.llvm.org
Thu Feb 6 07:09:18 PST 2025


Author: Arseniy Zaostrovnykh
Date: 2025-02-06T16:09:14+01:00
New Revision: f5c4f271abe757ae49ca97475b7b77de56d24f69

URL: https://github.com/llvm/llvm-project/commit/f5c4f271abe757ae49ca97475b7b77de56d24f69
DIFF: https://github.com/llvm/llvm-project/commit/f5c4f271abe757ae49ca97475b7b77de56d24f69.diff

LOG: [analyzer] Add -ftime-trace scopes for region-store bindings and removeDead (#125884)

>From investigation of a few slow analysis cases, I discovered that
`RegionStoreManager::bind*` and `ExprEngine::removeDead` are often the
slowest actions. This change adds explicit scope to the time trace
generated by `-ftime-trace` to enable easy diagnostics of the cases when
these functions are the slowdown culprits.

--
CPP-6109

Added: 
    clang/test/Analysis/ftime-trace-bind.cpp
    clang/test/Analysis/ftime-trace-removeDead.cpp

Modified: 
    clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
    clang/lib/StaticAnalyzer/Core/RegionStore.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 9545ce5f2569664..e3ec7c57571c8f3 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -74,6 +74,7 @@
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/GraphWriter.h"
 #include "llvm/Support/SaveAndRestore.h"
+#include "llvm/Support/TimeProfiler.h"
 #include "llvm/Support/raw_ostream.h"
 #include <cassert>
 #include <cstdint>
@@ -1031,6 +1032,7 @@ void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out,
                             const LocationContext *LC,
                             const Stmt *DiagnosticStmt,
                             ProgramPoint::Kind K) {
+  llvm::TimeTraceScope TimeScope("ExprEngine::removeDead");
   assert((K == ProgramPoint::PreStmtPurgeDeadSymbolsKind ||
           ReferenceStmt == nullptr || isa<ReturnStmt>(ReferenceStmt))
           && "PostStmt is not generally supported by the SymbolReaper yet");

diff  --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
index 6266878565c5243..d01b6ae55f61144 100644
--- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -29,6 +29,7 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
 #include "llvm/ADT/ImmutableMap.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/TimeProfiler.h"
 #include "llvm/Support/raw_ostream.h"
 #include <optional>
 #include <utility>
@@ -112,6 +113,13 @@ class BindingKey {
 
   LLVM_DUMP_METHOD void dump() const;
 };
+
+std::string locDescr(Loc L) {
+  std::string S;
+  llvm::raw_string_ostream OS(S);
+  L.dumpToStream(OS);
+  return OS.str();
+}
 } // end anonymous namespace
 
 BindingKey BindingKey::Make(const MemRegion *R, Kind k) {
@@ -2408,6 +2416,8 @@ StoreRef RegionStoreManager::killBinding(Store ST, Loc L) {
 
 RegionBindingsRef
 RegionStoreManager::bind(RegionBindingsConstRef B, Loc L, SVal V) {
+  llvm::TimeTraceScope TimeScope("RegionStoreManager::bind",
+                                 [&L]() { return locDescr(L); });
   // We only care about region locations.
   auto MemRegVal = L.getAs<loc::MemRegionVal>();
   if (!MemRegVal)
@@ -2514,6 +2524,8 @@ RegionBindingsRef
 RegionStoreManager::bindArray(RegionBindingsConstRef B,
                               const TypedValueRegion* R,
                               SVal Init) {
+  llvm::TimeTraceScope TimeScope("RegionStoreManager::bindArray",
+                                 [R]() { return R->getDescriptiveName(); });
 
   const ArrayType *AT =cast<ArrayType>(Ctx.getCanonicalType(R->getValueType()));
   QualType ElementTy = AT->getElementType();
@@ -2578,6 +2590,8 @@ RegionStoreManager::bindArray(RegionBindingsConstRef B,
 RegionBindingsRef RegionStoreManager::bindVector(RegionBindingsConstRef B,
                                                  const TypedValueRegion* R,
                                                  SVal V) {
+  llvm::TimeTraceScope TimeScope("RegionStoreManager::bindVector",
+                                 [R]() { return R->getDescriptiveName(); });
   QualType T = R->getValueType();
   const VectorType *VT = T->castAs<VectorType>(); // Use castAs for typedefs.
 
@@ -2700,6 +2714,8 @@ std::optional<RegionBindingsRef> RegionStoreManager::tryBindSmallStruct(
 RegionBindingsRef RegionStoreManager::bindStruct(RegionBindingsConstRef B,
                                                  const TypedValueRegion *R,
                                                  SVal V) {
+  llvm::TimeTraceScope TimeScope("RegionStoreManager::bindStruct",
+                                 [R]() { return R->getDescriptiveName(); });
   QualType T = R->getValueType();
   assert(T->isStructureOrClassType());
 
@@ -2818,6 +2834,8 @@ RegionBindingsRef
 RegionStoreManager::bindAggregate(RegionBindingsConstRef B,
                                   const TypedRegion *R,
                                   SVal Val) {
+  llvm::TimeTraceScope TimeScope("RegionStoreManager::bindAggregate",
+                                 [R]() { return R->getDescriptiveName(); });
   // Remove the old bindings, using 'R' as the root of all regions
   // we will invalidate. Then add the new binding.
   return removeSubRegionBindings(B, R).addBinding(R, BindingKey::Default, Val);

diff  --git a/clang/test/Analysis/ftime-trace-bind.cpp b/clang/test/Analysis/ftime-trace-bind.cpp
new file mode 100644
index 000000000000000..de121e4316e0328
--- /dev/null
+++ b/clang/test/Analysis/ftime-trace-bind.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core %s -ftime-trace=%t.raw.json -ftime-trace-granularity=0 -verify
+// RUN: %python -c 'import json, sys; print(json.dumps(json.load(sys.stdin), indent=4))' < %t.raw.json > %t.formatted.json
+// RUN: FileCheck --input-file=%t.formatted.json --check-prefix=CHECK %s
+
+// CHECK:          "name": "RegionStoreManager::bindArray",
+// CHECK-NEXT:     "args": {
+//
+// The below does not necessarily follow immediately,
+// depending on what parts of the array are initialized first.
+//
+// CHECK:              "detail": "'arr[0][1]'"
+// CHECK-NEXT:     }
+//
+// CHECK:              "detail": "'arr[0]'"
+// CHECK-NEXT:     }
+//
+// CHECK:              "detail": "'arr'"
+// CHECK-NEXT:     }
+
+int f() {
+    int arr[2][2][2] = {{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}};
+    return arr[1][0][1];
+}
+// expected-no-diagnostics

diff  --git a/clang/test/Analysis/ftime-trace-removeDead.cpp b/clang/test/Analysis/ftime-trace-removeDead.cpp
new file mode 100644
index 000000000000000..2ffd2ec45908c42
--- /dev/null
+++ b/clang/test/Analysis/ftime-trace-removeDead.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core %s -ftime-trace=%t.raw.json -ftime-trace-granularity=0 -verify
+// RUN: %python -c 'import json, sys; print(json.dumps(json.load(sys.stdin), indent=4))' < %t.raw.json > %t.formatted.json
+// RUN: FileCheck --input-file=%t.formatted.json --check-prefix=CHECK %s
+
+// The trace file is rather large, but it should contain at least one scope for removeDead:
+//
+// CHECK:          "name": "ExprEngine::removeDead"
+
+bool coin();
+int f() {
+    int x = 0;
+    int y = 0;
+    while (coin()) {
+        x = 1;
+    }
+    return x / y; // expected-warning{{Division by zero}}
+}


        


More information about the cfe-commits mailing list