avt77 updated this revision to Diff 158542.
avt77 added a comment.

efriedma, I removed redundant RAII objects but I still have the following:

1.0800 (271) _ZSt7declvalv (*)
 1.0840 (273) _ZSt7declvalv (*)
 1.0880 (269) _ZSt7declvalv (*)
 1.1000 (276) _ZSt7declvalv (*)
 1.1200 (282) _ZSt7declvalv (*)
 1.1360 (279) _ZSt7declvalv (*)
 1.1440 (286) _ZSt7declvalv (*)
 1.1760 (292) _ZSt7declvalv (*)
 1.1760 (295) _ZSt7declvalv (*)
 1.1800 (294) _ZSt7declvalv (*)
 1.1880 (298) _ZSt7declvalv (*)
 1.5960 (397) _ZSt7declvalv (*)

Every line corresponds to one unit and the number in parenthesis means the 
number of times we're dealing with the given function during the compilation of 
one unit. You say it's impossible but one time invocation of this function 
costs 0.0040 and 397 times invocations cost 1.588 (very close to the above 
number).

Do you have any ideas how to deal with all this stuff? Should I add/remove 
RAIIs somewhere?


https://reviews.llvm.org/D47196

Files:
  include/clang/Driver/CC1Options.td
  include/clang/Frontend/CodeGenOptions.h
  include/clang/Frontend/Utils.h
  lib/Analysis/AnalysisDeclContext.cpp
  lib/CodeGen/CGExpr.cpp
  lib/CodeGen/CodeGenAction.cpp
  lib/CodeGen/CodeGenFunction.cpp
  lib/CodeGen/CodeGenModule.cpp
  lib/Frontend/CompilerInvocation.cpp
  lib/Frontend/FrontendTiming.cpp
  lib/Parse/CMakeLists.txt
  lib/Parse/ParseCXXInlineMethods.cpp
  lib/Parse/ParseTemplate.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaLambda.cpp
  lib/Sema/SemaOverload.cpp
  lib/Sema/SemaTemplateDeduction.cpp
  lib/Sema/SemaTemplateInstantiate.cpp
  lib/Sema/TreeTransform.h
  test/Frontend/ftime-report-template-decl.cpp
  test/Headers/opencl-c-header.cl

Index: test/Headers/opencl-c-header.cl
===================================================================
--- test/Headers/opencl-c-header.cl
+++ test/Headers/opencl-c-header.cl
@@ -71,4 +71,5 @@
 }
 #endif //__OPENCL_C_VERSION__
 
-// CHECK-MOD: Reading modules
+// CHECK-DAG-MOD: Clang Timers: CodeGen Functions
+// CHECK-DAG-MOD: Reading modules
Index: test/Frontend/ftime-report-template-decl.cpp
===================================================================
--- test/Frontend/ftime-report-template-decl.cpp
+++ test/Frontend/ftime-report-template-decl.cpp
@@ -3,9 +3,15 @@
 
 // Template function declarations
 template <typename T>
-void foo();
+T foo(T bar) {
+  T Result = bar * bar + bar / 1.2 + bar;
+  return Result;
+};
 template <typename T, typename U>
-void foo();
+T foo(T bar, U bar2) {
+  T Result = bar2 * bar + bar / 1.2 + bar2;
+  return Result;
+};
 
 // Template function definitions.
 template <typename T>
@@ -130,9 +136,15 @@
 template <typename U>
 oneT L<0>::O<char>::Fun(U) { return one; }
 
-void Instantiate() {
+double Instantiate() {
   sassert(sizeof(L<0>::O<int>::Fun(0)) == sizeof(one));
   sassert(sizeof(L<0>::O<char>::Fun(0)) == sizeof(one));
+  int R1 = foo<int>(123) + foo<double>(177.2) - foo<double>(331.442);
+  char R2 = foo<char, int>('d', 1234) * foo<double>(1.26);
+  int R3 = foo<double>(1.2) + foo<double>(11.22) / foo<double>(66.77);
+  double R4 = foo<double, int>(34.56, 1234);
+  double R5 = R1 + R2 * R3 - R4 + one[0] * foo<double>(15.52) - two[1] / foo<double>(51.25);
+  return R5 * R1 + R4 / R3 + R2;
 }
 }
 
@@ -150,7 +162,10 @@
 };
 _Wrap_alloc<int>::rebind<int> w;
 
-// CHECK: Miscellaneous Ungrouped Timers
+// FIXME:  We need more complex test to increase the compilation time;
+// otherwise we see the foolowing message from time to time only.
+// VIOLATILE-CHECK: Clang Timers: CodeGen Functions
+// CHECK-DAG: Miscellaneous Ungrouped Timers
 // CHECK-DAG: LLVM IR Generation Time
 // CHECK-DAG: Code Generation Time
 // CHECK: Total
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -27,6 +27,7 @@
 #include "clang/AST/StmtCXX.h"
 #include "clang/AST/StmtObjC.h"
 #include "clang/AST/StmtOpenMP.h"
+#include "clang/Frontend/Utils.h"
 #include "clang/Sema/Designator.h"
 #include "clang/Sema/Lookup.h"
 #include "clang/Sema/Ownership.h"
@@ -11002,6 +11003,18 @@
 
   LSI->CallOperator = NewCallOperator;
 
+  FrontendTimeRAII<const FunctionDecl *> FTRAII(
+      FrontendTimesIsEnabled,
+      getFrontendFunctionTimeCtx<const FunctionDecl *>(), {NewCallOperator, 0.0});
+
+//  if (FrontendTimesIsEnabled) {
+//    // At this point we're sure we're dealing with some function that's why
+//    // we're starting the corresponding time slice. We'll stop it in
+//    // Sema::ActOnFinishFunctionBody.
+//    getFrontendFunctionTimeCtx<const FunctionDecl *>()->startFrontendTimer(
+//        {NewCallOperator, 0.0});
+//  }
+
   for (unsigned I = 0, NumParams = NewCallOperator->getNumParams();
        I != NumParams; ++I) {
     auto *P = NewCallOperator->getParamDecl(I);
Index: lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiate.cpp
+++ lib/Sema/SemaTemplateInstantiate.cpp
@@ -128,6 +128,9 @@
     }
     // Add template arguments from a function template specialization.
     else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Ctx)) {
+      FrontendTimeRAII<const FunctionDecl *> FTRAII(
+          FrontendTimesIsEnabled,
+          getFrontendFunctionTimeCtx<const FunctionDecl *>(), {Function, 0});
       if (!RelativeToPrimary &&
           (Function->getTemplateSpecializationKind() ==
                                                   TSK_ExplicitSpecialization &&
Index: lib/Sema/SemaTemplateDeduction.cpp
===================================================================
--- lib/Sema/SemaTemplateDeduction.cpp
+++ lib/Sema/SemaTemplateDeduction.cpp
@@ -2968,6 +2968,9 @@
                                           QualType *FunctionType,
                                           TemplateDeductionInfo &Info) {
   FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
+  FrontendTimeRAII<const FunctionDecl *> FTRAII(
+      FrontendTimesIsEnabled,
+      getFrontendFunctionTimeCtx<const FunctionDecl *>(), {Function, 0});
   TemplateParameterList *TemplateParams
     = FunctionTemplate->getTemplateParameters();
 
@@ -3801,6 +3804,9 @@
     return TDK_Invalid;
 
   FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
+  FrontendTimeRAII<const FunctionDecl *> FTRAII(
+      FrontendTimesIsEnabled,
+      getFrontendFunctionTimeCtx<const FunctionDecl *>(), {Function, 0});
   unsigned NumParams = Function->getNumParams();
 
   unsigned FirstInnerIndex = getFirstInnerIndex(FunctionTemplate);
@@ -4021,6 +4027,9 @@
     return TDK_Invalid;
 
   FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
+  FrontendTimeRAII<const FunctionDecl *> FTRAII(
+      FrontendTimesIsEnabled,
+      getFrontendFunctionTimeCtx<const FunctionDecl *>(), {Function, 0});
   TemplateParameterList *TemplateParams
     = FunctionTemplate->getTemplateParameters();
   QualType FunctionType = Function->getType();
Index: lib/Sema/SemaOverload.cpp
===================================================================
--- lib/Sema/SemaOverload.cpp
+++ lib/Sema/SemaOverload.cpp
@@ -23,6 +23,7 @@
 #include "clang/Basic/DiagnosticOptions.h"
 #include "clang/Basic/PartialDiagnostic.h"
 #include "clang/Basic/TargetInfo.h"
+#include "clang/Frontend/Utils.h"
 #include "clang/Sema/Initialization.h"
 #include "clang/Sema/Lookup.h"
 #include "clang/Sema/SemaInternal.h"
@@ -965,6 +966,9 @@
 Sema::OverloadKind
 Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old,
                     NamedDecl *&Match, bool NewIsUsingDecl) {
+  FrontendTimeRAII<const FunctionDecl *> FTRAII(
+      FrontendTimesIsEnabled,
+      getFrontendFunctionTimeCtx<const FunctionDecl *>(), {New, 0});
   for (LookupResult::iterator I = Old.begin(), E = Old.end();
          I != E; ++I) {
     NamedDecl *OldD = *I;
@@ -1046,6 +1050,9 @@
 
 bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
                       bool UseMemberUsingDeclRules, bool ConsiderCudaAttrs) {
+  FrontendTimeRAII<const FunctionDecl *> FTRAII(
+      FrontendTimesIsEnabled,
+      getFrontendFunctionTimeCtx<const FunctionDecl *>(), {New, 0});
   // C++ [basic.start.main]p2: This function shall not be overloaded.
   if (New->isMain())
     return false;
@@ -5934,6 +5941,9 @@
                            bool PartialOverloading,
                            bool AllowExplicit,
                            ConversionSequenceList EarlyConversions) {
+  FrontendTimeRAII<const FunctionDecl *> FTRAII(
+      FrontendTimesIsEnabled,
+      getFrontendFunctionTimeCtx<const FunctionDecl *>(), {Function, 0});
   const FunctionProtoType *Proto
     = dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>());
   assert(Proto && "Functions without a prototype cannot be overloaded");
Index: lib/Sema/SemaLambda.cpp
===================================================================
--- lib/Sema/SemaLambda.cpp
+++ lib/Sema/SemaLambda.cpp
@@ -10,17 +10,18 @@
 //  This file implements semantic analysis for C++ lambda expressions.
 //
 //===----------------------------------------------------------------------===//
-#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/SemaLambda.h"
 #include "TypeLocBuilder.h"
 #include "clang/AST/ASTLambda.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/Basic/TargetInfo.h"
+#include "clang/Frontend/Utils.h"
+#include "clang/Sema/DeclSpec.h"
 #include "clang/Sema/Initialization.h"
 #include "clang/Sema/Lookup.h"
 #include "clang/Sema/Scope.h"
 #include "clang/Sema/ScopeInfo.h"
 #include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/SemaLambda.h"
 using namespace clang;
 using namespace sema;
 
@@ -907,6 +908,11 @@
   CXXMethodDecl *Method =
       startLambdaDefinition(Class, Intro.Range, MethodTyInfo, EndLoc, Params,
                             ParamInfo.getDeclSpec().isConstexprSpecified());
+
+  FrontendTimeRAII<const FunctionDecl *> FTRAII(
+      FrontendTimesIsEnabled,
+      getFrontendFunctionTimeCtx<const FunctionDecl *>(), {Method, 0});
+
   if (ExplicitParams)
     CheckCXXDefaultArguments(Method);
 
@@ -1441,6 +1447,14 @@
 ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
                                  Scope *CurScope) {
   LambdaScopeInfo LSI = *cast<LambdaScopeInfo>(FunctionScopes.back());
+
+//  if (FrontendTimesIsEnabled) {
+//    // We're dealing with lambda-function that's why we're starting
+//    // the corresponding time slice. It will be finished in
+//    // ActOnFinishFunctionBody.
+//    getFrontendFunctionTimeCtx<const FunctionDecl *>()->startFrontendTimer(
+//        {LSI.CallOperator, 0.0});
+//  }
   ActOnFinishFunctionBody(LSI.CallOperator, Body);
   return BuildLambdaExpr(StartLoc, Body->getLocEnd(), &LSI);
 }
@@ -1506,6 +1520,9 @@
 
 ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
                                  LambdaScopeInfo *LSI) {
+  FrontendTimeRAII<const FunctionDecl *> FTRAII(
+      FrontendTimesIsEnabled,
+      getFrontendFunctionTimeCtx<const FunctionDecl *>(), {LSI->CallOperator, 0});
   // Collect information from the lambda scope.
   SmallVector<LambdaCapture, 4> Captures;
   SmallVector<Expr *, 4> CaptureInits;
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -28,6 +28,7 @@
 #include "clang/Basic/PartialDiagnostic.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/TargetInfo.h"
+#include "clang/Frontend/Utils.h"
 #include "clang/Lex/HeaderSearch.h" // TODO: Sema shouldn't depend on Lex
 #include "clang/Lex/Lexer.h" // TODO: Extract static functions to fix layering.
 #include "clang/Lex/ModuleLoader.h" // TODO: Sema shouldn't depend on Lex
@@ -1989,6 +1990,9 @@
                                            SC_Extern,
                                            false,
                                            R->isFunctionProtoType());
+  FrontendTimeRAII<const FunctionDecl *> FTRAII(
+      FrontendTimesIsEnabled,
+      getFrontendFunctionTimeCtx<const FunctionDecl *>(), {New, 0});
   New->setImplicit();
 
   // Create Decl objects for each parameter, adding them to the
@@ -8377,6 +8381,10 @@
                                               isVirtualOkay);
   if (!NewFD) return nullptr;
 
+  FrontendTimeRAII<const FunctionDecl *> FTRAII(
+      FrontendTimesIsEnabled,
+      getFrontendFunctionTimeCtx<const FunctionDecl *>(), {NewFD, 0});
+
   if (OriginalLexicalContext && OriginalLexicalContext->isObjCContainer())
     NewFD->setTopLevelDeclInObjCContainer();
 
@@ -9899,6 +9907,9 @@
 bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
                                     LookupResult &Previous,
                                     bool IsMemberSpecialization) {
+  FrontendTimeRAII<const FunctionDecl *> FTRAII(
+      FrontendTimesIsEnabled,
+      getFrontendFunctionTimeCtx<const FunctionDecl *>(), {NewFD, 0});
   assert(!NewFD->getReturnType()->isVariablyModifiedType() &&
          "Variably modified return types are not handled here");
 
@@ -12782,6 +12793,17 @@
   else
     FD = cast<FunctionDecl>(D);
 
+  FrontendTimeRAII<const FunctionDecl *> FTRAII(
+      FrontendTimesIsEnabled,
+      getFrontendFunctionTimeCtx<const FunctionDecl *>(), {FD, 0});
+
+//  if (FrontendTimesIsEnabled) {
+//    // We're starting with new function definition that's why we're starting
+//    // the new time slice. It will be stopped in ActOnFinishFunctionBody.
+//    getFrontendFunctionTimeCtx<const FunctionDecl *>()->startFrontendTimer(
+//        {FD, 0.0});
+//  }
+
   // Check for defining attributes before the check for redefinition.
   if (const auto *Attr = FD->getAttr<AliasAttr>()) {
     Diag(Attr->getLocation(), diag::err_alias_is_definition) << FD << 0;
@@ -12993,6 +13015,9 @@
 Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
                                     bool IsInstantiation) {
   FunctionDecl *FD = dcl ? dcl->getAsFunction() : nullptr;
+  FrontendTimeRAII<const FunctionDecl *> FTRAII(
+      FrontendTimesIsEnabled,
+      getFrontendFunctionTimeCtx<const FunctionDecl *>(), {FD, 0});
 
   sema::AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy();
   sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr;
@@ -13294,6 +13319,19 @@
     DiscardCleanupsInEvaluationContext();
   }
 
+//  if (FrontendTimesIsEnabled) {
+//    assert(getFrontendFunctionTimeCtx<const FunctionDecl *>()
+//                   ->ChildStack.back()
+//                   .first == FD &&
+//           "Invalid FD");
+//    // We're stopping the current time slice and adding the one to FrontendTimes.
+//    //  This slice was started in one of the following places:
+//    //  TreeTransform<Derived>::TransformLambdaExpr
+//    //  Sema::ActOnLambdaExpr
+//    //  Sema::ActOnStartOfFunctionDef
+//    getFrontendFunctionTimeCtx<const FunctionDecl *>()->stopFrontendTimer();
+//  }
+
   return dcl;
 }
 
Index: lib/Parse/ParseTemplate.cpp
===================================================================
--- lib/Parse/ParseTemplate.cpp
+++ lib/Parse/ParseTemplate.cpp
@@ -13,27 +13,63 @@
 
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclTemplate.h"
+#include "clang/Frontend/Utils.h"
 #include "clang/Parse/ParseDiagnostic.h"
 #include "clang/Parse/Parser.h"
 #include "clang/Parse/RAIIObjectsForParser.h"
 #include "clang/Sema/DeclSpec.h"
 #include "clang/Sema/ParsedTemplate.h"
 #include "clang/Sema/Scope.h"
 using namespace clang;
 
+#define DEBUG_TYPE "parsetemplate"
+
 /// Parse a template declaration, explicit instantiation, or
 /// explicit specialization.
 Decl *Parser::ParseDeclarationStartingWithTemplate(
     DeclaratorContext Context, SourceLocation &DeclEnd,
     ParsedAttributes &AccessAttrs, AccessSpecifier AS) {
   ObjCDeclContextSwitch ObjCDC(*this);
+  Decl *Result;
 
+  if (FrontendTimesIsEnabled) {
+    LLVM_DEBUG(getFrontendFunctionTimeCtx<const FunctionDecl *>()->debugPrint(
+        "ParseDeclarationStartingWithTemplate: ", nullptr));
+    // At this moment we don't know if this template is interesting for time
+    // report but we have to start the timer if it is. The decision will be
+    // done below after instatiation/specialization.
+    getFrontendFunctionTimeCtx<const FunctionDecl *>()->startFrontendTimer(
+        {nullptr, 0.0});
+  }
   if (Tok.is(tok::kw_template) && NextToken().isNot(tok::less)) {
-    return ParseExplicitInstantiation(Context, SourceLocation(), ConsumeToken(),
-                                      DeclEnd, AccessAttrs, AS);
+    Result = ParseExplicitInstantiation(
+        Context, SourceLocation(), ConsumeToken(), DeclEnd, AccessAttrs, AS);
+  } else
+    Result = ParseTemplateDeclarationOrSpecialization(Context, DeclEnd,
+                                                      AccessAttrs, AS);
+  if (FrontendTimesIsEnabled) {
+    bool Done = false;
+    if (const auto *F = dyn_cast_or_null<FunctionDecl>(Result)) {
+      if (F->isFunctionOrFunctionTemplate() && F->hasBody()) {
+        LLVM_DEBUG(
+            getFrontendFunctionTimeCtx<const FunctionDecl *>()->debugPrint(
+                "stopFrontendTimer(ParseDeclarationStartingWithTemplate): ",
+                F));
+        // Yes, we should add this time slice to the given function
+        getFrontendFunctionTimeCtx<const FunctionDecl *>()->stopFrontendTimer(
+            true, {F, 0.0});
+        Done = true;
+      }
+    }
+    if (!Done) {
+      // We should not add this time slice to any function
+      getFrontendFunctionTimeCtx<const FunctionDecl *>()->stopFrontendTimer(
+          true, {nullptr, -1.0});
+      LLVM_DEBUG(llvm::dbgs() << "ParseDeclarationStartingWithTemplate: simply "
+                                 "remove the non-func time slice from times\n");
+    }
   }
-  return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AccessAttrs,
-                                                  AS);
+  return Result;
 }
 
 /// Parse a template declaration or an explicit specialization.
Index: lib/Parse/ParseCXXInlineMethods.cpp
===================================================================
--- lib/Parse/ParseCXXInlineMethods.cpp
+++ lib/Parse/ParseCXXInlineMethods.cpp
@@ -13,6 +13,7 @@
 
 #include "clang/Parse/Parser.h"
 #include "clang/AST/DeclTemplate.h"
+#include "clang/Frontend/Utils.h"
 #include "clang/Parse/ParseDiagnostic.h"
 #include "clang/Parse/RAIIObjectsForParser.h"
 #include "clang/Sema/DeclSpec.h"
Index: lib/Parse/CMakeLists.txt
===================================================================
--- lib/Parse/CMakeLists.txt
+++ lib/Parse/CMakeLists.txt
@@ -24,6 +24,7 @@
   LINK_LIBS
   clangAST
   clangBasic
+  clangFrontend
   clangLex
   clangSema
   )
Index: lib/Frontend/FrontendTiming.cpp
===================================================================
--- lib/Frontend/FrontendTiming.cpp
+++ lib/Frontend/FrontendTiming.cpp
@@ -7,14 +7,42 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// This file keps implementation of frontend timing utils.
+// This file keeps implementation of frontend timing utils.
 //
 //===----------------------------------------------------------------------===//
 
+#include "clang/AST/Decl.h"
 #include "clang/Frontend/Utils.h"
+#include "llvm/ADT/StringRef.h"
 
 namespace clang {
 
 bool FrontendTimesIsEnabled = false;
+llvm::TimerGroup *FDefTimeGroup = nullptr;
 
+using FTimeBase = const FunctionDecl *;
+FrontendTimeCtx<FTimeBase> FuncTimeCtx;
+
+template <>
+FrontendTimeCtx<FTimeBase> *getFrontendFunctionTimeCtx<FTimeBase>() {
+  if (FrontendTimesIsEnabled && !FuncTimeCtx.isValid())
+    FuncTimeCtx.init("cftimer", "Clang Function Timer",
+                     FuncTimeCtx.getFrontendDefaultTimerGroup());
+  return &FuncTimeCtx;
+}
+
+template <> bool isFirstValid<FTimeBase>(FTimeBase First) {
+  assert(First && "Invalid First");
+  if (FrontendTimesIsEnabled && FuncTimeCtx.isValid() &&
+      !First->isInvalidDecl() && First->getIdentifier()) {
+    if (First->getVisibility() == DefaultVisibility && First->hasBody())
+      return true;
+  }
+  return false;
+}
+
+template <> bool isFirstValid<llvm::StringRef>(llvm::StringRef First) {
+  assert(!First.empty() && "Invalid First");
+  return FrontendTimesIsEnabled;
+}
 }
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp
+++ lib/Frontend/CompilerInvocation.cpp
@@ -787,6 +787,10 @@
   Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier);
 
   Opts.ControlFlowGuard = Args.hasArg(OPT_cfguard);
+  if (!Args.getLastArgValue(OPT_ftime_report_threshold, "0.04")
+           .getAsDouble(Opts.FTimeReportThreshold)) {
+    // TODO: Report a error message
+  }
 
   Opts.DisableGCov = Args.hasArg(OPT_test_coverage);
   Opts.EmitGcovArcs = Args.hasArg(OPT_femit_coverage_data);
Index: lib/CodeGen/CodeGenModule.cpp
===================================================================
--- lib/CodeGen/CodeGenModule.cpp
+++ lib/CodeGen/CodeGenModule.cpp
@@ -43,6 +43,7 @@
 #include "clang/Basic/Version.h"
 #include "clang/CodeGen/ConstantInitBuilder.h"
 #include "clang/Frontend/CodeGenOptions.h"
+#include "clang/Frontend/Utils.h"
 #include "clang/Sema/SemaDiagnostic.h"
 #include "llvm/ADT/Triple.h"
 #include "llvm/Analysis/TargetLibraryInfo.h"
@@ -4563,13 +4564,17 @@
   switch (D->getKind()) {
   case Decl::CXXConversion:
   case Decl::CXXMethod:
-  case Decl::Function:
+  case Decl::Function: {
+    FrontendTimeRAII<const FunctionDecl *> FTRAII(
+        FrontendTimesIsEnabled,
+        getFrontendFunctionTimeCtx<const FunctionDecl *>(),
+        {cast<FunctionDecl>(D), 0});
     EmitGlobal(cast<FunctionDecl>(D));
     // Always provide some coverage mapping
     // even for the functions that aren't emitted.
     AddDeferredUnusedCoverageMapping(D);
     break;
-
+  }
   case Decl::CXXDeductionGuide:
     // Function-like, but does not result in code emission.
     break;
Index: lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- lib/CodeGen/CodeGenFunction.cpp
+++ lib/CodeGen/CodeGenFunction.cpp
@@ -13,9 +13,9 @@
 
 #include "CodeGenFunction.h"
 #include "CGBlocks.h"
-#include "CGCleanup.h"
 #include "CGCUDARuntime.h"
 #include "CGCXXABI.h"
+#include "CGCleanup.h"
 #include "CGDebugInfo.h"
 #include "CGOpenMPRuntime.h"
 #include "CodeGenModule.h"
@@ -31,6 +31,7 @@
 #include "clang/Basic/TargetInfo.h"
 #include "clang/CodeGen/CGFunctionInfo.h"
 #include "clang/Frontend/CodeGenOptions.h"
+#include "clang/Frontend/Utils.h"
 #include "clang/Sema/SemaDiagnostic.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/Dominators.h"
@@ -93,6 +94,8 @@
   Builder.setFastMathFlags(FMF);
 }
 
+using FTimeBase = const FunctionDecl *;
+
 CodeGenFunction::~CodeGenFunction() {
   assert(LifetimeExtendedCleanupStack.empty() && "failed to emit a cleanup");
 
@@ -104,6 +107,13 @@
 
   if (getLangOpts().OpenMP && CurFn)
     CGM.getOpenMPRuntime().functionFinished(*this);
+  if (FrontendTimesIsEnabled && CurFuncDecl) {
+    // We're completing with the current function and as result we should
+    // add the current time slice to the common compilation time of the given
+    // function. This time slice was started in CodeGenFunction::StartFunction
+    // and finished here.
+    getFrontendFunctionTimeCtx<FTimeBase>()->stopFrontendTimer();
+  }
 }
 
 CharUnits CodeGenFunction::getNaturalPointeeTypeAlignment(QualType T,
@@ -820,9 +830,17 @@
 
   DidCallStackSave = false;
   CurCodeDecl = D;
-  if (const auto *FD = dyn_cast_or_null<FunctionDecl>(D))
+  if (const auto *FD = dyn_cast_or_null<FunctionDecl>(D)) {
     if (FD->usesSEHTry())
       CurSEHParent = FD;
+    if (FrontendTimesIsEnabled) {
+      // We're dealing with function that's wy we should add this time slice
+      // to the common compilation time of the given function. The end of this
+      // time slice will be fixed in destructor
+      // CodeGenFunction::~CodeGenFunction().
+      getFrontendFunctionTimeCtx<FTimeBase>()->startFrontendTimer({FD, 0.0});
+    }
+  }
   CurFuncDecl = (D ? D->getNonClosureContext() : nullptr);
   FnRetTy = RetTy;
   CurFn = Fn;
Index: lib/CodeGen/CodeGenAction.cpp
===================================================================
--- lib/CodeGen/CodeGenAction.cpp
+++ lib/CodeGen/CodeGenAction.cpp
@@ -22,7 +22,9 @@
 #include "clang/CodeGen/ModuleBuilder.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/Utils.h"
 #include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/Statistic.h"
 #include "llvm/Bitcode/BitcodeReader.h"
 #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
 #include "llvm/IR/DebugInfo.h"
@@ -36,15 +38,17 @@
 #include "llvm/Pass.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/SourceMgr.h"
-#include "llvm/Support/Timer.h"
 #include "llvm/Support/ToolOutputFile.h"
 #include "llvm/Support/YAMLTraits.h"
 #include "llvm/Transforms/IPO/Internalize.h"
 
 #include <memory>
 using namespace clang;
 using namespace llvm;
 
+using FTimeBase = const FunctionDecl *;
+using FTP = std::pair<FTimeBase, double>;
+
 namespace clang {
   class BackendConsumer;
   class ClangDiagnosticHandler final : public DiagnosticHandler {
@@ -107,6 +111,18 @@
     // refers to.
     llvm::Module *CurLinkModule = nullptr;
 
+    using FTimeMark = StringRef;
+    using FTP = std::pair<FTimeMark, double>;
+    using FTPIterator = std::vector<FTP>::iterator;
+
+    class BCSortClassName {
+    public:
+      bool operator()(FTP i, FTP j) { return i.first.compare(j.first) < 0; }
+      StringRef getName(FTP E) { return E.first; }
+    };
+
+    FrontendTimeCtx<FTimeMark> BCTimerCtx;
+
   public:
     BackendConsumer(BackendAction Action, DiagnosticsEngine &Diags,
                     const HeaderSearchOptions &HeaderSearchOpts,
@@ -128,6 +144,12 @@
           LinkModules(std::move(LinkModules)) {
       FrontendTimesIsEnabled = TimePasses;
     }
+
+    ~BackendConsumer() {
+      if (FrontendTimesIsEnabled)
+        BCTimerCtx.print<BCSortClassName>(BCSortClassName(), "BackendConsumer");
+    }
+
     llvm::Module *getModule() const { return Gen->GetModule(); }
     std::unique_ptr<llvm::Module> takeModule() {
       return std::unique_ptr<llvm::Module>(Gen->ReleaseModule());
@@ -177,6 +199,9 @@
     }
 
     void HandleInlineFunctionDefinition(FunctionDecl *D) override {
+      FrontendTimeRAII<FTimeBase> FTRAII(
+          FrontendTimesIsEnabled,
+          getFrontendFunctionTimeCtx<FTimeBase>(), {D, 0});
       PrettyStackTraceDecl CrashInfo(D, SourceLocation(),
                                      Context->getSourceManager(),
                                      "LLVM IR generation of inline function");
@@ -795,7 +820,13 @@
 
 CodeGenAction::CodeGenAction(unsigned _Act, LLVMContext *_VMContext)
     : Act(_Act), VMContext(_VMContext ? _VMContext : new LLVMContext),
-      OwnsVMContext(!_VMContext) {}
+      OwnsVMContext(!_VMContext) {
+  if (FrontendTimesIsEnabled) {
+    CompilerInstance &CI = getCompilerInstance();
+    getFrontendFunctionTimeCtx<FTimeBase>()->setThreshold(
+        CI.getCodeGenOpts().FTimeReportThreshold);
+  }
+}
 
 CodeGenAction::~CodeGenAction() {
   TheModule.reset();
@@ -805,11 +836,34 @@
 
 bool CodeGenAction::hasIRSupport() const { return true; }
 
+static StringRef getFDName(CodeGen::CodeGenModule &CGM,
+                           const FunctionDecl *FD) {
+  assert(isFirstValid<const FunctionDecl *>(FD) && "Invalid FD");
+  return CGM.getMangledName(GlobalDecl(FD));
+}
+
+class CGSortClassName {
+  CodeGen::CodeGenModule &CGM;
+
+public:
+  CGSortClassName(CodeGen::CodeGenModule &_CGM) : CGM(_CGM) {}
+  bool operator()(FTP i, FTP j) {
+    StringRef NameI = getFDName(CGM, i.first);
+    StringRef NameJ = getFDName(CGM, j.first);
+    return NameI.compare(NameJ) < 0;
+  }
+
+  StringRef getName(FTP E) { return getFDName(CGM, E.first); }
+};
+
 void CodeGenAction::EndSourceFileAction() {
   // If the consumer creation failed, do nothing.
   if (!getCompilerInstance().hasASTConsumer())
     return;
-
+  if (FrontendTimesIsEnabled)
+    getFrontendFunctionTimeCtx<FTimeBase>()->print<CGSortClassName>(
+        CGSortClassName(BEConsumer->getCodeGenerator()->CGM()),
+        "CodeGen Functions", " (*)");
   // Steal the module from the consumer.
   TheModule = BEConsumer->takeModule();
 }
Index: lib/CodeGen/CGExpr.cpp
===================================================================
--- lib/CodeGen/CGExpr.cpp
+++ lib/CodeGen/CGExpr.cpp
@@ -27,6 +27,7 @@
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/NSAPI.h"
 #include "clang/Frontend/CodeGenOptions.h"
+#include "clang/Frontend/Utils.h"
 #include "llvm/ADT/Hashing.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/IR/DataLayout.h"
@@ -2536,8 +2537,12 @@
     return LV;
   }
 
-  if (const auto *FD = dyn_cast<FunctionDecl>(ND))
+  if (const auto *FD = dyn_cast<FunctionDecl>(ND)) {
+    FrontendTimeRAII<const FunctionDecl *> FTRAII(
+        FrontendTimesIsEnabled,
+        getFrontendFunctionTimeCtx<const FunctionDecl *>(), {FD, 0});
     return EmitFunctionDeclLValue(*this, E, FD);
+  }
 
   // FIXME: While we're emitting a binding from an enclosing scope, all other
   // DeclRefExprs we see should be implicitly treated as if they also refer to
@@ -3740,8 +3745,12 @@
     return LV;
   }
 
-  if (const auto *FD = dyn_cast<FunctionDecl>(ND))
+  if (const auto *FD = dyn_cast<FunctionDecl>(ND)) {
+    FrontendTimeRAII<const FunctionDecl *> FTRAII(
+        FrontendTimesIsEnabled,
+        getFrontendFunctionTimeCtx<const FunctionDecl *>(), {FD, 0});
     return EmitFunctionDeclLValue(*this, E, FD);
+  }
 
   llvm_unreachable("Unhandled member declaration!");
 }
Index: lib/Analysis/AnalysisDeclContext.cpp
===================================================================
--- lib/Analysis/AnalysisDeclContext.cpp
+++ lib/Analysis/AnalysisDeclContext.cpp
@@ -35,6 +35,7 @@
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/Utils.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/STLExtras.h"
Index: include/clang/Frontend/Utils.h
===================================================================
--- include/clang/Frontend/Utils.h
+++ include/clang/Frontend/Utils.h
@@ -17,12 +17,15 @@
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/VirtualFileSystem.h"
-#include "llvm/ADT/IntrusiveRefCntPtr.h"
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/Statistic.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/StringSet.h"
 #include "llvm/Option/OptSpecifier.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/Timer.h"
 #include <cstdint>
 #include <memory>
 #include <string>
@@ -239,7 +242,246 @@
 /// If the user specifies the -ftime-report argument on an Clang command line
 /// then the value of this boolean will be true, otherwise false.
 extern bool FrontendTimesIsEnabled;
+extern llvm::TimerGroup *FDefTimeGroup;
+
+template <typename T> bool isFirstValid(T First);
+
+template <typename T> struct FrontendTimeCtx {
+  using FTimePair = std::pair<T, double>;
+  std::vector<FTimePair> FrontendTimes;
+  llvm::Timer FrontendTimer;
+  llvm::TimerGroup *TGroup = nullptr;
+  bool DeleteTGroup = false;
+  double ChildTime;
+  double Threshold = 0.0;
+  std::vector<FTimePair> ChildStack;
+  bool IsValid = false;
+
+  static double getCurProcessTime(llvm::Timer &FT) {
+    assert(FT.isRunning() && "FrontendTimer must be running");
+    FT.stopTimer();
+    return FT.getTotalTime().getProcessTime();
+  }
+
+  static llvm::TimerGroup *getFrontendDefaultTimerGroup() {
+    if (!FDefTimeGroup)
+      FDefTimeGroup = (llvm::TimerGroup *)new llvm::TimerGroup(
+          "clangdeftg", "Clang Timers Group");
+    return FDefTimeGroup;
+  }
+
+public:
+  FrontendTimeCtx() : IsValid(false){};
+  bool isValid(){return IsValid;}
+  void setThreshold(double _T){Threshold = _T;}
+  void init(llvm::StringRef TimerName, llvm::StringRef TimerDsc,
+            llvm::StringRef GroupName, llvm::StringRef GroupDsc) {
+    if (FrontendTimesIsEnabled) {
+      TGroup = (llvm::TimerGroup *)new llvm::TimerGroup(GroupName, GroupDsc);
+      DeleteTGroup = true;
+      init(TimerName, TimerDsc, TGroup);
+    } else
+      IsValid = false;
+  };
+
+  void init(llvm::StringRef TimerName, llvm::StringRef TimerDsc,
+            llvm::TimerGroup *TG) {
+    if (FrontendTimesIsEnabled) {
+      FrontendTimer.init(TimerName, TimerDsc, *TG);
+      TGroup = TG;
+      ChildStack.clear();
+      ChildTime = 0.0;
+      IsValid = true;
+    } else
+      IsValid = false;
+  };
+
+  ~FrontendTimeCtx() {
+    if (FrontendTimesIsEnabled && IsValid && DeleteTGroup)
+      delete TGroup;
+  }
+
+  void startFrontendTimer(FTimePair TDsc) {
+    if (FrontendTimesIsEnabled) {
+      assert(IsValid && "Time Context must be initialized");
+      if (FrontendTimer.isRunning())
+        // It stops the timer as a side effect
+        TDsc.second = getCurProcessTime(FrontendTimer);
+      else
+        TDsc.second = FrontendTimer.getTotalTime().getProcessTime();
+      ChildStack.push_back(TDsc);
+      FrontendTimer.startTimer();
+    }
+  }
+
+  bool stopFrontendTimer(bool UseEl = false, FTimePair El = FTimePair()) {
+    if (FrontendTimesIsEnabled) {
+      assert(IsValid && "Time Context must be initialized");
+      assert(FrontendTimer.isRunning() && "FrontendTimer must be running");
+      assert(!ChildStack.empty() &&
+             "There should be at least one running time slice");
+      FTimePair Result = ChildStack.back();
+      ChildStack.pop_back();
+      // As side effect getCurProcessTime does stopTimer().
+      // Should we fix such a side effect?
+      double CurProcTime = getCurProcessTime(FrontendTimer) - Result.second;
+      Result.second = CurProcTime - ChildTime;
+      if (ChildStack.empty())
+        ChildTime = 0;
+      else {
+        ChildTime += Result.second;
+        FrontendTimer.startTimer();
+      }
+      if (UseEl) {
+        if (El.second > 0)
+          Result.first = El.first;
+        else
+          return false;
+      }
+      if (isFirstValid(Result.first) && Result.second > Threshold) {
+        FrontendTimes.push_back(Result);
+        return true;
+      }
+    }
+    return false;
+  }
+
+  using FTimePair2 = std::pair<FTimePair, unsigned>;
+  static bool ftimeSort2(FTimePair2 I, FTimePair2 J) {
+    return I.first.second < J.first.second;
+  }
+
+  static bool ftimeSort(FTimePair I, FTimePair J) {
+    return I.second < J.second;
+  }
+
+  llvm::TimerGroup *getTimerGroup() {
+    assert(IsValid && "Time Context must be initialized");
+    return TGroup;
+  }
 
+  llvm::Timer *getFrontendTimer() { return &FrontendTimer; }
+
+  std::vector<FTimePair> *getFrontendTimes() { return &FrontendTimes; }
+
+  // Print report about function compilation times
+  // SortName - a functor to sort times by names
+  // SubGroup - a times delimeter to include in output header
+  // Mark - included in the output to simplify grepping of the log
+  template <typename Compare>
+  void print(Compare SortName, StringRef SubGroup, StringRef Mark = " (+)") {
+    if (FrontendTimesIsEnabled && !FrontendTimes.empty()) {
+      std::unique_ptr<llvm::raw_ostream> OutStream =
+          llvm::CreateInfoOutputFile();
+      // FromtendTimes keep time slices spent on the given funcs during
+      // compilation. There could be several time slices corresponding to
+      // on function: parsing time, llvm generation time, code generation time,
+      // etc. We combine such time slices in one time slot related to one func.
+      llvm::sort(FrontendTimes.begin(), FrontendTimes.end(), SortName);
+      using FTPIterator = typename std::vector<FTimePair>::iterator;
+      std::pair<FTPIterator, FTPIterator> range;
+
+      // FinalTimes keep values of func compilation times
+      std::vector<FTimePair2> FinalTimes;
+
+      *OutStream << "===------------ Clang Timers: " << SubGroup
+                 << " ------------==\n";
+      for (unsigned i = 0; i < FrontendTimes.size();) {
+        range = std::equal_range(FrontendTimes.begin() + i, FrontendTimes.end(),
+                                 FrontendTimes[i], SortName);
+        auto dist = std::distance(range.first, range.second);
+        FTimePair E = {FrontendTimes[i].first, 0};
+        // If we have several time slices related to one func than we sum all
+        // corresponding time values to get time slot of one function
+        while (range.first != range.second) {
+          E.second += range.first->second;
+          range.first++;
+        }
+        FinalTimes.push_back({E, dist});
+        i += dist;
+      }
+      // We sort FinalTimes to find the longest compilation times
+      llvm::sort(FinalTimes.begin(), FinalTimes.end(), ftimeSort2);
+      // TODO: TimeThreshold is used to include the compilation time in output.
+      // Should we use special switch here? The smaller TimeThreshold the more
+      // output we generate.
+      double TimeThreshold =
+          (FinalTimes.front().first.second + FinalTimes.back().first.second) /
+          2;
+      for (auto E : FinalTimes) {
+        // FIXME: do we need second threshold here?
+        if ((E.first.second > TimeThreshold) || (E.second > 1))
+          *OutStream << llvm::format("%7.4f (%d) ", E.second, E.first.second)
+                     << SortName.getName(E.first) << Mark << "\n";
+      }
+    }
+  }
+  void debugPrint(StringRef H, const void *P) {
+    llvm::dbgs() << H << P
+                 << llvm::format("FrontendTimes.size=%d,ChildStack.size=%d,"
+                                 "ChildTime=%7.4f, ProcessTime=%7.4f\n",
+                                 FrontendTimes.size(), ChildStack.size(),
+                                 ChildTime,
+                                 FrontendTimer.getTotalTime().getProcessTime());
+  }
+};
+
+template <typename T> FrontendTimeCtx<T> *getFrontendFunctionTimeCtx();
+
+template <typename T> class FrontendTimeRAII {
+  using FTimePair = std::pair<T, double>;
+  FrontendTimeCtx<T> *Ctx = nullptr;
+  void init(FTimePair E, llvm::StringRef TName, llvm::StringRef TDsc,
+            llvm::StringRef GName, llvm::StringRef GDsc) {
+    if (Ctx) {
+      if (!Ctx->IsValid)
+        Ctx->init(TName, TDsc, GName, GDsc);
+      Ctx->startFrontendTimer(E);
+    }
+  }
+
+  void init(FTimePair E, llvm::StringRef TName, llvm::StringRef TDsc,
+            llvm::TimerGroup *TG) {
+    if (Ctx) {
+      if (!Ctx->IsValid)
+        Ctx->init(TName, TDsc, TG);
+      Ctx->startFrontendTimer(E);
+    }
+  }
+
+public:
+  FrontendTimeRAII(bool Enabled, FrontendTimeCtx<T> *FTC, FTimePair E,
+                   llvm::StringRef TName, llvm::StringRef TDsc,
+                   llvm::TimerGroup *TG) {
+    if (Enabled) {
+      Ctx = FTC;
+      init(E, TName, TDsc);
+    }
+  }
+
+  FrontendTimeRAII(bool Enabled, FrontendTimeCtx<T> *FTC, FTimePair E,
+                   llvm::StringRef TName, llvm::StringRef TDsc,
+                   llvm::StringRef GName, llvm::StringRef GDsc) {
+    if (Enabled) {
+      Ctx = FTC;
+      init(E, TName, TDsc, GName, GDsc);
+    }
+  }
+
+  FrontendTimeRAII(bool Enabled, FrontendTimeCtx<T> *FTC, FTimePair E) {
+    if (Enabled) {
+      Ctx = FTC;
+      init(E, "clangtimer", "Clang Func Timer",
+           FrontendTimeCtx<T>::getFrontendDefaultTimerGroup());
+    }
+  }
+
+  ~FrontendTimeRAII() {
+    if (Ctx && Ctx->IsValid) {
+      Ctx->stopFrontendTimer();
+    }
+  }
+};
 } // namespace clang
 
 #endif // LLVM_CLANG_FRONTEND_UTILS_H
Index: include/clang/Frontend/CodeGenOptions.h
===================================================================
--- include/clang/Frontend/CodeGenOptions.h
+++ include/clang/Frontend/CodeGenOptions.h
@@ -116,6 +116,9 @@
   /// environment variables.
   std::string CoverageDataFile;
 
+  /// Compilation time threshold to be included in funcs time report
+  double FTimeReportThreshold;
+
   /// The filename with path we use for coverage notes files.
   std::string CoverageNotesFile;
 
Index: include/clang/Driver/CC1Options.td
===================================================================
--- include/clang/Driver/CC1Options.td
+++ include/clang/Driver/CC1Options.td
@@ -226,6 +226,10 @@
   HelpText<"Emit coverage data to this filename.">;
 def coverage_data_file_EQ : Joined<["-"], "coverage-data-file=">,
   Alias<coverage_data_file>;
+def ftime_report_threshold : Separate<["-"], "ftime-report-threshold">,
+  HelpText<"Emit coverage data to this filename.">;
+def ftime_report_threshold_EQ : Joined<["-"], "ftime-report-threshold=">,
+  Alias<ftime_report_threshold>;
 def coverage_notes_file : Separate<["-"], "coverage-notes-file">,
   HelpText<"Emit coverage notes to this filename.">;
 def coverage_notes_file_EQ : Joined<["-"], "coverage-notes-file=">,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to