[clang] [analyzer] Add -ftime-trace scopes for region-store bindings and removeDead (PR #125884)
Arseniy Zaostrovnykh via cfe-commits
cfe-commits at lists.llvm.org
Wed Feb 5 09:03:28 PST 2025
https://github.com/necto created https://github.com/llvm/llvm-project/pull/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.
>From 8d2043190836370fe05347d2837593ffb45fb0a3 Mon Sep 17 00:00:00 2001
From: Arseniy Zaostrovnykh <necto.ne at gmail.com>
Date: Thu, 30 Jan 2025 11:38:01 +0100
Subject: [PATCH 1/2] Add time-trace scopes for binds, as they often take long
---
clang/lib/StaticAnalyzer/Core/RegionStore.cpp | 18 ++++++++++++++
clang/test/Analysis/ftime-trace-bind.cpp | 24 +++++++++++++++++++
2 files changed, 42 insertions(+)
create mode 100644 clang/test/Analysis/ftime-trace-bind.cpp
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
>From 7f58e00d6f7fc7a7dd9317085a2723e02e31b3f0 Mon Sep 17 00:00:00 2001
From: Arseniy Zaostrovnykh <necto.ne at gmail.com>
Date: Fri, 31 Jan 2025 14:02:46 +0100
Subject: [PATCH 2/2] Add time-trace scope for removeDead
---
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 2 ++
clang/test/Analysis/ftime-trace-removeDead.cpp | 17 +++++++++++++++++
2 files changed, 19 insertions(+)
create mode 100644 clang/test/Analysis/ftime-trace-removeDead.cpp
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/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