Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit 5d98994

Browse files
committed
Build up statistics about the work done for analysis based warnings.
Special detail is added for uninitialized variable analysis as this has serious performance problems than need to be tracked. Computing some of this data is expensive, for example walking the CFG to determine its size. To avoid doing that unless the stats data is going to be used, we thread a bit into the Sema object to track whether detailed stats should be collected or not. This bit is used to avoid computations whereever the computations are likely to be more expensive than checking the state of the flag. Thus, counters are in some cases unconditionally updated, but the more expensive (and less frequent) aggregation steps are skipped. With this patch, we're able to see that for 'gcc.c': *** Analysis Based Warnings Stats: 232 functions analyzed (0 w/o CFGs). 7151 CFG blocks built. 30 average CFG blocks per function. 1167 max CFG blocks per function. 163 functions analyzed for uninitialiazed variables 640 variables analyzed. 3 average variables per function. 94 max variables per function. 96409 block visits. 591 average block visits per function. 61546 max block visits per function. And for the reduced testcase in PR10183: *** Analysis Based Warnings Stats: 98 functions analyzed (0 w/o CFGs). 8526 CFG blocks built. 87 average CFG blocks per function. 7277 max CFG blocks per function. 68 functions analyzed for uninitialiazed variables 1359 variables analyzed. 19 average variables per function. 1196 max variables per function. 2540494 block visits. 37360 average block visits per function. 2536495 max block visits per function. That last number is the somewhat scary one that indicates the problem in PR10183. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@134494 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 786dcd9 commit 5d98994

File tree

8 files changed

+152
-17
lines changed

8 files changed

+152
-17
lines changed

include/clang/Analysis/Analyses/UninitializedValues.h

+8-2
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,16 @@ class UninitVariablesHandler {
3232
const VarDecl *vd,
3333
bool isAlwaysUninit) {}
3434
};
35-
35+
36+
struct UninitVariablesAnalysisStats {
37+
unsigned NumVariablesAnalyzed;
38+
unsigned NumBlockVisits;
39+
};
40+
3641
void runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg,
3742
AnalysisContext &ac,
38-
UninitVariablesHandler &handler);
43+
UninitVariablesHandler &handler,
44+
UninitVariablesAnalysisStats &stats);
3945

4046
}
4147
#endif

include/clang/Analysis/AnalysisContext.h

+5
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,11 @@ class AnalysisContext {
107107

108108
void dumpCFG();
109109

110+
/// \brief Returns true if we have built a CFG for this analysis context.
111+
/// Note that this doesn't correspond to whether or not a valid CFG exists, it
112+
/// corresponds to whether we *attempted* to build one.
113+
bool isCFGBuilt() const { return builtCFG; }
114+
110115
ParentMap &getParentMap();
111116
PseudoConstantAnalysis *getPseudoConstantAnalysis();
112117
LiveVariables *getLiveVariables();

include/clang/Sema/AnalysisBasedWarnings.h

+37
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,41 @@ class AnalysisBasedWarnings {
4949
enum VisitFlag { NotVisited = 0, Visited = 1, Pending = 2 };
5050
llvm::DenseMap<const FunctionDecl*, VisitFlag> VisitedFD;
5151

52+
/// \name Statistics
53+
/// @{
54+
55+
/// \brief Number of function CFGs built and analyzed.
56+
unsigned NumFunctionsAnalyzed;
57+
58+
/// \brief Number of functions for which the CFG could not be successfully
59+
/// built.
60+
unsigned NumFunctionsWithBadCFGs;
61+
62+
/// \brief Total number of blocks across all CFGs.
63+
unsigned NumCFGBlocks;
64+
65+
/// \brief Largest number of CFG blocks for a single function analyzed.
66+
unsigned MaxCFGBlocksPerFunction;
67+
68+
/// \brief Total number of CFGs with variables analyzed for uninitialized
69+
/// uses.
70+
unsigned NumUninitAnalysisFunctions;
71+
72+
/// \brief Total number of variables analyzed for uninitialized uses.
73+
unsigned NumUninitAnalysisVariables;
74+
75+
/// \brief Max number of variables analyzed for uninitialized uses in a single
76+
/// function.
77+
unsigned MaxUninitAnalysisVariablesPerFunction;
78+
79+
/// \brief Total number of block visits during uninitialized use analysis.
80+
unsigned NumUninitAnalysisBlockVisits;
81+
82+
/// \brief Max number of block visits during uninitialized use analysis of
83+
/// a single function.
84+
unsigned MaxUninitAnalysisBlockVisitsPerFunction;
85+
86+
/// @}
5287

5388
public:
5489
AnalysisBasedWarnings(Sema &s);
@@ -57,6 +92,8 @@ class AnalysisBasedWarnings {
5792
const Decl *D, const BlockExpr *blkExpr);
5893

5994
Policy getDefaultPolicy() { return DefaultPolicy; }
95+
96+
void PrintStats() const;
6097
};
6198

6299
}} // end namespace clang::sema

include/clang/Sema/Sema.h

+6-3
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,9 @@ class Sema {
193193
Diagnostic &Diags;
194194
SourceManager &SourceMgr;
195195

196+
/// \brief Flag indicating whether or not to collect detailed statistics.
197+
bool CollectStats;
198+
196199
/// \brief Source of additional semantic information.
197200
ExternalSemaSource *ExternalSource;
198201

@@ -689,7 +692,9 @@ class Sema {
689692
ASTContext &getASTContext() const { return Context; }
690693
ASTConsumer &getASTConsumer() const { return Consumer; }
691694
ASTMutationListener *getASTMutationListener() const;
692-
695+
696+
void PrintStats() const;
697+
693698
/// \brief Helper class that creates diagnostics with optional
694699
/// template instantiation stacks.
695700
///
@@ -5849,8 +5854,6 @@ class Sema {
58495854
llvm::SmallVectorImpl<CodeCompletionResult> &Results);
58505855
//@}
58515856

5852-
void PrintStats() const {}
5853-
58545857
//===--------------------------------------------------------------------===//
58555858
// Extra semantic analysis beyond the C type system
58565859

lib/Analysis/UninitializedValues.cpp

+13-7
Original file line numberDiff line numberDiff line change
@@ -654,15 +654,19 @@ static bool runOnBlock(const CFGBlock *block, const CFG &cfg,
654654
return vals.updateValueVectorWithScratch(block);
655655
}
656656

657-
void clang::runUninitializedVariablesAnalysis(const DeclContext &dc,
658-
const CFG &cfg,
659-
AnalysisContext &ac,
660-
UninitVariablesHandler &handler) {
657+
void clang::runUninitializedVariablesAnalysis(
658+
const DeclContext &dc,
659+
const CFG &cfg,
660+
AnalysisContext &ac,
661+
UninitVariablesHandler &handler,
662+
UninitVariablesAnalysisStats &stats) {
661663
CFGBlockValues vals(cfg);
662664
vals.computeSetOfDeclarations(dc);
663665
if (vals.hasNoDeclarations())
664666
return;
665667

668+
stats.NumVariablesAnalyzed = vals.getNumEntries();
669+
666670
// Mark all variables uninitialized at the entry.
667671
const CFGBlock &entry = cfg.getEntry();
668672
for (CFGBlock::const_succ_iterator i = entry.succ_begin(),
@@ -684,19 +688,21 @@ void clang::runUninitializedVariablesAnalysis(const DeclContext &dc,
684688

685689
while (const CFGBlock *block = worklist.dequeue()) {
686690
// Did the block change?
687-
bool changed = runOnBlock(block, cfg, ac, vals, wasAnalyzed);
691+
bool changed = runOnBlock(block, cfg, ac, vals, wasAnalyzed);
692+
++stats.NumBlockVisits;
688693
if (changed || !previouslyVisited[block->getBlockID()])
689694
worklist.enqueueSuccessors(block);
690695
previouslyVisited[block->getBlockID()] = true;
691696
}
692697

693698
// Run through the blocks one more time, and report uninitialized variabes.
694699
for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) {
695-
if (wasAnalyzed[(*BI)->getBlockID()])
700+
if (wasAnalyzed[(*BI)->getBlockID()]) {
696701
runOnBlock(*BI, cfg, ac, vals, wasAnalyzed, &handler,
697702
/* flagBlockUses */ true);
703+
++stats.NumBlockVisits;
704+
}
698705
}
699706
}
700707

701708
UninitVariablesHandler::~UninitVariablesHandler() {}
702-

lib/Parse/ParseAST.cpp

+6-1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ void clang::ParseAST(Sema &S, bool PrintStats) {
5757
Stmt::CollectingStats(true);
5858
}
5959

60+
// Also turn on collection of stats inside of the Sema object.
61+
bool OldCollectStats = PrintStats;
62+
std::swap(OldCollectStats, S.CollectStats);
63+
6064
ASTConsumer *Consumer = &S.getASTConsumer();
6165

6266
llvm::OwningPtr<Parser> ParseOP(new Parser(S.getPreprocessor(), S));
@@ -95,7 +99,8 @@ void clang::ParseAST(Sema &S, bool PrintStats) {
9599
Consumer->HandleTopLevelDecl(DeclGroupRef(*I));
96100

97101
Consumer->HandleTranslationUnit(S.getASTContext());
98-
102+
103+
std::swap(OldCollectStats, S.CollectStats);
99104
if (PrintStats) {
100105
llvm::errs() << "\nSTATISTICS:\n";
101106
P.getActions().PrintStats();

lib/Sema/AnalysisBasedWarnings.cpp

+66-2
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,11 @@ clang::sema::AnalysisBasedWarnings::Policy::Policy() {
597597
enableCheckUnreachable = 0;
598598
}
599599

600-
clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) : S(s) {
600+
clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s)
601+
: S(s),
602+
NumFunctionsAnalyzed(0),
603+
NumCFGBlocks(0),
604+
MaxCFGBlocksPerFunction(0) {
601605
Diagnostic &D = S.getDiagnostics();
602606
DefaultPolicy.enableCheckUnreachable = (unsigned)
603607
(D.getDiagnosticLevel(diag::warn_unreachable, SourceLocation()) !=
@@ -713,8 +717,68 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
713717
!= Diagnostic::Ignored) {
714718
if (CFG *cfg = AC.getCFG()) {
715719
UninitValsDiagReporter reporter(S);
720+
UninitVariablesAnalysisStats stats = {};
716721
runUninitializedVariablesAnalysis(*cast<DeclContext>(D), *cfg, AC,
717-
reporter);
722+
reporter, stats);
723+
724+
if (S.CollectStats && stats.NumVariablesAnalyzed > 0) {
725+
++NumUninitAnalysisFunctions;
726+
NumUninitAnalysisVariables += stats.NumVariablesAnalyzed;
727+
NumUninitAnalysisBlockVisits += stats.NumBlockVisits;
728+
MaxUninitAnalysisVariablesPerFunction =
729+
std::max(MaxUninitAnalysisVariablesPerFunction,
730+
stats.NumVariablesAnalyzed);
731+
MaxUninitAnalysisBlockVisitsPerFunction =
732+
std::max(MaxUninitAnalysisBlockVisitsPerFunction,
733+
stats.NumBlockVisits);
734+
}
735+
}
736+
}
737+
738+
// Collect statistics about the CFG if it was built.
739+
if (S.CollectStats && AC.isCFGBuilt()) {
740+
++NumFunctionsAnalyzed;
741+
if (CFG *cfg = AC.getCFG()) {
742+
// If we successfully built a CFG for this context, record some more
743+
// detail information about it.
744+
unsigned NumBlocks = std::distance(cfg->begin(), cfg->end());
745+
NumCFGBlocks += NumBlocks;
746+
MaxCFGBlocksPerFunction = std::max(MaxCFGBlocksPerFunction,
747+
NumBlocks);
748+
} else {
749+
++NumFunctionsWithBadCFGs;
718750
}
719751
}
720752
}
753+
754+
void clang::sema::AnalysisBasedWarnings::PrintStats() const {
755+
llvm::errs() << "\n*** Analysis Based Warnings Stats:\n";
756+
757+
unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs;
758+
unsigned AvgCFGBlocksPerFunction =
759+
!NumCFGsBuilt ? 0 : NumCFGBlocks/NumCFGsBuilt;
760+
llvm::errs() << NumFunctionsAnalyzed << " functions analyzed ("
761+
<< NumFunctionsWithBadCFGs << " w/o CFGs).\n"
762+
<< " " << NumCFGBlocks << " CFG blocks built.\n"
763+
<< " " << AvgCFGBlocksPerFunction
764+
<< " average CFG blocks per function.\n"
765+
<< " " << MaxCFGBlocksPerFunction
766+
<< " max CFG blocks per function.\n";
767+
768+
unsigned AvgUninitVariablesPerFunction = !NumUninitAnalysisFunctions ? 0
769+
: NumUninitAnalysisVariables/NumUninitAnalysisFunctions;
770+
unsigned AvgUninitBlockVisitsPerFunction = !NumUninitAnalysisFunctions ? 0
771+
: NumUninitAnalysisBlockVisits/NumUninitAnalysisFunctions;
772+
llvm::errs() << NumUninitAnalysisFunctions
773+
<< " functions analyzed for uninitialiazed variables\n"
774+
<< " " << NumUninitAnalysisVariables << " variables analyzed.\n"
775+
<< " " << AvgUninitVariablesPerFunction
776+
<< " average variables per function.\n"
777+
<< " " << MaxUninitAnalysisVariablesPerFunction
778+
<< " max variables per function.\n"
779+
<< " " << NumUninitAnalysisBlockVisits << " block visits.\n"
780+
<< " " << AvgUninitBlockVisitsPerFunction
781+
<< " average block visits per function.\n"
782+
<< " " << MaxUninitAnalysisBlockVisitsPerFunction
783+
<< " max block visits per function.\n";
784+
}

lib/Sema/Sema.cpp

+11-2
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
141141
: TheTargetAttributesSema(0), FPFeatures(pp.getLangOptions()),
142142
LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer),
143143
Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
144-
ExternalSource(0), CodeCompleter(CodeCompleter), CurContext(0),
145-
PackContext(0), MSStructPragmaOn(false), VisContext(0),
144+
CollectStats(false), ExternalSource(0), CodeCompleter(CodeCompleter),
145+
CurContext(0), PackContext(0), MSStructPragmaOn(false), VisContext(0),
146146
ExprNeedsCleanups(0), LateTemplateParser(0), OpaqueParser(0),
147147
IdResolver(pp.getLangOptions()), CXXTypeInfoDecl(0), MSVCGuidDecl(0),
148148
GlobalNewDeleteDeclared(false),
@@ -234,6 +234,15 @@ ASTMutationListener *Sema::getASTMutationListener() const {
234234
return getASTConsumer().GetASTMutationListener();
235235
}
236236

237+
/// \brief Print out statistics about the semantic analysis.
238+
void Sema::PrintStats() const {
239+
llvm::errs() << "\n*** Semantic Analysis Stats:\n";
240+
llvm::errs() << NumSFINAEErrors << " SFINAE diagnostics trapped.\n";
241+
242+
BumpAlloc.PrintStats();
243+
AnalysisWarnings.PrintStats();
244+
}
245+
237246
/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast.
238247
/// If there is already an implicit cast, merge into the existing one.
239248
/// The result is of the given category.

0 commit comments

Comments
 (0)