avt77 created this revision. avt77 added reviewers: RKSimon, simon.f.whittaker, mgorny, russell.gallop, efriedma, rsmith, mzolotukhin, davezarzycki, vsk. Herald added a subscriber: mgrang.
I introduce the new infrastructure supporting recursive timers in Clang. This patch is based on https://reviews.llvm.org/D45619 [Time-report] (1) and it is not the last one in this series. The main idea is a possibilty to have "horizontal" timers instead of "vertical" ones which we have today. The patch alows to find the most critical functions (from compilation time of view) and to to analyze them. https://reviews.llvm.org/D47196 Files: include/clang/Frontend/Utils.h lib/CodeGen/BackendUtil.cpp lib/CodeGen/CodeGenAction.cpp lib/CodeGen/CodeGenFunction.cpp lib/Frontend/FrontendTiming.cpp lib/Parse/CMakeLists.txt lib/Parse/ParseTemplate.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaLambda.cpp lib/Sema/SemaTemplateInstantiateDecl.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); + char R2 = foo<char, int>('d', 1234); + int R3 = foo<double>(1.2); + double R4 = foo<double, int>(34.56, 1234); + double R5 = R1 + R2 * R3 - R4 + one[0] - two[1]; + return R5 * R1 + R4 / R3 + R2; } } @@ -150,7 +162,8 @@ }; _Wrap_alloc<int>::rebind<int> w; -// CHECK: Miscellaneous Ungrouped Timers +// 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" @@ -10945,6 +10946,13 @@ LSI->CallOperator = NewCallOperator; + if (FrontendTimesIsEnabled) { + llvm::dbgs() << "startFrontendTimer(TransformLambdaExpr): " + << NewCallOperator << "\n"; + 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/SemaTemplateInstantiateDecl.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiateDecl.cpp +++ lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1,4 +1,5 @@ -//===--- SemaTemplateInstantiateDecl.cpp - C++ Template Decl Instantiation ===/ +//===--- SemaTemplateInstantiateDecl.cpp - C++ T--emplate Decl Instantiation +//===/ // // The LLVM Compiler Infrastructure // @@ -9,7 +10,6 @@ // This file implements C++ template instantiation for declarations. // //===----------------------------------------------------------------------===/ -#include "clang/Sema/SemaInternal.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTMutationListener.h" @@ -20,11 +20,14 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/PrettyDeclStackTrace.h" #include "clang/AST/TypeLoc.h" +#include "clang/Frontend/Utils.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "clang/Sema/TemplateInstCallback.h" +#define DEBUG_TYPE "templateinst" using namespace clang; static bool isDeclWithinFunction(const Decl *D) { Index: lib/Sema/SemaLambda.cpp =================================================================== --- lib/Sema/SemaLambda.cpp +++ lib/Sema/SemaLambda.cpp @@ -10,20 +10,23 @@ // 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; +#define DEBUG_TYPE "semalambda" + /// Examines the FunctionScopeInfo stack to determine the nearest /// enclosing lambda (to the current lambda) that is 'capture-ready' for /// the variable referenced in the current lambda (i.e. \p VarToCapture). @@ -1428,6 +1431,12 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, Scope *CurScope) { LambdaScopeInfo LSI = *cast<LambdaScopeInfo>(FunctionScopes.back()); + + if (FrontendTimesIsEnabled) { + DEBUG(llvm::dbgs() << "ActOnLambdaExpr: " << LSI.CallOperator << "\n"); + getFrontendFunctionTimeCtx<const FunctionDecl *>()->startFrontendTimer( + {LSI.CallOperator, 0.0}); + } ActOnFinishFunctionBody(LSI.CallOperator, Body); return BuildLambdaExpr(StartLoc, Body->getLocEnd(), &LSI); } 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 @@ -51,6 +52,8 @@ using namespace clang; using namespace sema; +#define DEBUG_TYPE "semadecl" + Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType) { if (OwnedType) { Decl *Group[2] = { OwnedType, Ptr }; @@ -8285,6 +8288,11 @@ isVirtualOkay); if (!NewFD) return nullptr; + DEBUG(llvm::dbgs() << "FrontendTimeRAII: " << NewFD << "\n"); + FrontendTimeRAII<const FunctionDecl *> FTRAII( + FrontendTimesIsEnabled, + getFrontendFunctionTimeCtx<const FunctionDecl *>(), {NewFD, 0}); + if (OriginalLexicalContext && OriginalLexicalContext->isObjCContainer()) NewFD->setTopLevelDeclInObjCContainer(); @@ -12476,6 +12484,13 @@ else FD = cast<FunctionDecl>(D); + if (FrontendTimesIsEnabled) { + DEBUG(llvm::dbgs() << "startFrontendTimer(ActOnStartFuncionDef): " << FD + << "\n"); + 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; @@ -12975,6 +12990,16 @@ DiscardCleanupsInEvaluationContext(); } + if (FrontendTimesIsEnabled) { + DEBUG(llvm::dbgs() << "stopFrontendTimer(ActOnFinishFunctionBody): " << FD + << "\n"); + assert(getFrontendFunctionTimeCtx<const FunctionDecl *>() + ->ChildStack.back() + .first == FD && + "Invalid FD"); + getFrontendFunctionTimeCtx<const FunctionDecl *>()->stopFrontendTimer(); + } + return dcl; } Index: lib/Parse/ParseTemplate.cpp =================================================================== --- lib/Parse/ParseTemplate.cpp +++ lib/Parse/ParseTemplate.cpp @@ -13,30 +13,58 @@ #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, AccessSpecifier AS, AttributeList *AccessAttrs) { ObjCDeclContextSwitch ObjCDC(*this); - + Decl *Result; + + if (FrontendTimesIsEnabled) { + DEBUG(llvm::dbgs() << "startFrontendTimer in " + "ParseDeclarationStartingWithTemplate: nullptr\n"); + getFrontendFunctionTimeCtx<const FunctionDecl *>()->startFrontendTimer( + {nullptr, 0.0}); + } if (Tok.is(tok::kw_template) && NextToken().isNot(tok::less)) { - return ParseExplicitInstantiation(Context, - SourceLocation(), ConsumeToken(), - DeclEnd, AS); + Result = ParseExplicitInstantiation(Context, SourceLocation(), + ConsumeToken(), DeclEnd, AS); + } else + Result = ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AS, + AccessAttrs); + if (FrontendTimesIsEnabled) { + bool Done = false; + DEBUG(llvm::dbgs() + << "stopFrontendTimer in ParseDeclarationStartingWithTemplate: "); + if (const auto *F = dyn_cast_or_null<FunctionDecl>(Result)) { + if (F->isFunctionOrFunctionTemplate() && F->hasBody()) { + DEBUG(llvm::dbgs() << F << "\n"); + getFrontendFunctionTimeCtx<const FunctionDecl *>()->stopFrontendTimer( + true, {F, 0.0}); + Done = true; + } + } + if (!Done) { + getFrontendFunctionTimeCtx<const FunctionDecl *>()->stopFrontendTimer( + true, {nullptr, -1.0}); + DEBUG(llvm::dbgs() << "simply remove the time slot from times\n"); + } } - return ParseTemplateDeclarationOrSpecialization(Context, DeclEnd, AS, - AccessAttrs); + return Result; } 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 @@ -11,10 +11,38 @@ // //===----------------------------------------------------------------------===// +#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/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" @@ -41,6 +42,8 @@ using namespace clang; using namespace CodeGen; +#define DEBUG_TYPE "codegenfunction" + /// shouldEmitLifetimeMarkers - Decide whether we need emit the life-time /// markers. static bool shouldEmitLifetimeMarkers(const CodeGenOptions &CGOpts, @@ -109,6 +112,8 @@ Builder.setFastMathFlags(FMF); } +using FTimeBase = const FunctionDecl *; + CodeGenFunction::~CodeGenFunction() { assert(LifetimeExtendedCleanupStack.empty() && "failed to emit a cleanup"); @@ -120,6 +125,15 @@ if (getLangOpts().OpenMP && CurFn) CGM.getOpenMPRuntime().functionFinished(*this); + if (FrontendTimesIsEnabled && CurFuncDecl) { + DEBUG(llvm::dbgs() << "stopFrontendTimer(~CodeGenFunction) " + "ChildStack.back().first:CurFuncDecl = " + << getFrontendFunctionTimeCtx<const FunctionDecl *>() + ->ChildStack.back() + .first + << ":" << CurFuncDecl << "\n"); + getFrontendFunctionTimeCtx<FTimeBase>()->stopFrontendTimer(); + } } CharUnits CodeGenFunction::getNaturalPointeeTypeAlignment(QualType T, @@ -831,9 +845,15 @@ 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) { + DEBUG(llvm::dbgs() << "startFrontendTimer(StartFunction): " << FD + << "\n"); + 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,16 @@ #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; +#define DEBUG_TYPE "codegenaction" + namespace clang { class BackendConsumer; class ClangDiagnosticHandler final : public DiagnosticHandler { @@ -107,6 +110,18 @@ // refers to. llvm::Module *CurLinkModule = nullptr; + using FTimeMark = StringRef; + using FTP = std::pair<FTimeMark, double>; + using FTPIterator = std::vector<FTP>::iterator; + + class SortClassName { + 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, @@ -127,7 +142,19 @@ CodeGenOpts, C, CoverageInfo)), LinkModules(std::move(LinkModules)) { FrontendTimesIsEnabled = TimePasses; + DEBUG(llvm::dbgs() << "BackendConsumer " + "(FrontendTimes.size():ChildStack.size():ChildTime)" + " " + << BCTimerCtx.FrontendTimes.size() << ":" + << BCTimerCtx.ChildStack.size() << ":" + << BCTimerCtx.ChildTime << "\n"); } + + ~BackendConsumer() { + if (FrontendTimesIsEnabled) + BCTimerCtx.print<SortClassName>(SortClassName(), "BackendConsumer"); + } + llvm::Module *getModule() const { return Gen->GetModule(); } std::unique_ptr<llvm::Module> takeModule() { return std::unique_ptr<llvm::Module>(Gen->ReleaseModule()); @@ -140,6 +167,12 @@ } void Initialize(ASTContext &Ctx) override { + DEBUG(llvm::dbgs() << "BackendConsumer::Initialize " + "(FrontendTimes.size():ChildStack.size():ChildTime)" + " " + << BCTimerCtx.FrontendTimes.size() << ":" + << BCTimerCtx.ChildStack.size() << ":" + << BCTimerCtx.ChildTime << "\n"); assert(!Context && "initialized multiple times"); Context = &Ctx; @@ -154,6 +187,12 @@ } bool HandleTopLevelDecl(DeclGroupRef D) override { + DEBUG(llvm::dbgs() << "BackendConsumer::HandleTopLevelDecl " + "(FrontendTimes.size():ChildStack.size():ChildTime)" + " " + << BCTimerCtx.FrontendTimes.size() << ":" + << BCTimerCtx.ChildStack.size() << ":" + << BCTimerCtx.ChildTime << "\n"); PrettyStackTraceDecl CrashInfo(*D.begin(), SourceLocation(), Context->getSourceManager(), "LLVM IR generation of declaration"); @@ -177,6 +216,12 @@ } void HandleInlineFunctionDefinition(FunctionDecl *D) override { + DEBUG(llvm::dbgs() << "BackendConsumer::HandleInlineFunctionDefinition " + "(FrontendTimes.size():ChildStack.size():ChildTime)" + " " + << BCTimerCtx.FrontendTimes.size() << ":" + << BCTimerCtx.ChildStack.size() << ":" + << BCTimerCtx.ChildTime << "\n"); PrettyStackTraceDecl CrashInfo(D, SourceLocation(), Context->getSourceManager(), "LLVM IR generation of inline function"); @@ -225,6 +270,12 @@ } void HandleTranslationUnit(ASTContext &C) override { + DEBUG(llvm::dbgs() << "BackendConsumer::HandleTranslationUnit " + "(FrontendTimes.size():ChildStack.size():ChildTime)" + " " + << BCTimerCtx.FrontendTimes.size() << ":" + << BCTimerCtx.ChildStack.size() << ":" + << BCTimerCtx.ChildTime << "\n"); { PrettyStackTraceString CrashInfo("Per-file LLVM IR generation"); if (FrontendTimesIsEnabled) { @@ -805,11 +856,41 @@ bool CodeGenAction::hasIRSupport() const { return true; } +static StringRef getFDName(CodeGen::CodeGenModule &CGM, + const FunctionDecl *FD) { + assert(isFirstValid<const FunctionDecl *>(FD) && "Invalid FD"); + if (FD->hasBody()) { + GlobalDecl GD; + return CGM.getMangledName(GD.getWithDecl(FD)); + } + return FD->getName(); +} + +using FTimeBase = const FunctionDecl *; +using FTP = std::pair<FTimeBase, double>; + +class SortClassName { + CodeGen::CodeGenModule &CGM; + +public: + SortClassName(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<SortClassName>( + SortClassName(BEConsumer->getCodeGenerator()->CGM()), + "CodeGen Functions", " (*)"); // Steal the module from the consumer. TheModule = BEConsumer->takeModule(); } Index: lib/CodeGen/BackendUtil.cpp =================================================================== --- lib/CodeGen/BackendUtil.cpp +++ lib/CodeGen/BackendUtil.cpp @@ -64,6 +64,11 @@ using namespace clang; using namespace llvm; +namespace clang { +void BuryPointer(const void *Ptr); +extern bool FrontendTimesIsEnabled; +} + namespace { // Default filename used for profile generation. 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,212 @@ /// 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; + std::vector<FTimePair> ChildStack; + + 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: + bool IsValid; + FrontendTimeCtx() : IsValid(false){}; + 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 > 0.00001) { + 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; } + + template <typename Compare> + void print(Compare SortName, StringRef SubGroup, StringRef Mark = " (+)") { + if (FrontendTimesIsEnabled && !FrontendTimes.empty()) { + std::unique_ptr<llvm::raw_ostream> OutStream = + llvm::CreateInfoOutputFile(); + std::sort(FrontendTimes.begin(), FrontendTimes.end(), SortName); + using FTPIterator = typename std::vector<FTimePair>::iterator; + std::pair<FTPIterator, FTPIterator> range; + + 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}; + while (range.first != range.second) { + E.second += range.first->second; + range.first++; + } + FinalTimes.push_back({E, dist}); + i += dist; + } + std::sort(FinalTimes.begin(), FinalTimes.end(), ftimeSort2); + double TimeThreshold = + (FinalTimes.front().first.second + FinalTimes.back().first.second) / + 2; + for (auto E : FinalTimes) { + 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"; + } + } + } +}; + +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); + } + } + +public: + FrontendTimeRAII(bool Enabled, FrontendTimeCtx<T> *FTC, FTimePair E, + llvm::StringRef TName, llvm::StringRef TDsc, + llvm::TimerGroup *TG) { + if (Enabled) { + Ctx = FTC; + if (!Ctx->IsValid) + Ctx->init(TName, TDsc, TG); + Ctx->startFrontendTimer(E); + } + } + + 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, StringRef(), StringRef(), StringRef(), StringRef()); + } + } + + ~FrontendTimeRAII() { + if (Ctx && Ctx->IsValid) { + // Ctx->stopFrontendTimer(true, {T(), -1.0}); + Ctx->stopFrontendTimer(); + } + } +}; } // namespace clang #endif // LLVM_CLANG_FRONTEND_UTILS_H
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits