[clang] [llvm] Added instant events and marking defered templated instantiation. (PR #103039)

via cfe-commits cfe-commits at lists.llvm.org
Thu Aug 29 06:15:21 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-support

@llvm/pr-subscribers-clang

Author: None (ivanaivanovska)

<details>
<summary>Changes</summary>

Added an instant event type and issuing such events each time a template instantiation is deferred.

---
Full diff: https://github.com/llvm/llvm-project/pull/103039.diff


5 Files Affected:

- (modified) clang/lib/Sema/SemaExpr.cpp (+15) 
- (modified) clang/lib/Sema/SemaTemplateInstantiateDecl.cpp (+13) 
- (modified) clang/unittests/Support/TimeProfilerTest.cpp (+49-2) 
- (modified) llvm/include/llvm/Support/TimeProfiler.h (+7) 
- (modified) llvm/lib/Support/TimeProfiler.cpp (+91-31) 


``````````diff
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 95f53dfefbcc52..a7dd01c936bac8 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"
@@ -64,6 +65,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>
 
@@ -18046,6 +18048,19 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
                 std::make_pair(Func, PointOfInstantiation));
             // Notify the consumer that a function was implicitly instantiated.
             Consumer.HandleCXXImplicitFunctionInstantiation(Func);
+
+            llvm::timeTraceProfilerInsert("DeferInstantiation", [&]() {
+              llvm::TimeTraceMetadata M;
+              llvm::raw_string_ostream OS(M.Detail);
+              Func->getNameForDiagnostic(OS, getPrintingPolicy(),
+                                         /*Qualified=*/true);
+              if (llvm::isTimeTraceVerbose()) {
+                auto Loc = SourceMgr.getExpansionLoc(Func->getLocation());
+                M.File = SourceMgr.getFilename(Loc);
+                M.Line = SourceMgr.getExpansionLineNumber(Loc);
+              }
+              return M;
+            });
           }
         }
       } else {
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 0e064be2391838..550add5495c833 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4983,6 +4983,19 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
       Function->setInstantiationIsPending(true);
       PendingInstantiations.push_back(
         std::make_pair(Function, PointOfInstantiation));
+
+      llvm::timeTraceProfilerInsert("DeferInstantiation", [&]() {
+        llvm::TimeTraceMetadata M;
+        llvm::raw_string_ostream OS(M.Detail);
+        Function->getNameForDiagnostic(OS, getPrintingPolicy(),
+                                       /*Qualified=*/true);
+        if (llvm::isTimeTraceVerbose()) {
+          auto Loc = SourceMgr.getExpansionLoc(Function->getLocation());
+          M.File = SourceMgr.getFilename(Loc);
+          M.Line = SourceMgr.getExpansionLineNumber(Loc);
+        }
+        return M;
+      });
     } 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..ccda12e943dd73 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, test.cc:5)
+| 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>, a.h:7)
 | PerformPendingInstantiations
 | | InstantiateFunction (fooA<int>, a.h:7)
-| | | InstantiateFunction (fooB<int>, b.h:3)
+| | | InstantiateFunction (fooB<int>, b.h:8)
+| | | | DeferInstantiation (fooC<int>, b.h:3)
+| | | DeferInstantiation (fooMTA<int>, a.h:4)
+| | | InstantiateFunction (fooC<int>, b.h:3)
 | | | InstantiateFunction (fooMTA<int>, a.h:4)
 )",
             buildTraceGraph(Json));
diff --git a/llvm/include/llvm/Support/TimeProfiler.h b/llvm/include/llvm/Support/TimeProfiler.h
index 9e2ba31991f542..9a6bcdefee6c20 100644
--- a/llvm/include/llvm/Support/TimeProfiler.h
+++ b/llvm/include/llvm/Support/TimeProfiler.h
@@ -83,6 +83,8 @@ namespace llvm {
 
 class raw_pwrite_stream;
 
+enum class TimeTraceEventType { CompleteEvent, InstantEvent, AsyncEvent };
+
 struct TimeTraceMetadata {
   std::string Detail;
   // Source file and line number information for the event.
@@ -152,6 +154,11 @@ timeTraceProfilerBegin(StringRef Name,
 TimeTraceProfilerEntry *timeTraceAsyncProfilerBegin(StringRef Name,
                                                     StringRef Detail);
 
+// Mark an instant event.
+void timeTraceProfilerInsert(StringRef Name,
+                             llvm::function_ref<TimeTraceMetadata()> Metadata);
+void timeTraceProfilerInsert(StringRef Name, StringRef Detail);
+
 /// Manually end the last time section.
 void timeTraceProfilerEnd();
 void timeTraceProfilerEnd(TimeTraceProfilerEntry *E);
diff --git a/llvm/lib/Support/TimeProfiler.cpp b/llvm/lib/Support/TimeProfiler.cpp
index c2014028ddadca..31faa36c29f14d 100644
--- a/llvm/lib/Support/TimeProfiler.cpp
+++ b/llvm/lib/Support/TimeProfiler.cpp
@@ -13,6 +13,7 @@
 #include "llvm/Support/TimeProfiler.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/STLFunctionalExtras.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/Support/JSON.h"
 #include "llvm/Support/Path.h"
@@ -75,18 +76,18 @@ struct llvm::TimeTraceProfilerEntry {
   const std::string Name;
   TimeTraceMetadata Metadata;
 
-  const bool AsyncEvent = false;
+  TimeTraceEventType EventType;
   TimeTraceProfilerEntry(TimePointType &&S, TimePointType &&E, std::string &&N,
-                         std::string &&Dt, bool Ae)
+                         std::string &&Dt, TimeTraceEventType Et)
       : Start(std::move(S)), End(std::move(E)), Name(std::move(N)), Metadata(),
-        AsyncEvent(Ae) {
+        EventType(Et) {
     Metadata.Detail = std::move(Dt);
   }
 
   TimeTraceProfilerEntry(TimePointType &&S, TimePointType &&E, std::string &&N,
-                         TimeTraceMetadata &&Mt, bool Ae)
+                         TimeTraceMetadata &&Mt, TimeTraceEventType Et)
       : Start(std::move(S)), End(std::move(E)), Name(std::move(N)),
-        Metadata(std::move(Mt)), AsyncEvent(Ae) {}
+        Metadata(std::move(Mt)), EventType(Et) {}
 
   // Calculate timings for FlameGraph. Cast time points to microsecond precision
   // rather than casting duration. This avoids truncation issues causing inner
@@ -104,6 +105,23 @@ struct llvm::TimeTraceProfilerEntry {
   }
 };
 
+struct InProgressEntry {
+  std::unique_ptr<TimeTraceProfilerEntry> Event;
+  std::vector<TimeTraceProfilerEntry> InstantEvents;
+
+  InProgressEntry(TimePointType &&S, TimePointType &&E, std::string &&N,
+                  std::string &&Dt, TimeTraceEventType Et)
+      : Event(std::make_unique<TimeTraceProfilerEntry>(
+            std::move(S), std::move(E), std::move(N), std::move(Dt), Et)),
+        InstantEvents() {}
+
+  InProgressEntry(TimePointType &&S, TimePointType &&E, std::string &&N,
+                  TimeTraceMetadata &&Mt, TimeTraceEventType Et)
+      : Event(std::make_unique<TimeTraceProfilerEntry>(
+            std::move(S), std::move(E), std::move(N), std::move(Mt), Et)),
+        InstantEvents() {}
+};
+
 struct llvm::TimeTraceProfiler {
   TimeTraceProfiler(unsigned TimeTraceGranularity = 0, StringRef ProcName = "",
                     bool TimeTraceVerbose = false)
@@ -114,27 +132,46 @@ struct llvm::TimeTraceProfiler {
     llvm::get_thread_name(ThreadName);
   }
 
-  TimeTraceProfilerEntry *begin(std::string Name,
-                                llvm::function_ref<std::string()> Detail,
-                                bool AsyncEvent = false) {
-    Stack.emplace_back(std::make_unique<TimeTraceProfilerEntry>(
+  TimeTraceProfilerEntry *
+  begin(std::string Name, llvm::function_ref<std::string()> Detail,
+        TimeTraceEventType EventType = TimeTraceEventType::CompleteEvent) {
+    Stack.emplace_back(std::make_unique<InProgressEntry>(
         ClockType::now(), TimePointType(), std::move(Name), Detail(),
-        AsyncEvent));
-    return Stack.back().get();
+        EventType));
+    return Stack.back()->Event.get();
   }
 
   TimeTraceProfilerEntry *
   begin(std::string Name, llvm::function_ref<TimeTraceMetadata()> Metadata,
-        bool AsyncEvent = false) {
-    Stack.emplace_back(std::make_unique<TimeTraceProfilerEntry>(
+        TimeTraceEventType EventType = TimeTraceEventType::CompleteEvent) {
+    Stack.emplace_back(std::make_unique<InProgressEntry>(
+        ClockType::now(), TimePointType(), std::move(Name), Metadata(),
+        EventType));
+    return Stack.back()->Event.get();
+  }
+
+  void insert(std::string Name, llvm::function_ref<std::string()> Detail) {
+    if (Stack.empty())
+      return;
+
+    Stack.back().get()->InstantEvents.emplace_back(TimeTraceProfilerEntry(
+        ClockType::now(), TimePointType(), std::move(Name), Detail(),
+        TimeTraceEventType::InstantEvent));
+  }
+
+  void insert(std::string Name,
+              llvm::function_ref<TimeTraceMetadata()> Metadata) {
+    if (Stack.empty())
+      return;
+
+    Stack.back().get()->InstantEvents.emplace_back(TimeTraceProfilerEntry(
         ClockType::now(), TimePointType(), std::move(Name), Metadata(),
-        AsyncEvent));
-    return Stack.back().get();
+        TimeTraceEventType::InstantEvent));
   }
 
   void end() {
     assert(!Stack.empty() && "Must call begin() first");
-    end(*Stack.back());
+    end(*Stack.back()->Event);
   }
 
   void end(TimeTraceProfilerEntry &E) {
@@ -145,8 +182,14 @@ struct llvm::TimeTraceProfiler {
     DurationType Duration = E.End - E.Start;
 
     // Only include sections longer or equal to TimeTraceGranularity msec.
-    if (duration_cast<microseconds>(Duration).count() >= TimeTraceGranularity)
+    if (duration_cast<microseconds>(Duration).count() >= TimeTraceGranularity) {
       Entries.emplace_back(E);
+      if (Stack.back()->Event.get() == &E) {
+        for (auto &IE : Stack.back()->InstantEvents) {
+          Entries.emplace_back(IE);
+        }
+      }
+    }
 
     // Track total time taken by each "name", but only the topmost levels of
     // them; e.g. if there's a template instantiation that instantiates other
@@ -154,18 +197,17 @@ struct llvm::TimeTraceProfiler {
     // happens to be the ones that don't have any currently open entries above
     // itself.
     if (llvm::none_of(llvm::drop_begin(llvm::reverse(Stack)),
-                      [&](const std::unique_ptr<TimeTraceProfilerEntry> &Val) {
-                        return Val->Name == E.Name;
+                      [&](const std::unique_ptr<InProgressEntry> &Val) {
+                        return Val->Event->Name == E.Name;
                       })) {
       auto &CountAndTotal = CountAndTotalPerName[E.Name];
       CountAndTotal.first++;
       CountAndTotal.second += Duration;
     };
 
-    llvm::erase_if(Stack,
-                   [&](const std::unique_ptr<TimeTraceProfilerEntry> &Val) {
-                     return Val.get() == &E;
-                   });
+    llvm::erase_if(Stack, [&](const std::unique_ptr<InProgressEntry> &Val) {
+      return Val->Event.get() == &E;
+    });
   }
 
   // Write events from this TimeTraceProfilerInstance and
@@ -194,13 +236,15 @@ struct llvm::TimeTraceProfiler {
         J.attribute("pid", Pid);
         J.attribute("tid", int64_t(Tid));
         J.attribute("ts", StartUs);
-        if (E.AsyncEvent) {
+        if (TimeTraceEventType::AsyncEvent == E.EventType) {
           J.attribute("cat", E.Name);
           J.attribute("ph", "b");
           J.attribute("id", 0);
-        } else {
+        } else if (E.EventType == TimeTraceEventType::CompleteEvent) {
           J.attribute("ph", "X");
           J.attribute("dur", DurUs);
+        } else { // instant event
+          J.attribute("ph", "i");
         }
         J.attribute("name", E.Name);
         if (!E.Metadata.isEmpty()) {
@@ -215,7 +259,7 @@ struct llvm::TimeTraceProfiler {
         }
       });
 
-      if (E.AsyncEvent) {
+      if (TimeTraceEventType::AsyncEvent == E.EventType) {
         J.object([&] {
           J.attribute("pid", Pid);
           J.attribute("tid", int64_t(Tid));
@@ -319,7 +363,7 @@ struct llvm::TimeTraceProfiler {
     J.objectEnd();
   }
 
-  SmallVector<std::unique_ptr<TimeTraceProfilerEntry>, 16> Stack;
+  SmallVector<std::unique_ptr<InProgressEntry>, 16> Stack;
   SmallVector<TimeTraceProfilerEntry, 128> Entries;
   StringMap<CountAndDurationType> CountAndTotalPerName;
   // System clock time when the session was begun.
@@ -406,7 +450,8 @@ TimeTraceProfilerEntry *llvm::timeTraceProfilerBegin(StringRef Name,
                                                      StringRef Detail) {
   if (TimeTraceProfilerInstance != nullptr)
     return TimeTraceProfilerInstance->begin(
-        std::string(Name), [&]() { return std::string(Detail); }, false);
+        std::string(Name), [&]() { return std::string(Detail); },
+        TimeTraceEventType::CompleteEvent);
   return nullptr;
 }
 
@@ -414,7 +459,8 @@ TimeTraceProfilerEntry *
 llvm::timeTraceProfilerBegin(StringRef Name,
                              llvm::function_ref<std::string()> Detail) {
   if (TimeTraceProfilerInstance != nullptr)
-    return TimeTraceProfilerInstance->begin(std::string(Name), Detail, false);
+    return TimeTraceProfilerInstance->begin(std::string(Name), Detail,
+                                            TimeTraceEventType::CompleteEvent);
   return nullptr;
 }
 
@@ -422,7 +468,8 @@ TimeTraceProfilerEntry *
 llvm::timeTraceProfilerBegin(StringRef Name,
                              llvm::function_ref<TimeTraceMetadata()> Metadata) {
   if (TimeTraceProfilerInstance != nullptr)
-    return TimeTraceProfilerInstance->begin(std::string(Name), Metadata, false);
+    return TimeTraceProfilerInstance->begin(std::string(Name), Metadata,
+                                            TimeTraceEventType::CompleteEvent);
   return nullptr;
 }
 
@@ -430,10 +477,23 @@ TimeTraceProfilerEntry *llvm::timeTraceAsyncProfilerBegin(StringRef Name,
                                                           StringRef Detail) {
   if (TimeTraceProfilerInstance != nullptr)
     return TimeTraceProfilerInstance->begin(
-        std::string(Name), [&]() { return std::string(Detail); }, true);
+        std::string(Name), [&]() { return std::string(Detail); },
+        TimeTraceEventType::AsyncEvent);
   return nullptr;
 }
 
+void llvm::timeTraceProfilerInsert(StringRef Name, StringRef Detail) {
+  if (TimeTraceProfilerInstance != nullptr)
+    TimeTraceProfilerInstance->insert(std::string(Name),
+                                      [&]() { return std::string(Detail); });
+}
+
+void llvm::timeTraceProfilerInsert(
+    StringRef Name, llvm::function_ref<TimeTraceMetadata()> Metadata) {
+  if (TimeTraceProfilerInstance != nullptr)
+    TimeTraceProfilerInstance->insert(std::string(Name), Metadata);
+}
+
 void llvm::timeTraceProfilerEnd() {
   if (TimeTraceProfilerInstance != nullptr)
     TimeTraceProfilerInstance->end();

``````````

</details>


https://github.com/llvm/llvm-project/pull/103039


More information about the cfe-commits mailing list