Author: ivanaivanovska Date: 2024-10-09T11:42:11+02:00 New Revision: 1be64e5413cbe9cfa89539f70ad02ee1d8945ebe
URL: https://github.com/llvm/llvm-project/commit/1be64e5413cbe9cfa89539f70ad02ee1d8945ebe DIFF: https://github.com/llvm/llvm-project/commit/1be64e5413cbe9cfa89539f70ad02ee1d8945ebe.diff LOG: [clang][Sema] Add instant event when template instantiation is deferred. (#111524) While profiling a clang invocation using `-ftime-trace`, now we add instant events when template instantiation is deferred. These events include the fully qualified name of the function template being deferred and therefore could be very verbose. This is therefore only added in verbose mode (when `TimeTraceVerbose` is enabled). The point of time when a particular instantiation is deferred can be used to identify the parent TimeTrace scope (usually another function instantiation), which is responsible for deferring this instantiation. This relationship can be used to attribute the cost of a deferred template instantiation to the function deferring this particular instantiation. Added: Modified: clang/lib/Sema/SemaExpr.cpp clang/lib/Sema/SemaTemplateInstantiateDecl.cpp clang/unittests/Support/TimeProfilerTest.cpp Removed: ################################################################################ diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index f930a21ea870ec..7401e4cc8f0928 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -18,6 +18,7 @@ #include "clang/AST/ASTLambda.h" #include "clang/AST/ASTMutationListener.h" #include "clang/AST/CXXInheritance.h" +#include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/EvaluatedExprVisitor.h" @@ -65,6 +66,7 @@ #include "llvm/Support/Casting.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/SaveAndRestore.h" +#include "llvm/Support/TimeProfiler.h" #include "llvm/Support/TypeSize.h" #include <optional> @@ -18144,6 +18146,15 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, Func->setInstantiationIsPending(true); PendingInstantiations.push_back( std::make_pair(Func, PointOfInstantiation)); + if (llvm::isTimeTraceVerbose()) { + llvm::timeTraceAddInstantEvent("DeferInstantiation", [&] { + std::string Name; + llvm::raw_string_ostream OS(Name); + Func->getNameForDiagnostic(OS, getPrintingPolicy(), + /*Qualified=*/true); + return Name; + }); + } // Notify the consumer that a function was implicitly instantiated. Consumer.HandleCXXImplicitFunctionInstantiation(Func); } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 17d167b3a5e0c6..8cdf0b17d2dd2f 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -5015,6 +5015,16 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, Function->setInstantiationIsPending(true); PendingInstantiations.push_back( std::make_pair(Function, PointOfInstantiation)); + + if (llvm::isTimeTraceVerbose()) { + llvm::timeTraceAddInstantEvent("DeferInstantiation", [&] { + std::string Name; + llvm::raw_string_ostream OS(Name); + Function->getNameForDiagnostic(OS, getPrintingPolicy(), + /*Qualified=*/true); + return Name; + }); + } } else if (TSK == TSK_ImplicitInstantiation) { if (AtEndOfTU && !getDiagnostics().hasErrorOccurred() && !getSourceManager().isInSystemHeader(PatternDecl->getBeginLoc())) { diff --git a/clang/unittests/Support/TimeProfilerTest.cpp b/clang/unittests/Support/TimeProfilerTest.cpp index f53fe71d630bf5..339b470153e64e 100644 --- a/clang/unittests/Support/TimeProfilerTest.cpp +++ b/clang/unittests/Support/TimeProfilerTest.cpp @@ -238,13 +238,55 @@ Frontend (test.cc) buildTraceGraph(Json)); } +TEST(TimeProfilerTest, ClassTemplateInstantiations) { + std::string Code = R"( + template<class T> + struct S + { + void foo() {} + void bar(); + }; + + template struct S<double>; // explicit instantiation of S<double> + + void user() { + S<int> a; // implicit instantiation of S<int> + S<float>* b; + b->foo(); // implicit instatiation of S<float> and S<float>::foo() + } + )"; + + setupProfiler(); + ASSERT_TRUE(compileFromString(Code, "-std=c++20", "test.cc")); + std::string Json = teardownProfiler(); + ASSERT_EQ(R"( +Frontend (test.cc) +| ParseClass (S) +| InstantiateClass (S<double>, test.cc:9) +| InstantiateFunction (S<double>::foo, test.cc:5) +| ParseDeclarationOrFunctionDefinition (test.cc:11:5) +| | ParseFunctionDefinition (user) +| | | InstantiateClass (S<int>, test.cc:3) +| | | InstantiateClass (S<float>, test.cc:3) +| | | DeferInstantiation (S<float>::foo) +| PerformPendingInstantiations +| | InstantiateFunction (S<float>::foo, test.cc:5) +)", + buildTraceGraph(Json)); +} + TEST(TimeProfilerTest, TemplateInstantiations) { std::string B_H = R"( template <typename T> - T fooB(T t) { + T fooC(T t) { return T(); } + template <typename T> + constexpr T fooB(T t) { + return fooC(t); + } + #define MacroTemp(x) template <typename T> void foo##x(T) { T(); } )"; @@ -267,14 +309,19 @@ TEST(TimeProfilerTest, TemplateInstantiations) { std::string Json = teardownProfiler(); ASSERT_EQ(R"( Frontend (test.cc) +| ParseFunctionDefinition (fooC) | ParseFunctionDefinition (fooB) | ParseFunctionDefinition (fooMTA) | ParseFunctionDefinition (fooA) | ParseDeclarationOrFunctionDefinition (test.cc:3:5) | | ParseFunctionDefinition (user) +| | | DeferInstantiation (fooA<int>) | PerformPendingInstantiations | | InstantiateFunction (fooA<int>, a.h:7) -| | | InstantiateFunction (fooB<int>, b.h:3) +| | | InstantiateFunction (fooB<int>, b.h:8) +| | | | DeferInstantiation (fooC<int>) +| | | DeferInstantiation (fooMTA<int>) +| | | InstantiateFunction (fooC<int>, b.h:3) | | | InstantiateFunction (fooMTA<int>, a.h:4) )", buildTraceGraph(Json)); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits