]> granicus.if.org Git - clang/commitdiff
Build up statistics about the work done for analysis based warnings.
authorChandler Carruth <chandlerc@gmail.com>
Wed, 6 Jul 2011 16:21:37 +0000 (16:21 +0000)
committerChandler Carruth <chandlerc@gmail.com>
Wed, 6 Jul 2011 16:21:37 +0000 (16:21 +0000)
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

include/clang/Analysis/Analyses/UninitializedValues.h
include/clang/Analysis/AnalysisContext.h
include/clang/Sema/AnalysisBasedWarnings.h
include/clang/Sema/Sema.h
lib/Analysis/UninitializedValues.cpp
lib/Parse/ParseAST.cpp
lib/Sema/AnalysisBasedWarnings.cpp
lib/Sema/Sema.cpp

index b966f3a90ffff7831d51f08cf31a0e5ba5aa4c80..badb493a9df4ede9781f49107065e4b9d52e0adb 100644 (file)
@@ -32,10 +32,16 @@ public:
                                          const VarDecl *vd,
                                          bool isAlwaysUninit) {}
 };
-  
+
+struct UninitVariablesAnalysisStats {
+  unsigned NumVariablesAnalyzed;
+  unsigned NumBlockVisits;
+};
+
 void runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg,
                                        AnalysisContext &ac,
-                                       UninitVariablesHandler &handler);
+                                       UninitVariablesHandler &handler,
+                                       UninitVariablesAnalysisStats &stats);
 
 }
 #endif
index 66c12a5384d4c529a3807033c26821739dff6dee..6a1876e6590089429c3cb1c2c680ad455264abef 100644 (file)
@@ -107,6 +107,11 @@ public:
 
   void dumpCFG();
 
+  /// \brief Returns true if we have built a CFG for this analysis context.
+  /// Note that this doesn't correspond to whether or not a valid CFG exists, it
+  /// corresponds to whether we *attempted* to build one.
+  bool isCFGBuilt() const { return builtCFG; }
+
   ParentMap &getParentMap();
   PseudoConstantAnalysis *getPseudoConstantAnalysis();
   LiveVariables *getLiveVariables();
index b7ae25486f4f7f4d36576721a369ab0fcc441310..8e781cd521c2f017585db40e3cdfd774c3df0d49 100644 (file)
@@ -49,6 +49,41 @@ private:
   enum VisitFlag { NotVisited = 0, Visited = 1, Pending = 2 };
   llvm::DenseMap<const FunctionDecl*, VisitFlag> VisitedFD;
 
+  /// \name Statistics
+  /// @{
+
+  /// \brief Number of function CFGs built and analyzed.
+  unsigned NumFunctionsAnalyzed;
+
+  /// \brief Number of functions for which the CFG could not be successfully
+  /// built.
+  unsigned NumFunctionsWithBadCFGs;
+
+  /// \brief Total number of blocks across all CFGs.
+  unsigned NumCFGBlocks;
+
+  /// \brief Largest number of CFG blocks for a single function analyzed.
+  unsigned MaxCFGBlocksPerFunction;
+
+  /// \brief Total number of CFGs with variables analyzed for uninitialized
+  /// uses.
+  unsigned NumUninitAnalysisFunctions;
+
+  /// \brief Total number of variables analyzed for uninitialized uses.
+  unsigned NumUninitAnalysisVariables;
+
+  /// \brief Max number of variables analyzed for uninitialized uses in a single
+  /// function.
+  unsigned MaxUninitAnalysisVariablesPerFunction;
+
+  /// \brief Total number of block visits during uninitialized use analysis.
+  unsigned NumUninitAnalysisBlockVisits;
+
+  /// \brief Max number of block visits during uninitialized use analysis of
+  /// a single function.
+  unsigned MaxUninitAnalysisBlockVisitsPerFunction;
+
+  /// @}
 
 public:
   AnalysisBasedWarnings(Sema &s);
@@ -57,6 +92,8 @@ public:
                      const Decl *D, const BlockExpr *blkExpr);
 
   Policy getDefaultPolicy() { return DefaultPolicy; }
+
+  void PrintStats() const;
 };
 
 }} // end namespace clang::sema
index 67a26786907f43b6aac44a4a50d4bd1b5421c403..468240487339f3d870c4192bfbe0c72b65fa7b52 100644 (file)
@@ -193,6 +193,9 @@ public:
   Diagnostic &Diags;
   SourceManager &SourceMgr;
 
+  /// \brief Flag indicating whether or not to collect detailed statistics.
+  bool CollectStats;
+
   /// \brief Source of additional semantic information.
   ExternalSemaSource *ExternalSource;
 
@@ -689,7 +692,9 @@ public:
   ASTContext &getASTContext() const { return Context; }
   ASTConsumer &getASTConsumer() const { return Consumer; }
   ASTMutationListener *getASTMutationListener() const;
-  
+
+  void PrintStats() const;
+
   /// \brief Helper class that creates diagnostics with optional
   /// template instantiation stacks.
   ///
@@ -5849,8 +5854,6 @@ public:
                   llvm::SmallVectorImpl<CodeCompletionResult> &Results);
   //@}
 
-  void PrintStats() const {}
-
   //===--------------------------------------------------------------------===//
   // Extra semantic analysis beyond the C type system
 
index e80e282813af61f78e16e303f0c2683b757a79c6..96cae9d1f47be60ed3e8c90cee93c6a2014c9dc7 100644 (file)
@@ -654,15 +654,19 @@ static bool runOnBlock(const CFGBlock *block, const CFG &cfg,
   return vals.updateValueVectorWithScratch(block);
 }
 
-void clang::runUninitializedVariablesAnalysis(const DeclContext &dc,
-                                              const CFG &cfg,
-                                              AnalysisContext &ac,
-                                              UninitVariablesHandler &handler) {
+void clang::runUninitializedVariablesAnalysis(
+    const DeclContext &dc,
+    const CFG &cfg,
+    AnalysisContext &ac,
+    UninitVariablesHandler &handler,
+    UninitVariablesAnalysisStats &stats) {
   CFGBlockValues vals(cfg);
   vals.computeSetOfDeclarations(dc);
   if (vals.hasNoDeclarations())
     return;
 
+  stats.NumVariablesAnalyzed = vals.getNumEntries();
+
   // Mark all variables uninitialized at the entry.
   const CFGBlock &entry = cfg.getEntry();
   for (CFGBlock::const_succ_iterator i = entry.succ_begin(), 
@@ -684,7 +688,8 @@ void clang::runUninitializedVariablesAnalysis(const DeclContext &dc,
 
   while (const CFGBlock *block = worklist.dequeue()) {
     // Did the block change?
-    bool changed = runOnBlock(block, cfg, ac, vals, wasAnalyzed);    
+    bool changed = runOnBlock(block, cfg, ac, vals, wasAnalyzed);
+    ++stats.NumBlockVisits;
     if (changed || !previouslyVisited[block->getBlockID()])
       worklist.enqueueSuccessors(block);    
     previouslyVisited[block->getBlockID()] = true;
@@ -692,11 +697,12 @@ void clang::runUninitializedVariablesAnalysis(const DeclContext &dc,
   
   // Run through the blocks one more time, and report uninitialized variabes.
   for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) {
-    if (wasAnalyzed[(*BI)->getBlockID()])
+    if (wasAnalyzed[(*BI)->getBlockID()]) {
       runOnBlock(*BI, cfg, ac, vals, wasAnalyzed, &handler,
                  /* flagBlockUses */ true);
+      ++stats.NumBlockVisits;
+    }
   }
 }
 
 UninitVariablesHandler::~UninitVariablesHandler() {}
-
index 00685362fd2963051fd106617406839cecdf712c..56584c96180bf9eae956738922ef368e338d5e42 100644 (file)
@@ -57,6 +57,10 @@ void clang::ParseAST(Sema &S, bool PrintStats) {
     Stmt::CollectingStats(true);
   }
 
+  // Also turn on collection of stats inside of the Sema object.
+  bool OldCollectStats = PrintStats;
+  std::swap(OldCollectStats, S.CollectStats);
+
   ASTConsumer *Consumer = &S.getASTConsumer();
 
   llvm::OwningPtr<Parser> ParseOP(new Parser(S.getPreprocessor(), S));
@@ -95,7 +99,8 @@ void clang::ParseAST(Sema &S, bool PrintStats) {
     Consumer->HandleTopLevelDecl(DeclGroupRef(*I));
   
   Consumer->HandleTranslationUnit(S.getASTContext());
-  
+
+  std::swap(OldCollectStats, S.CollectStats);
   if (PrintStats) {
     llvm::errs() << "\nSTATISTICS:\n";
     P.getActions().PrintStats();
index e560ef8a5c0ee414340c3987f19c17746eb7bcb1..8a4634df2f4d39f7814616d2819295b8c9ca711c 100644 (file)
@@ -597,7 +597,11 @@ clang::sema::AnalysisBasedWarnings::Policy::Policy() {
   enableCheckUnreachable = 0;
 }
 
-clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) : S(s) {
+clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s)
+  : S(s),
+    NumFunctionsAnalyzed(0),
+    NumCFGBlocks(0),
+    MaxCFGBlocksPerFunction(0) {
   Diagnostic &D = S.getDiagnostics();
   DefaultPolicy.enableCheckUnreachable = (unsigned)
     (D.getDiagnosticLevel(diag::warn_unreachable, SourceLocation()) !=
@@ -713,8 +717,68 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
       != Diagnostic::Ignored) {
     if (CFG *cfg = AC.getCFG()) {
       UninitValsDiagReporter reporter(S);
+      UninitVariablesAnalysisStats stats = {};
       runUninitializedVariablesAnalysis(*cast<DeclContext>(D), *cfg, AC,
-                                        reporter);
+                                        reporter, stats);
+
+      if (S.CollectStats && stats.NumVariablesAnalyzed > 0) {
+        ++NumUninitAnalysisFunctions;
+        NumUninitAnalysisVariables += stats.NumVariablesAnalyzed;
+        NumUninitAnalysisBlockVisits += stats.NumBlockVisits;
+        MaxUninitAnalysisVariablesPerFunction =
+            std::max(MaxUninitAnalysisVariablesPerFunction,
+                     stats.NumVariablesAnalyzed);
+        MaxUninitAnalysisBlockVisitsPerFunction =
+            std::max(MaxUninitAnalysisBlockVisitsPerFunction,
+                     stats.NumBlockVisits);
+      }
+    }
+  }
+
+  // Collect statistics about the CFG if it was built.
+  if (S.CollectStats && AC.isCFGBuilt()) {
+    ++NumFunctionsAnalyzed;
+    if (CFG *cfg = AC.getCFG()) {
+      // If we successfully built a CFG for this context, record some more
+      // detail information about it.
+      unsigned NumBlocks = std::distance(cfg->begin(), cfg->end());
+      NumCFGBlocks += NumBlocks;
+      MaxCFGBlocksPerFunction = std::max(MaxCFGBlocksPerFunction,
+                                         NumBlocks);
+    } else {
+      ++NumFunctionsWithBadCFGs;
     }
   }
 }
+
+void clang::sema::AnalysisBasedWarnings::PrintStats() const {
+  llvm::errs() << "\n*** Analysis Based Warnings Stats:\n";
+
+  unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs;
+  unsigned AvgCFGBlocksPerFunction =
+      !NumCFGsBuilt ? 0 : NumCFGBlocks/NumCFGsBuilt;
+  llvm::errs() << NumFunctionsAnalyzed << " functions analyzed ("
+               << NumFunctionsWithBadCFGs << " w/o CFGs).\n"
+               << "  " << NumCFGBlocks << " CFG blocks built.\n"
+               << "  " << AvgCFGBlocksPerFunction
+               << " average CFG blocks per function.\n"
+               << "  " << MaxCFGBlocksPerFunction
+               << " max CFG blocks per function.\n";
+
+  unsigned AvgUninitVariablesPerFunction = !NumUninitAnalysisFunctions ? 0
+      : NumUninitAnalysisVariables/NumUninitAnalysisFunctions;
+  unsigned AvgUninitBlockVisitsPerFunction = !NumUninitAnalysisFunctions ? 0
+      : NumUninitAnalysisBlockVisits/NumUninitAnalysisFunctions;
+  llvm::errs() << NumUninitAnalysisFunctions
+               << " functions analyzed for uninitialiazed variables\n"
+               << "  " << NumUninitAnalysisVariables << " variables analyzed.\n"
+               << "  " << AvgUninitVariablesPerFunction
+               << " average variables per function.\n"
+               << "  " << MaxUninitAnalysisVariablesPerFunction
+               << " max variables per function.\n"
+               << "  " << NumUninitAnalysisBlockVisits << " block visits.\n"
+               << "  " << AvgUninitBlockVisitsPerFunction
+               << " average block visits per function.\n"
+               << "  " << MaxUninitAnalysisBlockVisitsPerFunction
+               << " max block visits per function.\n";
+}
index 9550f9aad2e58fa96d6e88d4b4ed88d326952a03..fdf3bb3cb0125c76eb92d81f9df82618cf8c8d6f 100644 (file)
@@ -141,8 +141,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
   : TheTargetAttributesSema(0), FPFeatures(pp.getLangOptions()),
     LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer),
     Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
-    ExternalSource(0), CodeCompleter(CodeCompleter), CurContext(0), 
-    PackContext(0), MSStructPragmaOn(false), VisContext(0),
+    CollectStats(false), ExternalSource(0), CodeCompleter(CodeCompleter),
+    CurContext(0), PackContext(0), MSStructPragmaOn(false), VisContext(0),
     ExprNeedsCleanups(0), LateTemplateParser(0), OpaqueParser(0),
     IdResolver(pp.getLangOptions()), CXXTypeInfoDecl(0), MSVCGuidDecl(0),
     GlobalNewDeleteDeclared(false), 
@@ -234,6 +234,15 @@ ASTMutationListener *Sema::getASTMutationListener() const {
   return getASTConsumer().GetASTMutationListener();
 }
 
+/// \brief Print out statistics about the semantic analysis.
+void Sema::PrintStats() const {
+  llvm::errs() << "\n*** Semantic Analysis Stats:\n";
+  llvm::errs() << NumSFINAEErrors << " SFINAE diagnostics trapped.\n";
+
+  BumpAlloc.PrintStats();
+  AnalysisWarnings.PrintStats();
+}
+
 /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast.
 /// If there is already an implicit cast, merge into the existing one.
 /// The result is of the given category.