[clang] [llvm] Add source file name for template instantiations in -ftime-trace (PR #98320)

Utkarsh Saxena via cfe-commits cfe-commits at lists.llvm.org
Thu Jul 18 07:03:49 PDT 2024


https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/98320

>From 03cc5fbebaf0c0c737e9304b8b3310ab4908fcaa Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Wed, 10 Jul 2024 13:52:46 +0000
Subject: [PATCH 01/14] Add an option to add source file info to -ftime-trace

---
 clang/include/clang/Driver/Options.td          | 4 ++++
 clang/include/clang/Frontend/FrontendOptions.h | 3 +++
 clang/lib/Sema/SemaTemplateInstantiate.cpp     | 2 ++
 clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 2 ++
 4 files changed, 11 insertions(+)

diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index be7c3b60c20f1..c15f1b57bafc9 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -3989,6 +3989,10 @@ def ftime_trace_EQ : Joined<["-"], "ftime-trace=">, Group<f_Group>,
   HelpText<"Similar to -ftime-trace. Specify the JSON file or a directory which will contain the JSON file">,
   Visibility<[ClangOption, CC1Option, CLOption, DXCOption]>,
   MarshallingInfoString<FrontendOpts<"TimeTracePath">>;
+def ftime_trace_add_filename : Flag<["-"], "ftime-trace-add-filename">, Group<f_Group>,
+  HelpText<"Adds filename to event details wherever supported. Eg: For template instantiation A<int>, details would include A<int>@source_file.h.">,
+  Visibility<[ClangOption, CLOption, DXCOption]>;
+  MarshallingInfoString<FrontendOpts<"TimeTraceAddFilename">>;
 def fproc_stat_report : Joined<["-"], "fproc-stat-report">, Group<f_Group>,
   HelpText<"Print subprocess statistics">;
 def fproc_stat_report_EQ : Joined<["-"], "fproc-stat-report=">, Group<f_Group>,
diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h
index 5e5034fe01eb5..019a6737f8129 100644
--- a/clang/include/clang/Frontend/FrontendOptions.h
+++ b/clang/include/clang/Frontend/FrontendOptions.h
@@ -583,6 +583,9 @@ class FrontendOptions {
   /// Path which stores the output files for -ftime-trace
   std::string TimeTracePath;
 
+  /// Adds filename to event details wherever supported
+  bool TimeTraceAddFilename = false;
+
   /// Output Path for module output file.
   std::string ModuleOutputPath;
 
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index a7bc6749c5852..f0fa7fd427906 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -3430,6 +3430,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
     llvm::raw_string_ostream OS(Name);
     Instantiation->getNameForDiagnostic(OS, getPrintingPolicy(),
                                         /*Qualified=*/true);
+    if (llvm::timeTraceAddFilename())
+      OS << "@" << SourceMgr.getFilename(Instantiation->getLocation());
     return Name;
   });
 
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 88f6af80cbc55..ba55db4117c34 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4966,6 +4966,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
     llvm::raw_string_ostream OS(Name);
     Function->getNameForDiagnostic(OS, getPrintingPolicy(),
                                    /*Qualified=*/true);
+    if (llvm::timeTraceAddFilename())
+      OS << "@" << SourceMgr.getFilename(Function->getLocation());
     return Name;
   });
 

>From ae991f8c88c21a0872a5fa63219b3cb9b2787d9a Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Wed, 10 Jul 2024 15:52:55 +0000
Subject: [PATCH 02/14] Add tests

---
 clang/include/clang/Driver/Options.td          |  4 ----
 clang/include/clang/Frontend/FrontendOptions.h |  3 ---
 clang/lib/Sema/SemaTemplateInstantiate.cpp     |  3 +--
 clang/lib/Sema/SemaTemplateInstantiateDecl.cpp |  3 +--
 clang/test/Driver/ftime-trace-sections.py      | 16 +++++++++++++++-
 5 files changed, 17 insertions(+), 12 deletions(-)

diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index c15f1b57bafc9..be7c3b60c20f1 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -3989,10 +3989,6 @@ def ftime_trace_EQ : Joined<["-"], "ftime-trace=">, Group<f_Group>,
   HelpText<"Similar to -ftime-trace. Specify the JSON file or a directory which will contain the JSON file">,
   Visibility<[ClangOption, CC1Option, CLOption, DXCOption]>,
   MarshallingInfoString<FrontendOpts<"TimeTracePath">>;
-def ftime_trace_add_filename : Flag<["-"], "ftime-trace-add-filename">, Group<f_Group>,
-  HelpText<"Adds filename to event details wherever supported. Eg: For template instantiation A<int>, details would include A<int>@source_file.h.">,
-  Visibility<[ClangOption, CLOption, DXCOption]>;
-  MarshallingInfoString<FrontendOpts<"TimeTraceAddFilename">>;
 def fproc_stat_report : Joined<["-"], "fproc-stat-report">, Group<f_Group>,
   HelpText<"Print subprocess statistics">;
 def fproc_stat_report_EQ : Joined<["-"], "fproc-stat-report=">, Group<f_Group>,
diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h
index 019a6737f8129..5e5034fe01eb5 100644
--- a/clang/include/clang/Frontend/FrontendOptions.h
+++ b/clang/include/clang/Frontend/FrontendOptions.h
@@ -583,9 +583,6 @@ class FrontendOptions {
   /// Path which stores the output files for -ftime-trace
   std::string TimeTracePath;
 
-  /// Adds filename to event details wherever supported
-  bool TimeTraceAddFilename = false;
-
   /// Output Path for module output file.
   std::string ModuleOutputPath;
 
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index f0fa7fd427906..69f46a77d8067 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -3430,8 +3430,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
     llvm::raw_string_ostream OS(Name);
     Instantiation->getNameForDiagnostic(OS, getPrintingPolicy(),
                                         /*Qualified=*/true);
-    if (llvm::timeTraceAddFilename())
-      OS << "@" << SourceMgr.getFilename(Instantiation->getLocation());
+    OS << "@" << SourceMgr.getFilename(Instantiation->getLocation());
     return Name;
   });
 
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index ba55db4117c34..d835a217802ac 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4966,8 +4966,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
     llvm::raw_string_ostream OS(Name);
     Function->getNameForDiagnostic(OS, getPrintingPolicy(),
                                    /*Qualified=*/true);
-    if (llvm::timeTraceAddFilename())
-      OS << "@" << SourceMgr.getFilename(Function->getLocation());
+    OS << "@" << SourceMgr.getFilename(Function->getLocation());
     return Name;
   });
 
diff --git a/clang/test/Driver/ftime-trace-sections.py b/clang/test/Driver/ftime-trace-sections.py
index 02afa4ac54eb7..cfec77fc97a8e 100644
--- a/clang/test/Driver/ftime-trace-sections.py
+++ b/clang/test/Driver/ftime-trace-sections.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 
-import json, sys, time
+import json, sys, time, re
 
 
 def is_inside(range1, range2):
@@ -16,12 +16,18 @@ def is_before(range1, range2):
     c = range2["ts"]
     return b <= c
 
+instantiation_pattern = re.compile("^.*<.*>@.*.cpp$")
+
+def is_valid_instantiation(instantiation):
+    return instantiation_pattern.match(instantiation["args"]["detail"])
+
 
 log_contents = json.loads(sys.stdin.read())
 events = log_contents["traceEvents"]
 codegens = [event for event in events if event["name"] == "CodeGen Function"]
 frontends = [event for event in events if event["name"] == "Frontend"]
 backends = [event for event in events if event["name"] == "Backend"]
+instantiations = [event for event in events if event["name"].startswith("Instantiate")]
 
 beginning_of_time = log_contents["beginningOfTime"] / 1000000
 seconds_since_epoch = time.time()
@@ -48,3 +54,11 @@ def is_before(range1, range2):
     ]
 ):
     sys.exit("Not all Frontend section are before all Backend sections!")
+
+if not all(
+    [
+        is_valid_instantiation(instantiation)
+        for instantiation in instantiations
+    ]
+):
+    sys.exit("Not all Frontend section are before all Backend sections!")

>From afdaaddcb490668d0565c4a0a4de1bc49b9f41e9 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Wed, 10 Jul 2024 15:57:55 +0000
Subject: [PATCH 03/14] use , file: as separator

---
 clang/lib/Sema/SemaTemplateInstantiate.cpp     | 2 +-
 clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 2 +-
 clang/test/Driver/ftime-trace-sections.py      | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 69f46a77d8067..3105f3eefa0ba 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -3430,7 +3430,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
     llvm::raw_string_ostream OS(Name);
     Instantiation->getNameForDiagnostic(OS, getPrintingPolicy(),
                                         /*Qualified=*/true);
-    OS << "@" << SourceMgr.getFilename(Instantiation->getLocation());
+    OS << ", file:" << SourceMgr.getFilename(Instantiation->getLocation());
     return Name;
   });
 
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index d835a217802ac..88390d82260f5 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4966,7 +4966,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
     llvm::raw_string_ostream OS(Name);
     Function->getNameForDiagnostic(OS, getPrintingPolicy(),
                                    /*Qualified=*/true);
-    OS << "@" << SourceMgr.getFilename(Function->getLocation());
+    OS << ", file:" << SourceMgr.getFilename(Function->getLocation());
     return Name;
   });
 
diff --git a/clang/test/Driver/ftime-trace-sections.py b/clang/test/Driver/ftime-trace-sections.py
index cfec77fc97a8e..cec62db6b0d7b 100644
--- a/clang/test/Driver/ftime-trace-sections.py
+++ b/clang/test/Driver/ftime-trace-sections.py
@@ -16,7 +16,7 @@ def is_before(range1, range2):
     c = range2["ts"]
     return b <= c
 
-instantiation_pattern = re.compile("^.*<.*>@.*.cpp$")
+instantiation_pattern = re.compile("^.*<.*>, file:.*.cpp$")
 
 def is_valid_instantiation(instantiation):
     return instantiation_pattern.match(instantiation["args"]["detail"])

>From f3a5c475935f8519d85332750bb43c4ac99d7668 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Wed, 10 Jul 2024 16:01:08 +0000
Subject: [PATCH 04/14] format and fix error messages

---
 clang/test/Driver/ftime-trace-sections.py | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/clang/test/Driver/ftime-trace-sections.py b/clang/test/Driver/ftime-trace-sections.py
index cec62db6b0d7b..c42fa3c406ff4 100644
--- a/clang/test/Driver/ftime-trace-sections.py
+++ b/clang/test/Driver/ftime-trace-sections.py
@@ -16,8 +16,10 @@ def is_before(range1, range2):
     c = range2["ts"]
     return b <= c
 
+
 instantiation_pattern = re.compile("^.*<.*>, file:.*.cpp$")
 
+
 def is_valid_instantiation(instantiation):
     return instantiation_pattern.match(instantiation["args"]["detail"])
 
@@ -55,10 +57,6 @@ def is_valid_instantiation(instantiation):
 ):
     sys.exit("Not all Frontend section are before all Backend sections!")
 
-if not all(
-    [
-        is_valid_instantiation(instantiation)
-        for instantiation in instantiations
-    ]
-):
-    sys.exit("Not all Frontend section are before all Backend sections!")
+for instantiation in instantiations:
+    if not is_valid_instantiation(instantiation):
+        sys.exit("Invalid instantiation: " + str(instantiation))

>From ecb326f79facf5287cf6cfa345d3c7c6d6ad3464 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Tue, 16 Jul 2024 15:57:25 +0000
Subject: [PATCH 05/14] add filename as structured json

---
 clang/lib/Sema/SemaTemplateInstantiate.cpp    |  8 ++--
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |  8 ++--
 clang/test/Driver/ftime-trace-sections.py     |  5 +--
 llvm/include/llvm/Support/TimeProfiler.h      | 14 +++++++
 llvm/lib/Support/TimeProfiler.cpp             | 38 +++++++++++++++++--
 5 files changed, 57 insertions(+), 16 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 3105f3eefa0ba..71880641e33af 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -3426,12 +3426,12 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
     return true;
 
   llvm::TimeTraceScope TimeScope("InstantiateClass", [&]() {
-    std::string Name;
-    llvm::raw_string_ostream OS(Name);
+    llvm::TimeTraceMetadata M;
+    llvm::raw_string_ostream OS(M.Details);
     Instantiation->getNameForDiagnostic(OS, getPrintingPolicy(),
                                         /*Qualified=*/true);
-    OS << ", file:" << SourceMgr.getFilename(Instantiation->getLocation());
-    return Name;
+    M.Filename = SourceMgr.getFilename(Instantiation->getLocation());
+    return M;
   });
 
   Pattern = PatternDef;
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 88390d82260f5..e3f12b37d45c7 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4962,12 +4962,12 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
   }
 
   llvm::TimeTraceScope TimeScope("InstantiateFunction", [&]() {
-    std::string Name;
-    llvm::raw_string_ostream OS(Name);
+    llvm::TimeTraceMetadata M;
+    llvm::raw_string_ostream OS(M.Details);
     Function->getNameForDiagnostic(OS, getPrintingPolicy(),
                                    /*Qualified=*/true);
-    OS << ", file:" << SourceMgr.getFilename(Function->getLocation());
-    return Name;
+    M.Filename = SourceMgr.getFilename(Function->getLocation());
+    return M;
   });
 
   // If we're performing recursive template instantiation, create our own
diff --git a/clang/test/Driver/ftime-trace-sections.py b/clang/test/Driver/ftime-trace-sections.py
index c42fa3c406ff4..ab05f90a1358d 100644
--- a/clang/test/Driver/ftime-trace-sections.py
+++ b/clang/test/Driver/ftime-trace-sections.py
@@ -17,11 +17,8 @@ def is_before(range1, range2):
     return b <= c
 
 
-instantiation_pattern = re.compile("^.*<.*>, file:.*.cpp$")
-
-
 def is_valid_instantiation(instantiation):
-    return instantiation_pattern.match(instantiation["args"]["detail"])
+    return instantiation["args"]["filename"].endswith(".cpp")
 
 
 log_contents = json.loads(sys.stdin.read())
diff --git a/llvm/include/llvm/Support/TimeProfiler.h b/llvm/include/llvm/Support/TimeProfiler.h
index 31f7df10916db..d669c0d2a5e23 100644
--- a/llvm/include/llvm/Support/TimeProfiler.h
+++ b/llvm/include/llvm/Support/TimeProfiler.h
@@ -83,6 +83,12 @@ namespace llvm {
 
 class raw_pwrite_stream;
 
+struct TimeTraceMetadata {
+  std::string Details;
+  // Source file information for the event.
+  std::string Filename; 
+};
+
 struct TimeTraceProfiler;
 TimeTraceProfiler *getTimeTraceProfilerInstance();
 
@@ -128,6 +134,10 @@ TimeTraceProfilerEntry *
 timeTraceProfilerBegin(StringRef Name,
                        llvm::function_ref<std::string()> Detail);
 
+TimeTraceProfilerEntry *
+timeTraceProfilerBegin(StringRef Name,
+                       llvm::function_ref<TimeTraceMetadata()> MetaData);
+
 /// Manually begin a time section, with the given \p Name and \p Detail.
 /// This starts Async Events having \p Name as a category which is shown
 /// separately from other traces. See
@@ -164,6 +174,10 @@ class TimeTraceScope {
     if (getTimeTraceProfilerInstance() != nullptr)
       Entry = timeTraceProfilerBegin(Name, Detail);
   }
+  TimeTraceScope(StringRef Name, llvm::function_ref<TimeTraceMetadata()> Metadata) {
+    if (getTimeTraceProfilerInstance() != nullptr)
+      Entry = timeTraceProfilerBegin(Name, Metadata);
+  }
   ~TimeTraceScope() {
     if (getTimeTraceProfilerInstance() != nullptr)
       timeTraceProfilerEnd(Entry);
diff --git a/llvm/lib/Support/TimeProfiler.cpp b/llvm/lib/Support/TimeProfiler.cpp
index 9612db7d30f98..4b0466b265db4 100644
--- a/llvm/lib/Support/TimeProfiler.cpp
+++ b/llvm/lib/Support/TimeProfiler.cpp
@@ -73,12 +73,20 @@ struct llvm::TimeTraceProfilerEntry {
   const TimePointType Start;
   TimePointType End;
   const std::string Name;
-  const std::string Detail;
+  TimeTraceMetadata Metadata;
+
   const bool AsyncEvent = false;
   TimeTraceProfilerEntry(TimePointType &&S, TimePointType &&E, std::string &&N,
                          std::string &&Dt, bool Ae)
+      : Start(std::move(S)), End(std::move(E)), Name(std::move(N)), Metadata(),
+        AsyncEvent(Ae) {
+    Metadata.Details = std::move(Dt);
+  }
+
+  TimeTraceProfilerEntry(TimePointType &&S, TimePointType &&E, std::string &&N,
+                         TimeTraceMetadata &&Mt, bool Ae)
       : Start(std::move(S)), End(std::move(E)), Name(std::move(N)),
-        Detail(std::move(Dt)), AsyncEvent(Ae) {}
+        Metadata(std::move(Mt)), AsyncEvent(Ae) {}
 
   // Calculate timings for FlameGraph. Cast time points to microsecond precision
   // rather than casting duration. This avoids truncation issues causing inner
@@ -113,6 +121,15 @@ struct llvm::TimeTraceProfiler {
     return Stack.back().get();
   }
 
+  TimeTraceProfilerEntry *begin(std::string Name,
+                                llvm::function_ref<TimeTraceMetadata()>Metadata,
+                                bool AsyncEvent = false) {
+    Stack.emplace_back(std::make_unique<TimeTraceProfilerEntry>(
+        ClockType::now(), TimePointType(), std::move(Name), Metadata(),
+        AsyncEvent));
+    return Stack.back().get();
+  }
+
   void end() {
     assert(!Stack.empty() && "Must call begin() first");
     end(*Stack.back());
@@ -184,8 +201,13 @@ struct llvm::TimeTraceProfiler {
           J.attribute("dur", DurUs);
         }
         J.attribute("name", E.Name);
-        if (!E.Detail.empty()) {
-          J.attributeObject("args", [&] { J.attribute("detail", E.Detail); });
+        if (!E.Metadata.Details.empty()) {
+          J.attributeObject("args",
+                            [&] { J.attribute("detail", E.Metadata.Details); });
+        }
+        if (!E.Metadata.Filename.empty()) {
+          J.attributeObject(
+              "args", [&] { J.attribute("filename", E.Metadata.Filename); });
         }
       });
 
@@ -381,6 +403,14 @@ llvm::timeTraceProfilerBegin(StringRef Name,
   return nullptr;
 }
 
+TimeTraceProfilerEntry *
+llvm::timeTraceProfilerBegin(StringRef Name,
+                             llvm::function_ref<TimeTraceMetadata()> Metadata) {
+  if (TimeTraceProfilerInstance != nullptr)
+    return TimeTraceProfilerInstance->begin(std::string(Name), Metadata, false);
+  return nullptr;
+}
+
 TimeTraceProfilerEntry *llvm::timeTraceAsyncProfilerBegin(StringRef Name,
                                                           StringRef Detail) {
   if (TimeTraceProfilerInstance != nullptr)

>From 7032c5c7bf8f65eb4792bf9e5fdc5ba9b762c846 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Tue, 16 Jul 2024 15:59:20 +0000
Subject: [PATCH 06/14] prep for rebase. ignore ftime-trace-sections.py

---
 clang/test/Driver/ftime-trace-sections.py | 11 +----------
 1 file changed, 1 insertion(+), 10 deletions(-)

diff --git a/clang/test/Driver/ftime-trace-sections.py b/clang/test/Driver/ftime-trace-sections.py
index ab05f90a1358d..02afa4ac54eb7 100644
--- a/clang/test/Driver/ftime-trace-sections.py
+++ b/clang/test/Driver/ftime-trace-sections.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 
-import json, sys, time, re
+import json, sys, time
 
 
 def is_inside(range1, range2):
@@ -17,16 +17,11 @@ def is_before(range1, range2):
     return b <= c
 
 
-def is_valid_instantiation(instantiation):
-    return instantiation["args"]["filename"].endswith(".cpp")
-
-
 log_contents = json.loads(sys.stdin.read())
 events = log_contents["traceEvents"]
 codegens = [event for event in events if event["name"] == "CodeGen Function"]
 frontends = [event for event in events if event["name"] == "Frontend"]
 backends = [event for event in events if event["name"] == "Backend"]
-instantiations = [event for event in events if event["name"].startswith("Instantiate")]
 
 beginning_of_time = log_contents["beginningOfTime"] / 1000000
 seconds_since_epoch = time.time()
@@ -53,7 +48,3 @@ def is_valid_instantiation(instantiation):
     ]
 ):
     sys.exit("Not all Frontend section are before all Backend sections!")
-
-for instantiation in instantiations:
-    if not is_valid_instantiation(instantiation):
-        sys.exit("Invalid instantiation: " + str(instantiation))

>From 51035aff99a38bda1aeb994cd560fc0f798f2546 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Tue, 16 Jul 2024 16:06:10 +0000
Subject: [PATCH 07/14] rebase. add option. add unit tests.

---
 clang/include/clang/Driver/Options.td         |  4 ++
 .../include/clang/Frontend/FrontendOptions.h  |  8 +++-
 clang/lib/Driver/ToolChains/Clang.cpp         |  1 +
 clang/lib/Sema/SemaTemplateInstantiate.cpp    |  5 ++-
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |  5 ++-
 clang/test/Driver/ftime-trace-sections.cpp    |  2 +-
 clang/test/Driver/ftime-trace-sections.py     |  6 ++-
 clang/test/Driver/ftime-trace.cpp             | 39 ++++++++--------
 clang/tools/driver/cc1_main.cpp               |  3 +-
 clang/unittests/Support/TimeProfilerTest.cpp  | 44 ++++++++++++-------
 llvm/include/llvm/Support/TimeProfiler.h      | 14 ++++--
 llvm/lib/Support/TimeProfiler.cpp             | 43 +++++++++++-------
 12 files changed, 112 insertions(+), 62 deletions(-)

diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 561aa28a52b1f..7d6e0bf01823b 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -3986,6 +3986,10 @@ def ftime_trace_granularity_EQ : Joined<["-"], "ftime-trace-granularity=">, Grou
   HelpText<"Minimum time granularity (in microseconds) traced by time profiler">,
   Visibility<[ClangOption, CC1Option, CLOption, DXCOption]>,
   MarshallingInfoInt<FrontendOpts<"TimeTraceGranularity">, "500u">;
+def ftime_trace_verbose : Joined<["-"], "ftime-trace-verbose">, Group<f_Group>,
+  HelpText<"Make time trace capture verbose event details (eg. source filenames). This can increase the size of the output by 2-3 times">,
+  Visibility<[ClangOption, CC1Option, CLOption, DXCOption]>,
+  MarshallingInfoFlag<FrontendOpts<"TimeTraceVerbose">>;
 def ftime_trace_EQ : Joined<["-"], "ftime-trace=">, Group<f_Group>,
   HelpText<"Similar to -ftime-trace. Specify the JSON file or a directory which will contain the JSON file">,
   Visibility<[ClangOption, CC1Option, CLOption, DXCOption]>,
diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h
index 5e5034fe01eb5..cafacb8e54af7 100644
--- a/clang/include/clang/Frontend/FrontendOptions.h
+++ b/clang/include/clang/Frontend/FrontendOptions.h
@@ -580,6 +580,11 @@ class FrontendOptions {
   /// Minimum time granularity (in microseconds) traced by time profiler.
   unsigned TimeTraceGranularity;
 
+  /// Make time trace capture verbose event details (eg. source filenames). This
+  /// can increase the size of the output by 2-3 times.
+  LLVM_PREFERRED_TYPE(bool)
+  unsigned TimeTraceVerbose : 1;
+
   /// Path which stores the output files for -ftime-trace
   std::string TimeTracePath;
 
@@ -601,7 +606,8 @@ class FrontendOptions {
         EmitSymbolGraph(false), EmitExtensionSymbolGraphs(false),
         EmitSymbolGraphSymbolLabelsForTesting(false),
         EmitPrettySymbolGraphs(false), GenReducedBMI(false),
-        UseClangIRPipeline(false), TimeTraceGranularity(500) {}
+        UseClangIRPipeline(false), TimeTraceGranularity(500),
+        TimeTraceVerbose(false) {}
 
   /// getInputKindForExtension - Return the appropriate input kind for a file
   /// extension. For example, "c" would return Language::C.
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index d48b26cc74132..b3d2a0ff9a136 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -6746,6 +6746,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
   if (const char *Name = C.getTimeTraceFile(&JA)) {
     CmdArgs.push_back(Args.MakeArgString("-ftime-trace=" + Twine(Name)));
     Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_granularity_EQ);
+    Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_verbose);
   }
 
   if (Arg *A = Args.getLastArg(options::OPT_ftrapv_handler_EQ)) {
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 71880641e33af..12353686cfcc0 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -3427,10 +3427,11 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
 
   llvm::TimeTraceScope TimeScope("InstantiateClass", [&]() {
     llvm::TimeTraceMetadata M;
-    llvm::raw_string_ostream OS(M.Details);
+    llvm::raw_string_ostream OS(M.Detail);
     Instantiation->getNameForDiagnostic(OS, getPrintingPolicy(),
                                         /*Qualified=*/true);
-    M.Filename = SourceMgr.getFilename(Instantiation->getLocation());
+    if (llvm::isTimeTraceVerbose())
+      M.Filename = SourceMgr.getFilename(Instantiation->getLocation());
     return M;
   });
 
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 4c264b11a9c14..f8da6d6ecebf1 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4967,10 +4967,11 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
 
   llvm::TimeTraceScope TimeScope("InstantiateFunction", [&]() {
     llvm::TimeTraceMetadata M;
-    llvm::raw_string_ostream OS(M.Details);
+    llvm::raw_string_ostream OS(M.Detail);
     Function->getNameForDiagnostic(OS, getPrintingPolicy(),
                                    /*Qualified=*/true);
-    M.Filename = SourceMgr.getFilename(Function->getLocation());
+    if (llvm::isTimeTraceVerbose())
+      M.Filename = SourceMgr.getFilename(Function->getLocation());
     return M;
   });
 
diff --git a/clang/test/Driver/ftime-trace-sections.cpp b/clang/test/Driver/ftime-trace-sections.cpp
index 0c16052bc0c3a..da7109b9d81a6 100644
--- a/clang/test/Driver/ftime-trace-sections.cpp
+++ b/clang/test/Driver/ftime-trace-sections.cpp
@@ -1,5 +1,5 @@
 // RUN: rm -rf %t && mkdir %t && cd %t
-// RUN: %clangxx -S -ftime-trace -ftime-trace-granularity=0 -o out %s
+// RUN: %clangxx -S -ftime-trace -ftime-trace-granularity=0 -ftime-trace-verbose -o out %s
 // RUN: %python %S/ftime-trace-sections.py < out.json
 
 template <typename T>
diff --git a/clang/test/Driver/ftime-trace-sections.py b/clang/test/Driver/ftime-trace-sections.py
index b332931d29a62..b30fc1bc76ed3 100755
--- a/clang/test/Driver/ftime-trace-sections.py
+++ b/clang/test/Driver/ftime-trace-sections.py
@@ -51,7 +51,7 @@ def is_before(range1, range2):
     ]
 ):
     sys.exit("Not all Frontend section are before all Backend sections!")
-
+print( "\n\n" ,instants , "\n==================")
 # Check that entries for foo exist and are in a demangled form.
 if not any(e for e in instants if "foo<int>" in e["args"]["detail"]):
     sys.exit("Missing Instantiate entry for foo!")
@@ -59,3 +59,7 @@ def is_before(range1, range2):
     sys.exit("Missing CodeGen entry for foo!")
 if not any(e for e in opts if "foo<int>" in e["args"]["detail"]):
     sys.exit("Missing Optimize entry for foo!")
+
+for i in instants:
+    if not i["args"]["filename"].endswith(".cpp"):
+        sys.exit("No filename in instantiation: " + str(i))
\ No newline at end of file
diff --git a/clang/test/Driver/ftime-trace.cpp b/clang/test/Driver/ftime-trace.cpp
index 5fe63de915a71..60c5885704b58 100644
--- a/clang/test/Driver/ftime-trace.cpp
+++ b/clang/test/Driver/ftime-trace.cpp
@@ -1,18 +1,18 @@
 // RUN: rm -rf %t && mkdir -p %t && cd %t
-// RUN: %clangxx -S -no-canonical-prefixes -ftime-trace -ftime-trace-granularity=0 -o out %s
+// RUN: %clangxx -S -no-canonical-prefixes -ftime-trace -ftime-trace-granularity=0 -ftime-trace-verbose -o out %s
 // RUN: cat out.json \
 // RUN:   | %python -c 'import json, sys; json.dump(json.loads(sys.stdin.read()), sys.stdout, sort_keys=True, indent=2)' \
 // RUN:   | FileCheck %s
-// RUN: %clangxx -S -no-canonical-prefixes -ftime-trace=new-name.json -ftime-trace-granularity=0 -o out %s
+// RUN: %clangxx -S -no-canonical-prefixes -ftime-trace=new-name.json -ftime-trace-granularity=0 -ftime-trace-verbose -o out %s
 // RUN: cat new-name.json \
 // RUN:   | %python -c 'import json, sys; json.dump(json.loads(sys.stdin.read()), sys.stdout, sort_keys=True, indent=2)' \
 // RUN:   | FileCheck %s
 // RUN: mkdir dir1 dir2
-// RUN: %clangxx -S -no-canonical-prefixes -ftime-trace=dir1 -ftime-trace-granularity=0 -o out %s
+// RUN: %clangxx -S -no-canonical-prefixes -ftime-trace=dir1 -ftime-trace-granularity=0 -ftime-trace-verbose -o out %s
 // RUN: cat dir1/out.json \
 // RUN:   | %python -c 'import json, sys; json.dump(json.loads(sys.stdin.read()), sys.stdout, sort_keys=True, indent=2)' \
 // RUN:   | FileCheck %s
-// RUN: %clangxx -S -no-canonical-prefixes -ftime-trace=dir2/ -ftime-trace-granularity=0 -o out %s
+// RUN: %clangxx -S -no-canonical-prefixes -ftime-trace=dir2/ -ftime-trace-granularity=0 -ftime-trace-verbose -o out %s
 // RUN: cat dir2/out.json \
 // RUN:   | %python -c 'import json, sys; json.dump(json.loads(sys.stdin.read()), sys.stdout, sort_keys=True, indent=2)' \
 // RUN:   | FileCheck %s
@@ -34,32 +34,33 @@
 // RUN: mkdir d e f && cp %s d/a.cpp && touch d/b.c
 
 /// TODO: Support -fno-integrated-as.
-// RUN: %clang -### -c -ftime-trace -ftime-trace-granularity=0 -fintegrated-as d/a.cpp -o e/a.o 2>&1 | FileCheck %s --check-prefix=COMPILE1
-// COMPILE1: -cc1{{.*}} "-ftime-trace=e/a.json" "-ftime-trace-granularity=0"
+// RUN: %clang -### -c -ftime-trace -ftime-trace-granularity=0 -ftime-trace-verbose -fintegrated-as d/a.cpp -o e/a.o 2>&1 | FileCheck %s --check-prefix=COMPILE1
+// COMPILE1: -cc1{{.*}} "-ftime-trace=e/a.json" "-ftime-trace-granularity=0" "-ftime-trace-verbose"
 
-// RUN: %clang -### -c -ftime-trace -ftime-trace-granularity=0 d/a.cpp d/b.c -dumpdir f/ 2>&1 | FileCheck %s --check-prefix=COMPILE2
-// COMPILE2: -cc1{{.*}} "-ftime-trace=f/a.json" "-ftime-trace-granularity=0"
-// COMPILE2: -cc1{{.*}} "-ftime-trace=f/b.json" "-ftime-trace-granularity=0"
+// RUN: %clang -### -c -ftime-trace -ftime-trace-granularity=0 -ftime-trace-verbose d/a.cpp d/b.c -dumpdir f/ 2>&1 | FileCheck %s --check-prefix=COMPILE2
+// COMPILE2: -cc1{{.*}} "-ftime-trace=f/a.json" "-ftime-trace-granularity=0" "-ftime-trace-verbose"
+// COMPILE2: -cc1{{.*}} "-ftime-trace=f/b.json" "-ftime-trace-granularity=0" "-ftime-trace-verbose"
 
 /// -o specifies the link output. Create ${output}-${basename}.json.
-// RUN: %clang -### -ftime-trace -ftime-trace-granularity=0 d/a.cpp d/b.c -o e/x 2>&1 | FileCheck %s --check-prefix=LINK1
-// LINK1: -cc1{{.*}} "-ftime-trace=e/x-a.json" "-ftime-trace-granularity=0"
-// LINK1: -cc1{{.*}} "-ftime-trace=e/x-b.json" "-ftime-trace-granularity=0"
+// RUN: %clang -### -ftime-trace -ftime-trace-granularity=0 -ftime-trace-verbose d/a.cpp d/b.c -o e/x 2>&1 | FileCheck %s --check-prefix=LINK1
+// LINK1: -cc1{{.*}} "-ftime-trace=e/x-a.json" "-ftime-trace-granularity=0" "-ftime-trace-verbose"
+// LINK1: -cc1{{.*}} "-ftime-trace=e/x-b.json" "-ftime-trace-granularity=0" "-ftime-trace-verbose"
 
 /// -dumpdir is f/g, not ending with a path separator. We create f/g${basename}.json.
-// RUN: %clang -### -ftime-trace -ftime-trace-granularity=0 d/a.cpp d/b.c -o e/x -dumpdir f/g 2>&1 | FileCheck %s --check-prefix=LINK2
-// LINK2: -cc1{{.*}} "-ftime-trace=f/ga.json" "-ftime-trace-granularity=0"
-// LINK2: -cc1{{.*}} "-ftime-trace=f/gb.json" "-ftime-trace-granularity=0"
+// RUN: %clang -### -ftime-trace -ftime-trace-granularity=0 -ftime-trace-verbose d/a.cpp d/b.c -o e/x -dumpdir f/g 2>&1 | FileCheck %s --check-prefix=LINK2
+// LINK2: -cc1{{.*}} "-ftime-trace=f/ga.json" "-ftime-trace-granularity=0" "-ftime-trace-verbose"
+// LINK2: -cc1{{.*}} "-ftime-trace=f/gb.json" "-ftime-trace-granularity=0" "-ftime-trace-verbose"
 
-// RUN: %clang -### -ftime-trace=e -ftime-trace-granularity=0 d/a.cpp d/b.c -o f/x -dumpdir f/ 2>&1 | FileCheck %s --check-prefix=LINK3
-// LINK3: -cc1{{.*}} "-ftime-trace=e{{/|\\\\}}a-{{[^.]*}}.json" "-ftime-trace-granularity=0"
-// LINK3: -cc1{{.*}} "-ftime-trace=e{{/|\\\\}}b-{{[^.]*}}.json" "-ftime-trace-granularity=0"
+// RUN: %clang -### -ftime-trace=e -ftime-trace-granularity=0 -ftime-trace-verbose d/a.cpp d/b.c -o f/x -dumpdir f/ 2>&1 | FileCheck %s --check-prefix=LINK3
+// LINK3: -cc1{{.*}} "-ftime-trace=e{{/|\\\\}}a-{{[^.]*}}.json" "-ftime-trace-granularity=0" "-ftime-trace-verbose"
+// LINK3: -cc1{{.*}} "-ftime-trace=e{{/|\\\\}}b-{{[^.]*}}.json" "-ftime-trace-granularity=0" "-ftime-trace-verbose"
 
-// RUN: %clang -### -ftime-trace -ftime-trace=e -ftime-trace-granularity=1 -xassembler d/a.cpp 2>&1 | \
+// RUN: %clang -### -ftime-trace -ftime-trace=e -ftime-trace-granularity=1 -ftime-trace-verbose -xassembler d/a.cpp 2>&1 | \
 // RUN:   FileCheck %s --check-prefix=UNUSED
 // UNUSED:      warning: argument unused during compilation: '-ftime-trace'
 // UNUSED-NEXT: warning: argument unused during compilation: '-ftime-trace=e'
 // UNUSED-NEXT: warning: argument unused during compilation: '-ftime-trace-granularity=1'
+// UNUSED-NEXT: warning: argument unused during compilation: '-ftime-trace-verbose'
 // UNUSED-NOT:  warning:
 
 template <typename T>
diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp
index c2ccb47a15bc8..f5e5fad36573e 100644
--- a/clang/tools/driver/cc1_main.cpp
+++ b/clang/tools/driver/cc1_main.cpp
@@ -241,7 +241,8 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
 
   if (!Clang->getFrontendOpts().TimeTracePath.empty()) {
     llvm::timeTraceProfilerInitialize(
-        Clang->getFrontendOpts().TimeTraceGranularity, Argv0);
+        Clang->getFrontendOpts().TimeTraceGranularity, Argv0,
+        Clang->getFrontendOpts().TimeTraceVerbose);
   }
   // --print-supported-cpus takes priority over the actual compilation.
   if (Clang->getFrontendOpts().PrintSupportedCPUs)
diff --git a/clang/unittests/Support/TimeProfilerTest.cpp b/clang/unittests/Support/TimeProfilerTest.cpp
index 5f3950ff033f1..35297601a9e4e 100644
--- a/clang/unittests/Support/TimeProfilerTest.cpp
+++ b/clang/unittests/Support/TimeProfilerTest.cpp
@@ -23,7 +23,8 @@ namespace {
 
 // Should be called before testing.
 void setupProfiler() {
-  timeTraceProfilerInitialize(/*TimeTraceGranularity=*/0, "test");
+  timeTraceProfilerInitialize(/*TimeTraceGranularity=*/0, "test",
+                              /*TimeTraceVerbose=*/true);
 }
 
 // Should be called after `compileFromString()`.
@@ -65,8 +66,8 @@ std::string buildTraceGraph(StringRef Json) {
   struct EventRecord {
     int64_t TimestampBegin;
     int64_t TimestampEnd;
-    StringRef Name;
-    StringRef Detail;
+    std::string Name;
+    std::string Metadata;
   };
   std::vector<EventRecord> Events;
 
@@ -81,10 +82,16 @@ std::string buildTraceGraph(StringRef Json) {
     int64_t TimestampBegin = TraceEventObj->getInteger("ts").value_or(0);
     int64_t TimestampEnd =
         TimestampBegin + TraceEventObj->getInteger("dur").value_or(0);
-    StringRef Name = TraceEventObj->getString("name").value_or("");
-    StringRef Detail = "";
-    if (json::Object *Args = TraceEventObj->getObject("args"))
-      Detail = Args->getString("detail").value_or("");
+    std::string Name = TraceEventObj->getString("name").value_or("").str();
+    std::string Metadata = "";
+    if (json::Object *Args = TraceEventObj->getObject("args")) {
+      if (StringRef Detail = Args->getString("detail").value_or("");
+          !Detail.empty())
+        Metadata += Detail.str();
+      if (StringRef File = Args->getString("filename").value_or("");
+          !File.empty())
+        Metadata += ", " + File.str();
+    }
 
     // This is a "summary" event, like "Total PerformPendingInstantiations",
     // skip it
@@ -92,7 +99,7 @@ std::string buildTraceGraph(StringRef Json) {
       continue;
 
     Events.emplace_back(
-        EventRecord{TimestampBegin, TimestampEnd, Name, Detail});
+        EventRecord{TimestampBegin, TimestampEnd, Name, Metadata});
   }
 
   // There can be nested events that are very fast, for example:
@@ -132,9 +139,9 @@ std::string buildTraceGraph(StringRef Json) {
       Stream << "| ";
     }
     Stream.write(Event.Name.data(), Event.Name.size());
-    if (!Event.Detail.empty()) {
+    if (!Event.Metadata.empty()) {
       Stream << " (";
-      Stream.write(Event.Detail.data(), Event.Detail.size());
+      Stream.write(Event.Metadata.data(), Event.Metadata.size());
       Stream << ")";
     }
     Stream << "\n";
@@ -170,13 +177,16 @@ int slow_arr[12 + 34 * 56 +                                  // 22nd line
              static_cast<int>(slow_namespace::slow_func())]; // 23rd line
 
 constexpr int slow_init_list[] = {1, 1, 2, 3, 5, 8, 13, 21}; // 25th line
+
+template <typename T>
+void foo(T) {}
+void bar() { foo(0); }
     )";
 
   setupProfiler();
   ASSERT_TRUE(compileFromString(Code, "-std=c++20", "test.cc"));
   std::string Json = teardownProfiler();
-  std::string TraceGraph = buildTraceGraph(Json);
-  ASSERT_TRUE(TraceGraph == R"(
+  ASSERT_EQ(R"(
 Frontend
 | ParseDeclarationOrFunctionDefinition (test.cc:2:1)
 | ParseDeclarationOrFunctionDefinition (test.cc:6:1)
@@ -201,11 +211,13 @@ Frontend
 | | EvaluateAsRValue (<test.cc:22:14, line:23:58>)
 | ParseDeclarationOrFunctionDefinition (test.cc:25:1)
 | | EvaluateAsInitializer (slow_init_list)
+| ParseFunctionDefinition (foo)
+| ParseDeclarationOrFunctionDefinition (test.cc:29:1)
+| | ParseFunctionDefinition (bar)
 | PerformPendingInstantiations
-)");
-
-  // NOTE: If this test is failing, run this test with
-  // `llvm::errs() << TraceGraph;` and change the assert above.
+| | InstantiateFunction (foo<int>, test.cc)
+)",
+            buildTraceGraph(Json));
 }
 
 TEST(TimeProfilerTest, ConstantEvaluationC99) {
diff --git a/llvm/include/llvm/Support/TimeProfiler.h b/llvm/include/llvm/Support/TimeProfiler.h
index d669c0d2a5e23..f61aedb3bc37e 100644
--- a/llvm/include/llvm/Support/TimeProfiler.h
+++ b/llvm/include/llvm/Support/TimeProfiler.h
@@ -84,21 +84,26 @@ namespace llvm {
 class raw_pwrite_stream;
 
 struct TimeTraceMetadata {
-  std::string Details;
+  std::string Detail;
   // Source file information for the event.
-  std::string Filename; 
+  std::string Filename;
+
+  bool isEmpty() const { return Detail.empty() && Filename.empty(); }
 };
 
 struct TimeTraceProfiler;
 TimeTraceProfiler *getTimeTraceProfilerInstance();
 
+bool isTimeTraceVerbose();
+
 struct TimeTraceProfilerEntry;
 
 /// Initialize the time trace profiler.
 /// This sets up the global \p TimeTraceProfilerInstance
 /// variable to be the profiler instance.
 void timeTraceProfilerInitialize(unsigned TimeTraceGranularity,
-                                 StringRef ProcName);
+                                 StringRef ProcName,
+                                 bool TimeTraceVerbose = false);
 
 /// Cleanup the time trace profiler, if it was initialized.
 void timeTraceProfilerCleanup();
@@ -174,7 +179,8 @@ class TimeTraceScope {
     if (getTimeTraceProfilerInstance() != nullptr)
       Entry = timeTraceProfilerBegin(Name, Detail);
   }
-  TimeTraceScope(StringRef Name, llvm::function_ref<TimeTraceMetadata()> Metadata) {
+  TimeTraceScope(StringRef Name,
+                 llvm::function_ref<TimeTraceMetadata()> Metadata) {
     if (getTimeTraceProfilerInstance() != nullptr)
       Entry = timeTraceProfilerBegin(Name, Metadata);
   }
diff --git a/llvm/lib/Support/TimeProfiler.cpp b/llvm/lib/Support/TimeProfiler.cpp
index 4b0466b265db4..ccea04b1940a2 100644
--- a/llvm/lib/Support/TimeProfiler.cpp
+++ b/llvm/lib/Support/TimeProfiler.cpp
@@ -80,7 +80,7 @@ struct llvm::TimeTraceProfilerEntry {
                          std::string &&Dt, bool Ae)
       : Start(std::move(S)), End(std::move(E)), Name(std::move(N)), Metadata(),
         AsyncEvent(Ae) {
-    Metadata.Details = std::move(Dt);
+    Metadata.Detail = std::move(Dt);
   }
 
   TimeTraceProfilerEntry(TimePointType &&S, TimePointType &&E, std::string &&N,
@@ -105,10 +105,12 @@ struct llvm::TimeTraceProfilerEntry {
 };
 
 struct llvm::TimeTraceProfiler {
-  TimeTraceProfiler(unsigned TimeTraceGranularity = 0, StringRef ProcName = "")
+  TimeTraceProfiler(unsigned TimeTraceGranularity = 0, StringRef ProcName = "",
+                    bool TimeTraceVerbose = false)
       : BeginningOfTime(system_clock::now()), StartTime(ClockType::now()),
         ProcName(ProcName), Pid(sys::Process::getProcessId()),
-        Tid(llvm::get_threadid()), TimeTraceGranularity(TimeTraceGranularity) {
+        Tid(llvm::get_threadid()), TimeTraceGranularity(TimeTraceGranularity),
+        TimeTraceVerbose(TimeTraceVerbose) {
     llvm::get_thread_name(ThreadName);
   }
 
@@ -121,9 +123,9 @@ struct llvm::TimeTraceProfiler {
     return Stack.back().get();
   }
 
-  TimeTraceProfilerEntry *begin(std::string Name,
-                                llvm::function_ref<TimeTraceMetadata()>Metadata,
-                                bool AsyncEvent = false) {
+  TimeTraceProfilerEntry *
+  begin(std::string Name, llvm::function_ref<TimeTraceMetadata()> Metadata,
+        bool AsyncEvent = false) {
     Stack.emplace_back(std::make_unique<TimeTraceProfilerEntry>(
         ClockType::now(), TimePointType(), std::move(Name), Metadata(),
         AsyncEvent));
@@ -201,13 +203,13 @@ struct llvm::TimeTraceProfiler {
           J.attribute("dur", DurUs);
         }
         J.attribute("name", E.Name);
-        if (!E.Metadata.Details.empty()) {
-          J.attributeObject("args",
-                            [&] { J.attribute("detail", E.Metadata.Details); });
-        }
-        if (!E.Metadata.Filename.empty()) {
-          J.attributeObject(
-              "args", [&] { J.attribute("filename", E.Metadata.Filename); });
+        if (!E.Metadata.isEmpty()) {
+          J.attributeObject("args", [&] {
+            if (!E.Metadata.Detail.empty())
+              J.attribute("detail", E.Metadata.Detail);
+            if (!E.Metadata.Filename.empty())
+              J.attribute("filename", E.Metadata.Filename);
+          });
         }
       });
 
@@ -329,14 +331,25 @@ struct llvm::TimeTraceProfiler {
 
   // Minimum time granularity (in microseconds)
   const unsigned TimeTraceGranularity;
+
+  // Make time trace capture verbose event details (eg. source filenames). This
+  // can increase the size of the output by 2-3 times.
+  const bool TimeTraceVerbose;
 };
 
+bool llvm::isTimeTraceVerbose() {
+  return getTimeTraceProfilerInstance() &&
+         getTimeTraceProfilerInstance()->TimeTraceVerbose;
+}
+
 void llvm::timeTraceProfilerInitialize(unsigned TimeTraceGranularity,
-                                       StringRef ProcName) {
+                                       StringRef ProcName,
+                                       bool TimeTraceVerbose) {
   assert(TimeTraceProfilerInstance == nullptr &&
          "Profiler should not be initialized");
   TimeTraceProfilerInstance = new TimeTraceProfiler(
-      TimeTraceGranularity, llvm::sys::path::filename(ProcName));
+      TimeTraceGranularity, llvm::sys::path::filename(ProcName),
+      TimeTraceVerbose);
 }
 
 // Removes all TimeTraceProfilerInstances.

>From d9fd50b845de2e978ffc68fa10aaf5fcc0e26746 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Wed, 17 Jul 2024 09:00:19 +0000
Subject: [PATCH 08/14] format. release notes

---
 clang/docs/ReleaseNotes.rst               | 3 +++
 clang/test/Driver/ftime-trace-sections.py | 2 +-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index cb96c5a16f261..640bb44f42bb2 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -719,6 +719,9 @@ Improvements to Clang's time-trace
 - Clang now specifies that using ``auto`` in a lambda parameter is a C++14 extension when
   appropriate. (`#46059: <https://github.com/llvm/llvm-project/issues/46059>`_).
 
+- Clang now adds source file infomation for template instantiations as ``event["args"]["filename"]``. This
+  added behind an option ``-ftime-trace-verbose``. This is expected to increase the size of trace by 2-3 times.
+
 Improvements to Coverage Mapping
 --------------------------------
 
diff --git a/clang/test/Driver/ftime-trace-sections.py b/clang/test/Driver/ftime-trace-sections.py
index b30fc1bc76ed3..a5ed2de1239b3 100755
--- a/clang/test/Driver/ftime-trace-sections.py
+++ b/clang/test/Driver/ftime-trace-sections.py
@@ -51,7 +51,7 @@ def is_before(range1, range2):
     ]
 ):
     sys.exit("Not all Frontend section are before all Backend sections!")
-print( "\n\n" ,instants , "\n==================")
+
 # Check that entries for foo exist and are in a demangled form.
 if not any(e for e in instants if "foo<int>" in e["args"]["detail"]):
     sys.exit("Missing Instantiate entry for foo!")

>From ee7bd8c6c6201eb01d29fe23bc631f4a5a710532 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Wed, 17 Jul 2024 14:35:14 +0000
Subject: [PATCH 09/14] get expansion loc

---
 clang/lib/Sema/SemaTemplateInstantiate.cpp    |   3 +-
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |   3 +-
 clang/unittests/Support/TimeProfilerTest.cpp  | 124 ++++++++++++++----
 3 files changed, 100 insertions(+), 30 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 12353686cfcc0..bb8933277a5d0 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -3431,7 +3431,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
     Instantiation->getNameForDiagnostic(OS, getPrintingPolicy(),
                                         /*Qualified=*/true);
     if (llvm::isTimeTraceVerbose())
-      M.Filename = SourceMgr.getFilename(Instantiation->getLocation());
+      M.Filename = SourceMgr.getFilename(
+          SourceMgr.getExpansionLoc(Instantiation->getLocation()));
     return M;
   });
 
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index f8da6d6ecebf1..72fa2cb7b0315 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4971,7 +4971,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
     Function->getNameForDiagnostic(OS, getPrintingPolicy(),
                                    /*Qualified=*/true);
     if (llvm::isTimeTraceVerbose())
-      M.Filename = SourceMgr.getFilename(Function->getLocation());
+      M.Filename = SourceMgr.getFilename(
+          SourceMgr.getExpansionLoc(Function->getLocation()));
     return M;
   });
 
diff --git a/clang/unittests/Support/TimeProfilerTest.cpp b/clang/unittests/Support/TimeProfilerTest.cpp
index 35297601a9e4e..083e6a791f3e0 100644
--- a/clang/unittests/Support/TimeProfilerTest.cpp
+++ b/clang/unittests/Support/TimeProfilerTest.cpp
@@ -10,11 +10,14 @@
 #include "clang/Frontend/FrontendActions.h"
 #include "clang/Lex/PreprocessorOptions.h"
 
+#include "llvm/ADT/StringMap.h"
 #include "llvm/Support/JSON.h"
 #include "llvm/Support/TimeProfiler.h"
+#include "llvm/Support/VirtualFileSystem.h"
 #include <stack>
 
 #include "gtest/gtest.h"
+#include <tuple>
 
 using namespace clang;
 using namespace llvm;
@@ -39,14 +42,24 @@ std::string teardownProfiler() {
 
 // Returns true if code compiles successfully.
 // We only parse AST here. This is enough for constexpr evaluation.
-bool compileFromString(StringRef Code, StringRef Standard, StringRef FileName) {
+bool compileFromString(StringRef Code, StringRef Standard, StringRef FileName,
+                       llvm::StringMap<StringRef> Headers = {}) {
   CompilerInstance Compiler;
   Compiler.createDiagnostics();
 
+  llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(
+      new llvm::vfs::InMemoryFileSystem());
+  FS->addFile(FileName, 0, MemoryBuffer::getMemBuffer(Code));
+  for (const auto &Header : Headers) {
+    FS->addFile(Header.getKey(), 0,
+                MemoryBuffer::getMemBuffer(Header.getValue()));
+  }
+  llvm::IntrusiveRefCntPtr<FileManager> Files(
+      new FileManager(FileSystemOptions(), FS));
+  Compiler.setFileManager(Files.get());
+
   auto Invocation = std::make_shared<CompilerInvocation>();
-  Invocation->getPreprocessorOpts().addRemappedFile(
-      FileName, MemoryBuffer::getMemBuffer(Code).release());
-  const char *Args[] = {Standard.data(), FileName.data()};
+  std::vector<const char *> Args = {Standard.data(), FileName.data()};
   CompilerInvocation::CreateFromArgs(*Invocation, Args,
                                      Compiler.getDiagnostics());
   Compiler.setInvocation(std::move(Invocation));
@@ -61,6 +74,19 @@ bool compileFromString(StringRef Code, StringRef Standard, StringRef FileName) {
   return Compiler.ExecuteAction(Action);
 }
 
+std::string GetMetadata(json::Object *Event) {
+  std::string Metadata = "";
+  if (json::Object *Args = Event->getObject("args")) {
+    if (StringRef Detail = Args->getString("detail").value_or("");
+        !Detail.empty())
+      Metadata += Detail.str();
+    if (StringRef File = Args->getString("filename").value_or("");
+        !File.empty())
+      Metadata += ", " + File.str();
+  }
+  return Metadata;
+}
+
 // Returns pretty-printed trace graph.
 std::string buildTraceGraph(StringRef Json) {
   struct EventRecord {
@@ -75,6 +101,7 @@ std::string buildTraceGraph(StringRef Json) {
   Expected<json::Value> Root = json::parse(Json);
   if (!Root)
     return "";
+  std::stack<json::Object *> SourceEvents;
   for (json::Value &TraceEventValue :
        *Root->getAsObject()->getArray("traceEvents")) {
     json::Object *TraceEventObj = TraceEventValue.getAsObject();
@@ -83,14 +110,20 @@ std::string buildTraceGraph(StringRef Json) {
     int64_t TimestampEnd =
         TimestampBegin + TraceEventObj->getInteger("dur").value_or(0);
     std::string Name = TraceEventObj->getString("name").value_or("").str();
-    std::string Metadata = "";
-    if (json::Object *Args = TraceEventObj->getObject("args")) {
-      if (StringRef Detail = Args->getString("detail").value_or("");
-          !Detail.empty())
-        Metadata += Detail.str();
-      if (StringRef File = Args->getString("filename").value_or("");
-          !File.empty())
-        Metadata += ", " + File.str();
+    std::string Metadata = GetMetadata(TraceEventObj);
+
+    if (Name == "Source") {
+      if (TraceEventObj->getString("ph").value_or("") == "b") {
+        SourceEvents.push(TraceEventObj);
+      } else {
+        json::Object *SourceBegin = SourceEvents.top();
+        SourceEvents.pop();
+        Events.emplace_back(
+            EventRecord{SourceBegin->getInteger("ts").value_or(0),
+                        /*TimestampEnd=*/TimestampBegin, "Source",
+                        GetMetadata(SourceBegin)});
+      }
+      continue;
     }
 
     // This is a "summary" event, like "Total PerformPendingInstantiations",
@@ -111,8 +144,10 @@ std::string buildTraceGraph(StringRef Json) {
   std::reverse(Events.begin(), Events.end());
   std::stable_sort(
       Events.begin(), Events.end(), [](const auto &lhs, const auto &rhs) {
-        return std::make_pair(lhs.TimestampBegin, -lhs.TimestampEnd) <
-               std::make_pair(rhs.TimestampBegin, -rhs.TimestampEnd);
+        return std::make_tuple(lhs.TimestampBegin, -lhs.TimestampEnd,
+                               lhs.Name != "Source") <
+               std::make_tuple(rhs.TimestampBegin, -rhs.TimestampEnd,
+                               rhs.Name != "Source");
       });
 
   std::stringstream Stream;
@@ -177,10 +212,6 @@ int slow_arr[12 + 34 * 56 +                                  // 22nd line
              static_cast<int>(slow_namespace::slow_func())]; // 23rd line
 
 constexpr int slow_init_list[] = {1, 1, 2, 3, 5, 8, 13, 21}; // 25th line
-
-template <typename T>
-void foo(T) {}
-void bar() { foo(0); }
     )";
 
   setupProfiler();
@@ -211,11 +242,51 @@ Frontend
 | | EvaluateAsRValue (<test.cc:22:14, line:23:58>)
 | ParseDeclarationOrFunctionDefinition (test.cc:25:1)
 | | EvaluateAsInitializer (slow_init_list)
-| ParseFunctionDefinition (foo)
-| ParseDeclarationOrFunctionDefinition (test.cc:29:1)
-| | ParseFunctionDefinition (bar)
 | PerformPendingInstantiations
-| | InstantiateFunction (foo<int>, test.cc)
+)",
+            buildTraceGraph(Json));
+}
+
+TEST(TimeProfilerTest, TemplateInstantiations) {
+  constexpr StringRef B_H = R"(
+    template <typename T> 
+    T fooB(T t) { 
+      return T();
+    }
+
+    #define MacroTemp(x) template <typename T> void foo##x(T) { T(); }
+  )";
+
+  constexpr StringRef A_H = R"(
+    #include "b.h"
+
+    MacroTemp(MTA)
+
+    template <typename T>
+    void fooA(T t) { fooB(t); fooMTA(t); }
+  )";
+  constexpr StringRef Code = R"(
+    #include "a.h"
+    void user() { fooA(0); }
+  )";
+
+  setupProfiler();
+  ASSERT_TRUE(compileFromString(Code, "-std=c++20", "test.cc",
+                                /*Headers=*/{{"a.h", A_H}, {"b.h", B_H}}));
+  std::string Json = teardownProfiler();
+  ASSERT_EQ(R"(
+Frontend
+| Source (./a.h)
+| | Source (./b.h)
+| | ParseFunctionDefinition (fooB)
+| | ParseFunctionDefinition (fooMTA)
+| ParseFunctionDefinition (fooA)
+| ParseDeclarationOrFunctionDefinition (test.cc:3:5)
+| | ParseFunctionDefinition (user)
+| PerformPendingInstantiations
+| | InstantiateFunction (fooA<int>, ./a.h)
+| | | InstantiateFunction (fooB<int>, ./b.h)
+| | | InstantiateFunction (fooMTA<int>, ./a.h)
 )",
             buildTraceGraph(Json));
 }
@@ -230,15 +301,12 @@ struct {
   setupProfiler();
   ASSERT_TRUE(compileFromString(Code, "-std=c99", "test.c"));
   std::string Json = teardownProfiler();
-  std::string TraceGraph = buildTraceGraph(Json);
-  ASSERT_TRUE(TraceGraph == R"(
+  ASSERT_EQ(R"(
 Frontend
 | ParseDeclarationOrFunctionDefinition (test.c:2:1)
 | | isIntegerConstantExpr (<test.c:3:18>)
 | | EvaluateKnownConstIntCheckOverflow (<test.c:3:18>)
 | PerformPendingInstantiations
-)");
-
-  // NOTE: If this test is failing, run this test with
-  // `llvm::errs() << TraceGraph;` and change the assert above.
+)",
+            buildTraceGraph(Json));
 }

>From 11efd73bf5661ef419ac423be458ba3287d168ae Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Wed, 17 Jul 2024 19:22:41 +0000
Subject: [PATCH 10/14] add line number

---
 a-abfdec1d.o.tmp                              |  0
 clang/include/clang/Driver/Options.td         |  2 +-
 .../include/clang/Frontend/FrontendOptions.h  |  2 +-
 clang/lib/Sema/SemaTemplateInstantiate.cpp    |  8 +++---
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |  8 +++---
 clang/test/Driver/ftime-trace-sections.py     |  4 ---
 clang/unittests/Support/TimeProfilerTest.cpp  | 27 ++++++++++---------
 llvm/include/llvm/Support/TimeProfiler.h      |  7 ++---
 llvm/lib/Support/TimeProfiler.cpp             |  8 +++---
 9 files changed, 35 insertions(+), 31 deletions(-)
 create mode 100644 a-abfdec1d.o.tmp

diff --git a/a-abfdec1d.o.tmp b/a-abfdec1d.o.tmp
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 7d6e0bf01823b..bc5d7d63461bf 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -3987,7 +3987,7 @@ def ftime_trace_granularity_EQ : Joined<["-"], "ftime-trace-granularity=">, Grou
   Visibility<[ClangOption, CC1Option, CLOption, DXCOption]>,
   MarshallingInfoInt<FrontendOpts<"TimeTraceGranularity">, "500u">;
 def ftime_trace_verbose : Joined<["-"], "ftime-trace-verbose">, Group<f_Group>,
-  HelpText<"Make time trace capture verbose event details (eg. source filenames). This can increase the size of the output by 2-3 times">,
+  HelpText<"Make time trace capture verbose event details (e.g. source filenames). This can increase the size of the output by 2-3 times">,
   Visibility<[ClangOption, CC1Option, CLOption, DXCOption]>,
   MarshallingInfoFlag<FrontendOpts<"TimeTraceVerbose">>;
 def ftime_trace_EQ : Joined<["-"], "ftime-trace=">, Group<f_Group>,
diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h
index cafacb8e54af7..9be001e752bee 100644
--- a/clang/include/clang/Frontend/FrontendOptions.h
+++ b/clang/include/clang/Frontend/FrontendOptions.h
@@ -580,7 +580,7 @@ class FrontendOptions {
   /// Minimum time granularity (in microseconds) traced by time profiler.
   unsigned TimeTraceGranularity;
 
-  /// Make time trace capture verbose event details (eg. source filenames). This
+  /// Make time trace capture verbose event details (e.g. source filenames). This
   /// can increase the size of the output by 2-3 times.
   LLVM_PREFERRED_TYPE(bool)
   unsigned TimeTraceVerbose : 1;
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index bb8933277a5d0..725b62db5e80a 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -3430,9 +3430,11 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
     llvm::raw_string_ostream OS(M.Detail);
     Instantiation->getNameForDiagnostic(OS, getPrintingPolicy(),
                                         /*Qualified=*/true);
-    if (llvm::isTimeTraceVerbose())
-      M.Filename = SourceMgr.getFilename(
-          SourceMgr.getExpansionLoc(Instantiation->getLocation()));
+    if (llvm::isTimeTraceVerbose()) {
+      auto Loc = SourceMgr.getExpansionLoc(Instantiation->getLocation());
+      M.File = SourceMgr.getFilename(Loc);
+      M.Line = SourceMgr.getExpansionLineNumber(Loc);
+    }
     return M;
   });
 
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 72fa2cb7b0315..4e619f4b491a6 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4970,9 +4970,11 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
     llvm::raw_string_ostream OS(M.Detail);
     Function->getNameForDiagnostic(OS, getPrintingPolicy(),
                                    /*Qualified=*/true);
-    if (llvm::isTimeTraceVerbose())
-      M.Filename = SourceMgr.getFilename(
-          SourceMgr.getExpansionLoc(Function->getLocation()));
+    if (llvm::isTimeTraceVerbose()) {
+      auto Loc = SourceMgr.getExpansionLoc(Function->getLocation());
+      M.File = SourceMgr.getFilename(Loc);
+      M.Line = SourceMgr.getExpansionLineNumber(Loc);
+    }
     return M;
   });
 
diff --git a/clang/test/Driver/ftime-trace-sections.py b/clang/test/Driver/ftime-trace-sections.py
index a5ed2de1239b3..b332931d29a62 100755
--- a/clang/test/Driver/ftime-trace-sections.py
+++ b/clang/test/Driver/ftime-trace-sections.py
@@ -59,7 +59,3 @@ def is_before(range1, range2):
     sys.exit("Missing CodeGen entry for foo!")
 if not any(e for e in opts if "foo<int>" in e["args"]["detail"]):
     sys.exit("Missing Optimize entry for foo!")
-
-for i in instants:
-    if not i["args"]["filename"].endswith(".cpp"):
-        sys.exit("No filename in instantiation: " + str(i))
\ No newline at end of file
diff --git a/clang/unittests/Support/TimeProfilerTest.cpp b/clang/unittests/Support/TimeProfilerTest.cpp
index 083e6a791f3e0..5bd41f821cfff 100644
--- a/clang/unittests/Support/TimeProfilerTest.cpp
+++ b/clang/unittests/Support/TimeProfilerTest.cpp
@@ -42,14 +42,14 @@ std::string teardownProfiler() {
 
 // Returns true if code compiles successfully.
 // We only parse AST here. This is enough for constexpr evaluation.
-bool compileFromString(StringRef Code, StringRef Standard, StringRef FileName,
+bool compileFromString(StringRef Code, StringRef Standard, StringRef File,
                        llvm::StringMap<StringRef> Headers = {}) {
   CompilerInstance Compiler;
   Compiler.createDiagnostics();
 
   llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS(
       new llvm::vfs::InMemoryFileSystem());
-  FS->addFile(FileName, 0, MemoryBuffer::getMemBuffer(Code));
+  FS->addFile(File, 0, MemoryBuffer::getMemBuffer(Code));
   for (const auto &Header : Headers) {
     FS->addFile(Header.getKey(), 0,
                 MemoryBuffer::getMemBuffer(Header.getValue()));
@@ -59,7 +59,7 @@ bool compileFromString(StringRef Code, StringRef Standard, StringRef FileName,
   Compiler.setFileManager(Files.get());
 
   auto Invocation = std::make_shared<CompilerInvocation>();
-  std::vector<const char *> Args = {Standard.data(), FileName.data()};
+  std::vector<const char *> Args = {Standard.data(), File.data()};
   CompilerInvocation::CreateFromArgs(*Invocation, Args,
                                      Compiler.getDiagnostics());
   Compiler.setInvocation(std::move(Invocation));
@@ -75,14 +75,15 @@ bool compileFromString(StringRef Code, StringRef Standard, StringRef FileName,
 }
 
 std::string GetMetadata(json::Object *Event) {
-  std::string Metadata = "";
+  std::string Metadata;
+  llvm::raw_string_ostream OS(Metadata);
   if (json::Object *Args = Event->getObject("args")) {
-    if (StringRef Detail = Args->getString("detail").value_or("");
-        !Detail.empty())
-      Metadata += Detail.str();
-    if (StringRef File = Args->getString("filename").value_or("");
-        !File.empty())
-      Metadata += ", " + File.str();
+    if (auto Detail = Args->getString("detail"))
+      OS << Detail->str();
+    if (auto File = Args->getString("file"))
+      OS << ", " << File->str();
+    if (auto Line = Args->getInteger("line"))
+      OS << ":" << *Line;
   }
   return Metadata;
 }
@@ -284,9 +285,9 @@ Frontend
 | ParseDeclarationOrFunctionDefinition (test.cc:3:5)
 | | ParseFunctionDefinition (user)
 | PerformPendingInstantiations
-| | InstantiateFunction (fooA<int>, ./a.h)
-| | | InstantiateFunction (fooB<int>, ./b.h)
-| | | InstantiateFunction (fooMTA<int>, ./a.h)
+| | InstantiateFunction (fooA<int>, ./a.h:7)
+| | | InstantiateFunction (fooB<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 f61aedb3bc37e..6eb92930b36fd 100644
--- a/llvm/include/llvm/Support/TimeProfiler.h
+++ b/llvm/include/llvm/Support/TimeProfiler.h
@@ -85,10 +85,11 @@ class raw_pwrite_stream;
 
 struct TimeTraceMetadata {
   std::string Detail;
-  // Source file information for the event.
-  std::string Filename;
+  // Source file and line number information for the event.
+  std::string File;
+  int Line;
 
-  bool isEmpty() const { return Detail.empty() && Filename.empty(); }
+  bool isEmpty() const { return Detail.empty() && File.empty(); }
 };
 
 struct TimeTraceProfiler;
diff --git a/llvm/lib/Support/TimeProfiler.cpp b/llvm/lib/Support/TimeProfiler.cpp
index ccea04b1940a2..c2014028ddadc 100644
--- a/llvm/lib/Support/TimeProfiler.cpp
+++ b/llvm/lib/Support/TimeProfiler.cpp
@@ -207,8 +207,10 @@ struct llvm::TimeTraceProfiler {
           J.attributeObject("args", [&] {
             if (!E.Metadata.Detail.empty())
               J.attribute("detail", E.Metadata.Detail);
-            if (!E.Metadata.Filename.empty())
-              J.attribute("filename", E.Metadata.Filename);
+            if (!E.Metadata.File.empty())
+              J.attribute("file", E.Metadata.File);
+            if (E.Metadata.Line > 0)
+              J.attribute("line", E.Metadata.Line);
           });
         }
       });
@@ -332,7 +334,7 @@ struct llvm::TimeTraceProfiler {
   // Minimum time granularity (in microseconds)
   const unsigned TimeTraceGranularity;
 
-  // Make time trace capture verbose event details (eg. source filenames). This
+  // Make time trace capture verbose event details (e.g. source filenames). This
   // can increase the size of the output by 2-3 times.
   const bool TimeTraceVerbose;
 };

>From 18535a8ce4b92bcb7ef694d5deb3164058ca9442 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Wed, 17 Jul 2024 19:23:16 +0000
Subject: [PATCH 11/14] format

---
 clang/include/clang/Frontend/FrontendOptions.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h
index 9be001e752bee..8241925c98476 100644
--- a/clang/include/clang/Frontend/FrontendOptions.h
+++ b/clang/include/clang/Frontend/FrontendOptions.h
@@ -580,8 +580,8 @@ class FrontendOptions {
   /// Minimum time granularity (in microseconds) traced by time profiler.
   unsigned TimeTraceGranularity;
 
-  /// Make time trace capture verbose event details (e.g. source filenames). This
-  /// can increase the size of the output by 2-3 times.
+  /// Make time trace capture verbose event details (e.g. source filenames).
+  /// This can increase the size of the output by 2-3 times.
   LLVM_PREFERRED_TYPE(bool)
   unsigned TimeTraceVerbose : 1;
 

>From f45b09fc0d375eb729f6718a1afb558284637061 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Thu, 18 Jul 2024 08:11:38 +0000
Subject: [PATCH 12/14] remove source events from tests

---
 clang/unittests/Support/TimeProfilerTest.cpp | 27 +++++---------------
 1 file changed, 6 insertions(+), 21 deletions(-)

diff --git a/clang/unittests/Support/TimeProfilerTest.cpp b/clang/unittests/Support/TimeProfilerTest.cpp
index 5bd41f821cfff..9cfe00c942803 100644
--- a/clang/unittests/Support/TimeProfilerTest.cpp
+++ b/clang/unittests/Support/TimeProfilerTest.cpp
@@ -102,7 +102,6 @@ std::string buildTraceGraph(StringRef Json) {
   Expected<json::Value> Root = json::parse(Json);
   if (!Root)
     return "";
-  std::stack<json::Object *> SourceEvents;
   for (json::Value &TraceEventValue :
        *Root->getAsObject()->getArray("traceEvents")) {
     json::Object *TraceEventObj = TraceEventValue.getAsObject();
@@ -114,16 +113,6 @@ std::string buildTraceGraph(StringRef Json) {
     std::string Metadata = GetMetadata(TraceEventObj);
 
     if (Name == "Source") {
-      if (TraceEventObj->getString("ph").value_or("") == "b") {
-        SourceEvents.push(TraceEventObj);
-      } else {
-        json::Object *SourceBegin = SourceEvents.top();
-        SourceEvents.pop();
-        Events.emplace_back(
-            EventRecord{SourceBegin->getInteger("ts").value_or(0),
-                        /*TimestampEnd=*/TimestampBegin, "Source",
-                        GetMetadata(SourceBegin)});
-      }
       continue;
     }
 
@@ -145,10 +134,8 @@ std::string buildTraceGraph(StringRef Json) {
   std::reverse(Events.begin(), Events.end());
   std::stable_sort(
       Events.begin(), Events.end(), [](const auto &lhs, const auto &rhs) {
-        return std::make_tuple(lhs.TimestampBegin, -lhs.TimestampEnd,
-                               lhs.Name != "Source") <
-               std::make_tuple(rhs.TimestampBegin, -rhs.TimestampEnd,
-                               rhs.Name != "Source");
+        return std::make_pair(lhs.TimestampBegin, -lhs.TimestampEnd) <
+               std::make_pair(rhs.TimestampBegin, -rhs.TimestampEnd);
       });
 
   std::stringstream Stream;
@@ -250,8 +237,8 @@ Frontend
 
 TEST(TimeProfilerTest, TemplateInstantiations) {
   constexpr StringRef B_H = R"(
-    template <typename T> 
-    T fooB(T t) { 
+    template <typename T>
+    T fooB(T t) {
       return T();
     }
 
@@ -277,10 +264,8 @@ TEST(TimeProfilerTest, TemplateInstantiations) {
   std::string Json = teardownProfiler();
   ASSERT_EQ(R"(
 Frontend
-| Source (./a.h)
-| | Source (./b.h)
-| | ParseFunctionDefinition (fooB)
-| | ParseFunctionDefinition (fooMTA)
+| ParseFunctionDefinition (fooB)
+| ParseFunctionDefinition (fooMTA)
 | ParseFunctionDefinition (fooA)
 | ParseDeclarationOrFunctionDefinition (test.cc:3:5)
 | | ParseFunctionDefinition (user)

>From 5e0be5fb26790c9bd3ca1e14e7c111a7a3b03309 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Thu, 18 Jul 2024 08:25:14 +0000
Subject: [PATCH 13/14] use std::string instead of StringRef in tests

---
 clang/unittests/Support/TimeProfilerTest.cpp | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/clang/unittests/Support/TimeProfilerTest.cpp b/clang/unittests/Support/TimeProfilerTest.cpp
index 9cfe00c942803..140ddaa4d96f6 100644
--- a/clang/unittests/Support/TimeProfilerTest.cpp
+++ b/clang/unittests/Support/TimeProfilerTest.cpp
@@ -43,7 +43,7 @@ std::string teardownProfiler() {
 // Returns true if code compiles successfully.
 // We only parse AST here. This is enough for constexpr evaluation.
 bool compileFromString(StringRef Code, StringRef Standard, StringRef File,
-                       llvm::StringMap<StringRef> Headers = {}) {
+                       llvm::StringMap<std::string> Headers = {}) {
   CompilerInstance Compiler;
   Compiler.createDiagnostics();
 
@@ -175,7 +175,7 @@ std::string buildTraceGraph(StringRef Json) {
 } // namespace
 
 TEST(TimeProfilerTest, ConstantEvaluationCxx20) {
-  constexpr StringRef Code = R"(
+  std::string Code = R"(
 void print(double value);
 
 namespace slow_namespace {
@@ -236,7 +236,7 @@ Frontend
 }
 
 TEST(TimeProfilerTest, TemplateInstantiations) {
-  constexpr StringRef B_H = R"(
+  std::string B_H = R"(
     template <typename T>
     T fooB(T t) {
       return T();
@@ -245,7 +245,7 @@ TEST(TimeProfilerTest, TemplateInstantiations) {
     #define MacroTemp(x) template <typename T> void foo##x(T) { T(); }
   )";
 
-  constexpr StringRef A_H = R"(
+  std::string A_H = R"(
     #include "b.h"
 
     MacroTemp(MTA)
@@ -253,7 +253,7 @@ TEST(TimeProfilerTest, TemplateInstantiations) {
     template <typename T>
     void fooA(T t) { fooB(t); fooMTA(t); }
   )";
-  constexpr StringRef Code = R"(
+  std::string Code = R"(
     #include "a.h"
     void user() { fooA(0); }
   )";
@@ -278,7 +278,7 @@ Frontend
 }
 
 TEST(TimeProfilerTest, ConstantEvaluationC99) {
-  constexpr StringRef Code = R"(
+  std::string Code = R"(
 struct {
   short quantval[4]; // 3rd line
 } value;

>From a963585c8698466e9c98bd7ebad2c15eda7bc0a6 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Thu, 18 Jul 2024 14:03:17 +0000
Subject: [PATCH 14/14] add comment for omitting source events

---
 clang/unittests/Support/TimeProfilerTest.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/clang/unittests/Support/TimeProfilerTest.cpp b/clang/unittests/Support/TimeProfilerTest.cpp
index 140ddaa4d96f6..29794017ec0be 100644
--- a/clang/unittests/Support/TimeProfilerTest.cpp
+++ b/clang/unittests/Support/TimeProfilerTest.cpp
@@ -112,9 +112,10 @@ std::string buildTraceGraph(StringRef Json) {
     std::string Name = TraceEventObj->getString("name").value_or("").str();
     std::string Metadata = GetMetadata(TraceEventObj);
 
-    if (Name == "Source") {
+    // Skip source events as they are asynchronous events and may not perfectly
+    // nest the synchronous events.
+    if (Name == "Source")
       continue;
-    }
 
     // This is a "summary" event, like "Total PerformPendingInstantiations",
     // skip it



More information about the cfe-commits mailing list