[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
This commit is contained in:
committed by
GitHub
parent
3041dd5c20
commit
f5c4f271ab
@@ -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");
|
||||
|
||||
@@ -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 @@ public:
|
||||
|
||||
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);
|
||||
|
||||
24
clang/test/Analysis/ftime-trace-bind.cpp
Normal file
24
clang/test/Analysis/ftime-trace-bind.cpp
Normal file
@@ -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
|
||||
17
clang/test/Analysis/ftime-trace-removeDead.cpp
Normal file
17
clang/test/Analysis/ftime-trace-removeDead.cpp
Normal file
@@ -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}}
|
||||
}
|
||||
Reference in New Issue
Block a user