-
Notifications
You must be signed in to change notification settings - Fork 15k
[clang][analyzer] Add SyntaxRunningTime per-entry-point metric #163341
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
Conversation
Per-entry-point metrics are captured during the path-sensitive analysis time. For that reason, it is not trivial to add the syntax-only analysis time as it runs in a separate stage. Luckily syntax-only analysis is done before path-senstivie analysis. I use the function summary field to keep the syntax-only anlaysis time once syntax analysis is done, and then forward it to the per-EP metrics snapshot during the path-sensitive analysis. -- CPP-7099
|
@llvm/pr-subscribers-clang-static-analyzer-1 @llvm/pr-subscribers-clang Author: Arseniy Zaostrovnykh (necto) ChangesPer-entry-point metrics are captured during the path-sensitive analysis time. For that reason, it is not trivial to add the syntax-only analysis time as it runs in a separate stage. Luckily syntax-only analysis is done before path-senstivie analysis. I use the function summary field to keep the syntax-only anlaysis time once syntax analysis is done, and then forward it to the per-EP metrics snapshot during the path-sensitive analysis. -- CPP-7099 Full diff: https://github.com/llvm/llvm-project/pull/163341.diff 3 Files Affected:
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h
index 761395260a0cf..db4aec7c84754 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h
@@ -48,6 +48,9 @@ class FunctionSummariesTy {
/// The number of times the function has been inlined.
unsigned TimesInlined : 32;
+ /// Running time for syntax-based AST analysis in milliseconds.
+ std::optional<unsigned> SyntaxRunningTime = std::nullopt;
+
FunctionSummary()
: TotalBasicBlocks(0), InlineChecked(0), MayInline(0),
TimesInlined(0) {}
@@ -69,6 +72,11 @@ class FunctionSummariesTy {
return I;
}
+ FunctionSummary const *findSummary(const Decl *D) const {
+ auto I = Map.find(D);
+ return I == Map.end() ? nullptr : &I->second;
+ }
+
void markMayInline(const Decl *D) {
MapTy::iterator I = findOrInsertSummary(D);
I->second.InlineChecked = 1;
diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index 4efde59aab763..1775280fa7e1e 100644
--- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -721,6 +721,7 @@ AnalysisConsumer::getModeForDecl(Decl *D, AnalysisMode Mode) {
}
static UnsignedEPStat PathRunningTime("PathRunningTime");
+static UnsignedEPStat SyntaxRunningTime("SyntaxRunningTime");
void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode,
ExprEngine::InliningModes IMode,
@@ -759,6 +760,8 @@ void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode,
SyntaxCheckTimer->stopTimer();
llvm::TimeRecord CheckerEndTime = SyntaxCheckTimer->getTotalTime();
CheckerEndTime -= CheckerStartTime;
+ FunctionSummaries.findOrInsertSummary(D)->second.SyntaxRunningTime =
+ std::lround(CheckerEndTime.getWallTime() * 1000);
DisplayTime(CheckerEndTime);
if (AnalyzerTimers && ShouldClearTimersToPreventDisplayingThem) {
AnalyzerTimers->clear();
@@ -776,6 +779,36 @@ void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode,
}
}
+namespace {
+template <typename DeclT>
+static clang::Decl *preferDefinitionImpl(clang::Decl *D) {
+ if (auto *X = dyn_cast<DeclT>(D))
+ if (auto *Def = X->getDefinition())
+ return Def;
+ return D;
+}
+
+template <> clang::Decl *preferDefinitionImpl<ObjCMethodDecl>(clang::Decl *D) {
+ if (const auto *X = dyn_cast<ObjCMethodDecl>(D)) {
+ for (auto *I : X->redecls())
+ if (I->hasBody())
+ return I;
+ }
+ return D;
+}
+
+static Decl *getDefinitionOrCanonicalDecl(Decl *D) {
+ assert(D);
+ D = D->getCanonicalDecl();
+ D = preferDefinitionImpl<VarDecl>(D);
+ D = preferDefinitionImpl<FunctionDecl>(D);
+ D = preferDefinitionImpl<TagDecl>(D);
+ D = preferDefinitionImpl<ObjCMethodDecl>(D);
+ assert(D);
+ return D;
+}
+} // namespace
+
//===----------------------------------------------------------------------===//
// Path-sensitive checking.
//===----------------------------------------------------------------------===//
@@ -792,6 +825,16 @@ void AnalysisConsumer::RunPathSensitiveChecks(Decl *D,
if (!Mgr->getAnalysisDeclContext(D)->getAnalysis<RelaxedLiveVariables>())
return;
+ const Decl *DefDecl = getDefinitionOrCanonicalDecl(D);
+
+ // Get the SyntaxRunningTime from the function summary, because it is computed
+ // during the AM_Syntax analysis, which is done at a different point in time
+ // and in different order, but always before AM_Path.
+ if (const auto *Summary = FunctionSummaries.findSummary(DefDecl);
+ Summary && Summary->SyntaxRunningTime.has_value()) {
+ SyntaxRunningTime.set(*Summary->SyntaxRunningTime);
+ }
+
ExprEngine Eng(CTU, *Mgr, VisitedCallees, &FunctionSummaries, IMode);
// Execute the worklist algorithm.
diff --git a/clang/test/Analysis/analyzer-stats/entry-point-stats.cpp b/clang/test/Analysis/analyzer-stats/entry-point-stats.cpp
index 2a0caad5950ec..c0c13d88a278d 100644
--- a/clang/test/Analysis/analyzer-stats/entry-point-stats.cpp
+++ b/clang/test/Analysis/analyzer-stats/entry-point-stats.cpp
@@ -9,6 +9,7 @@
// CHECK-NEXT: "File": "{{.*}}entry-point-stats.cpp",
// CHECK-NEXT: "DebugName": "fib(unsigned int)",
// CHECK-NEXT: "PathRunningTime": "{{[0-9]+}}",
+// CHECK-NEXT: "SyntaxRunningTime": "{{[0-9]+}}",
// CHECK-NEXT: "MaxBugClassSize": "{{[0-9]+}}",
// CHECK-NEXT: "MaxCFGSize": "{{[0-9]+}}",
// CHECK-NEXT: "MaxQueueSize": "{{[0-9]+}}",
@@ -46,6 +47,7 @@
// CHECK-NEXT: "File": "{{.*}}entry-point-stats.cpp",
// CHECK-NEXT: "DebugName": "main(int, char **)",
// CHECK-NEXT: "PathRunningTime": "{{[0-9]+}}",
+// CHECK-NEXT: "SyntaxRunningTime": "{{[0-9]+}}",
// CHECK-NEXT: "MaxBugClassSize": "{{[0-9]+}}",
// CHECK-NEXT: "MaxCFGSize": "{{[0-9]+}}",
// CHECK-NEXT: "MaxQueueSize": "{{[0-9]+}}",
|
|
This is the final PR out of the triple replacing #162089. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me, I don't see any issues.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Have you checked that now the findSummary would get hits when it's using the DefDecl?
I have checked now. in the context of |
Per-entry-point metrics are captured during the path-sensitive analysis time. For that reason, it is not trivial to add the syntax-only analysis time as it runs in a separate stage. Luckily syntax-only analysis is done before path-senstivie analysis.
I use the function summary field to keep the syntax-only anlaysis time once syntax analysis is done, and then forward it to the per-EP metrics snapshot during the path-sensitive analysis.
Note that some of the entry points that were analyzed by syntax-only rules may be missing in the CSV export if they were never analyzed by path-sensitive rules. Conversely, if a function is analyzed with path-sensitive analysis but not syntax-only analysis, its
SyntaxRunningTimewill be empty.--
CPP-7099