anton-afanasyev created this revision.
Herald added subscribers: llvm-commits, cfe-commits, jdoerfert, arphaman, 
mgrang, hiraditya, mgorny, mehdi_amini.
Herald added projects: clang, LLVM.

This is the first part of time tracing system, I have splitted them cause this 
part is mostly written by Aras Pranckevicius except of several minor fixes 
concerning formatting. I'm to commit this in behalf of Aras, we have an 
arrangment with him.
The second part extends this option adding terminal output making no need for 
profiling visualization. I can also add xray support though this need is 
arguable.
The third part is for cleaning up previous attempts of such implementations 
(like https://reviews.llvm.org/D45619, https://reviews.llvm.org/D43578 and 
https://reviews.llvm.org/D47196).

This is taken from GitHub PR: 
https://github.com/aras-p/llvm-project-20170507/pull/2
Here is cfe maillist subject discussion: 
http://lists.llvm.org/pipermail/cfe-dev/2019-January/060836.html


Repository:
  rC Clang

https://reviews.llvm.org/D58675

Files:
  clang/include/clang/Basic/CodeGenOptions.def
  clang/include/clang/Driver/Options.td
  clang/include/clang/Frontend/FrontendOptions.h
  clang/lib/CodeGen/CodeGenModule.cpp
  clang/lib/Driver/ToolChains/Clang.cpp
  clang/lib/Frontend/CompilerInstance.cpp
  clang/lib/Frontend/CompilerInvocation.cpp
  clang/lib/Parse/ParseAST.cpp
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/lib/Parse/ParseTemplate.cpp
  clang/lib/Sema/Sema.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
  clang/lib/Serialization/GlobalModuleIndex.cpp
  clang/tools/driver/cc1_main.cpp
  llvm/lib/IR/LegacyPassManager.cpp
  llvm/lib/Support/CMakeLists.txt
  llvm/lib/Support/TimeProfiler.cpp
  llvm/lib/Support/TimeProfiler.h

Index: llvm/lib/Support/TimeProfiler.h
===================================================================
--- /dev/null
+++ llvm/lib/Support/TimeProfiler.h
@@ -0,0 +1,71 @@
+//===- llvm/Support/TimeProfiler.h - Hierarchical Time Profiler -*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_TIME_PROFILER_H
+#define LLVM_SUPPORT_TIME_PROFILER_H
+
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+
+struct TimeTraceProfiler;
+extern TimeTraceProfiler *TimeTraceProfilerInstance;
+
+/// Initialize the time trace profiler.
+/// This sets up the global \p TimeTraceProfilerInstance
+/// variable to be the profiler instance.
+void TimeTraceProfilerInitialize();
+
+/// Cleanup the time trace profiler, if it was initialized.
+void TimeTraceProfilerCleanup();
+
+/// Is the time trace profiler enabled, i.e. initialized?
+inline bool TimeTraceProfilerEnabled() {
+  return TimeTraceProfilerInstance != nullptr;
+}
+
+/// Write profiling data to output file.
+/// Data produced is JSON, in Chrome "Trace Event" format, see
+/// https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview
+void TimeTraceProfilerWrite(std::unique_ptr<raw_pwrite_stream> &OS);
+
+/// Manually begin a time section, with the given \p name and \p detail.
+/// Profiler copies the string data, so the pointers can be given into
+/// temporaries. Time sections can be hierarchical; every Begin must have a
+/// matching End pair but they can nest.
+void TimeTraceProfilerBegin(const char *name, const char *detail);
+
+/// Manually end the last time section.
+void TimeTraceProfilerEnd();
+
+/// The TimeTraceScope is a helper class to call the begin and end functions.
+/// of the time trace profiler.  When the object is constructed, it
+/// begins the section; and wen it is destroyed, it stops
+/// it.  If the time profiler is not initialized, the overhead
+/// is a single branch.
+struct TimeTraceScope {
+  TimeTraceScope(const char *name, const char *detail) {
+    if (TimeTraceProfilerInstance != nullptr)
+      TimeTraceProfilerBegin(name, detail);
+  }
+  ~TimeTraceScope() {
+    if (TimeTraceProfilerInstance != nullptr)
+      TimeTraceProfilerEnd();
+  }
+};
+
+/// Evaluates expression if time trace profiler is enabled, or passed null when
+/// it is not. Useful to avoid possibly expensive work in creating a string for
+/// profiling, when profiler is not enabled at all.
+#define TIME_TRACE_OR_NULL(expr)                                               \
+  (llvm::TimeTraceProfilerInstance != nullptr ? (expr) : nullptr)
+
+} // end namespace llvm
+
+#endif
Index: llvm/lib/Support/TimeProfiler.cpp
===================================================================
--- /dev/null
+++ llvm/lib/Support/TimeProfiler.cpp
@@ -0,0 +1,178 @@
+//===-- TimeProfiler.cpp - Hierarchical Time Profiler ---------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file Hierarchical time profiler implementation.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/TimeProfiler.h"
+#include "llvm/Support/FileSystem.h"
+#include <cassert>
+#include <chrono>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+using namespace std::chrono;
+
+namespace llvm {
+
+TimeTraceProfiler *TimeTraceProfilerInstance = nullptr;
+
+static std::string EscapeString(const char *src) {
+  std::string os;
+  while (*src) {
+    char c = *src;
+    switch (c) {
+    case '"':
+    case '\\':
+    case '\b':
+    case '\f':
+    case '\n':
+    case '\r':
+    case '\t':
+      os += '\\';
+      os += c;
+      break;
+    default:
+      if (c >= 32 && c < 126) {
+        os += c;
+      }
+    }
+    ++src;
+  }
+  return os;
+}
+
+typedef duration<steady_clock::rep, steady_clock::period> DurationType;
+typedef std::pair<std::string, DurationType> NameAndDuration;
+
+struct Entry {
+  time_point<steady_clock> Start;
+  DurationType Duration;
+  std::string Name;
+  std::string Detail;
+};
+
+struct TimeTraceProfiler {
+  TimeTraceProfiler() {
+    Stack.reserve(8);
+    Entries.reserve(128);
+    StartTime = steady_clock::now();
+  }
+
+  void Begin(const std::string &name, const std::string &detail) {
+    Entry e = {steady_clock::now(), {}, name, detail};
+    Stack.emplace_back(e);
+  }
+
+  void End() {
+    assert(!Stack.empty() && "Must call Begin first");
+    auto &e = Stack.back();
+    e.Duration = steady_clock::now() - e.Start;
+
+    // only include sections longer than 500us
+    if (duration_cast<microseconds>(e.Duration).count() > 500)
+      Entries.emplace_back(e);
+
+    // 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
+    // templates from within, we only want to add the topmost one. "topmost"
+    // happens to be the ones that don't have any currently open entries above
+    // itself.
+    if (std::find_if(++Stack.rbegin(), Stack.rend(), [&](const Entry &val) {
+          return val.Name == e.Name;
+        }) == Stack.rend()) {
+      TotalPerName[e.Name] += e.Duration;
+      CountPerName[e.Name]++;
+    }
+
+    Stack.pop_back();
+  }
+
+  void Write(std::unique_ptr<raw_pwrite_stream> &os) {
+    assert(Stack.empty() &&
+           "All profiler sections should be ended when calling Write");
+
+    *os << "{ \"traceEvents\": [\n";
+
+    // emit all events for the main flame graph
+    for (const auto &e : Entries) {
+      auto startUs = duration_cast<microseconds>(e.Start - StartTime).count();
+      auto durUs = duration_cast<microseconds>(e.Duration).count();
+      *os << "{ \"pid\":1, \"tid\":0, \"ph\":\"X\", \"ts\":" << startUs
+          << ", \"dur\":" << durUs << ", \"name\":\""
+          << EscapeString(e.Name.c_str()) << "\", \"args\":{ \"detail\":\""
+          << EscapeString(e.Detail.c_str()) << "\"} },\n";
+    }
+
+    // emit totals by section name as additional "thread" events, sorted from
+    // longest one
+    int tid = 1;
+    std::vector<NameAndDuration> sortedTotals;
+    sortedTotals.reserve(TotalPerName.size());
+    for (const auto &e : TotalPerName) {
+      sortedTotals.push_back(e);
+    }
+    std::sort(sortedTotals.begin(), sortedTotals.end(),
+              [](const NameAndDuration &a, const NameAndDuration &b) {
+                return a.second > b.second;
+              });
+    for (const auto &e : sortedTotals) {
+      auto durUs = duration_cast<microseconds>(e.second).count();
+      *os << "{ \"pid\":1, \"tid\":" << tid << ", \"ph\":\"X\", \"ts\":" << 0
+          << ", \"dur\":" << durUs << ", \"name\":\"Total "
+          << EscapeString(e.first.c_str())
+          << "\", \"args\":{ \"count\":" << CountPerName[e.first]
+          << ", \"avg ms\":" << (durUs / CountPerName[e.first] / 1000)
+          << "} },\n";
+      ++tid;
+    }
+
+    // emit metadata event with process name
+    *os << "{ \"cat\":\"\", \"pid\":1, \"tid\":0, \"ts\":0, \"ph\":\"M\", "
+           "\"name\":\"process_name\", \"args\":{ \"name\":\"clang\" } }\n";
+    *os << "] }\n";
+  }
+
+  std::vector<Entry> Stack;
+  std::vector<Entry> Entries;
+  std::unordered_map<std::string, DurationType> TotalPerName;
+  std::unordered_map<std::string, size_t> CountPerName;
+  time_point<steady_clock> StartTime;
+};
+
+void TimeTraceProfilerInitialize() {
+  assert(TimeTraceProfilerInstance == nullptr &&
+         "Profiler should not be initialized");
+  TimeTraceProfilerInstance = new TimeTraceProfiler();
+}
+
+void TimeTraceProfilerCleanup() {
+  delete TimeTraceProfilerInstance;
+  TimeTraceProfilerInstance = nullptr;
+}
+
+void TimeTraceProfilerWrite(std::unique_ptr<raw_pwrite_stream> &OS) {
+  assert(TimeTraceProfilerInstance != nullptr &&
+         "Profiler object can't be null");
+  TimeTraceProfilerInstance->Write(OS);
+}
+
+void TimeTraceProfilerBegin(const char *name, const char *detail) {
+  if (TimeTraceProfilerInstance != nullptr)
+    TimeTraceProfilerInstance->Begin(name, detail);
+}
+
+void TimeTraceProfilerEnd() {
+  if (TimeTraceProfilerInstance != nullptr)
+    TimeTraceProfilerInstance->End();
+}
+
+} // namespace llvm
Index: llvm/lib/Support/CMakeLists.txt
===================================================================
--- llvm/lib/Support/CMakeLists.txt
+++ llvm/lib/Support/CMakeLists.txt
@@ -131,6 +131,7 @@
   TarWriter.cpp
   TargetParser.cpp
   ThreadPool.cpp
+  TimeProfiler.cpp
   Timer.cpp
   ToolOutputFile.cpp
   TrigramIndex.cpp
Index: llvm/lib/IR/LegacyPassManager.cpp
===================================================================
--- llvm/lib/IR/LegacyPassManager.cpp
+++ llvm/lib/IR/LegacyPassManager.cpp
@@ -27,6 +27,7 @@
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/ManagedStatic.h"
 #include "llvm/Support/Mutex.h"
+#include "llvm/Support/TimeProfiler.h"
 #include "llvm/Support/Timer.h"
 #include "llvm/Support/raw_ostream.h"
 #include <algorithm>
@@ -1628,6 +1629,10 @@
     FunctionSize = F.getInstructionCount();
   }
 
+  bool profileTime = llvm::TimeTraceProfilerEnabled();
+  if (profileTime)
+    llvm::TimeTraceProfilerBegin("OptFunction", F.getName().data());
+
   for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) {
     FunctionPass *FP = getContainedPass(Index);
     bool LocalChanged = false;
@@ -1668,12 +1673,17 @@
     recordAvailableAnalysis(FP);
     removeDeadPasses(FP, F.getName(), ON_FUNCTION_MSG);
   }
+
+  if (profileTime)
+    llvm::TimeTraceProfilerEnd();
+
   return Changed;
 }
 
 bool FPPassManager::runOnModule(Module &M) {
   bool Changed = false;
 
+  llvm::TimeTraceScope timeScope("OptModule", M.getName().data());
   for (Function &F : M)
     Changed |= runOnFunction(F);
 
@@ -1706,6 +1716,8 @@
 /// the module, and if so, return true.
 bool
 MPPassManager::runOnModule(Module &M) {
+  llvm::TimeTraceScope timeScope("OptModule", M.getName().data());
+
   bool Changed = false;
 
   // Initialize on-the-fly passes
Index: clang/tools/driver/cc1_main.cpp
===================================================================
--- clang/tools/driver/cc1_main.cpp
+++ clang/tools/driver/cc1_main.cpp
@@ -34,8 +34,10 @@
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Path.h"
 #include "llvm/Support/Signals.h"
 #include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/TimeProfiler.h"
 #include "llvm/Support/Timer.h"
 #include "llvm/Support/raw_ostream.h"
 #include <cstdio>
@@ -194,6 +196,10 @@
   bool Success = CompilerInvocation::CreateFromArgs(
       Clang->getInvocation(), Argv.begin(), Argv.end(), Diags);
 
+  if (Clang->getFrontendOpts().TimeTrace) {
+    llvm::TimeTraceProfilerInitialize();
+  }
+
   // Infer the builtin include path if unspecified.
   if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
       Clang->getHeaderSearchOpts().ResourceDir.empty())
@@ -215,12 +221,29 @@
     return 1;
 
   // Execute the frontend actions.
-  Success = ExecuteCompilerInvocation(Clang.get());
+  {
+    llvm::TimeTraceScope scope("ExecuteCompiler", "");
+    Success = ExecuteCompilerInvocation(Clang.get());
+  }
 
   // If any timers were active but haven't been destroyed yet, print their
   // results now.  This happens in -disable-free mode.
   llvm::TimerGroup::printAll(llvm::errs());
 
+  if (llvm::TimeTraceProfilerEnabled()) {
+    SmallString<128> Path(Clang->getFrontendOpts().OutputFile);
+    llvm::sys::path::replace_extension(Path, "json");
+    auto profilerOutput =
+        Clang->createOutputFile(Path.str(),
+                                /*Binary=*/false,
+                                /*RemoveFileOnSignal=*/false, "",
+                                /*Extension=*/"json",
+                                /*useTemporary=*/false);
+
+    llvm::TimeTraceProfilerWrite(profilerOutput);
+    llvm::TimeTraceProfilerCleanup();
+  }
+
   // Our error handler depends on the Diagnostics object, which we're
   // potentially about to delete. Uninstall the handler now so that any
   // later errors use the default handling behavior instead.
Index: clang/lib/Serialization/GlobalModuleIndex.cpp
===================================================================
--- clang/lib/Serialization/GlobalModuleIndex.cpp
+++ clang/lib/Serialization/GlobalModuleIndex.cpp
@@ -10,11 +10,11 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "clang/Serialization/GlobalModuleIndex.h"
 #include "ASTReaderInternals.h"
 #include "clang/Basic/FileManager.h"
 #include "clang/Lex/HeaderSearch.h"
 #include "clang/Serialization/ASTBitCodes.h"
-#include "clang/Serialization/GlobalModuleIndex.h"
 #include "clang/Serialization/Module.h"
 #include "clang/Serialization/PCHContainerOperations.h"
 #include "llvm/ADT/DenseMap.h"
@@ -28,6 +28,7 @@
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/OnDiskHashTable.h"
 #include "llvm/Support/Path.h"
+#include "llvm/Support/TimeProfiler.h"
 #include <cstdio>
 using namespace clang;
 using namespace serialization;
@@ -126,6 +127,7 @@
                                      llvm::BitstreamCursor Cursor)
     : Buffer(std::move(Buffer)), IdentifierIndex(), NumIdentifierLookups(),
       NumIdentifierLookupHits() {
+  llvm::TimeTraceScope timeScope("Module LoadIndex", "");
   // Read the global index.
   bool InGlobalIndexBlock = false;
   bool Done = false;
@@ -739,6 +741,7 @@
   }
 
   using namespace llvm;
+  llvm::TimeTraceScope timeScope("Module WriteIndex", "");
 
   // Emit the file header.
   Stream.Emit((unsigned)'B', 8);
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -8,7 +8,6 @@
 //  This file implements C++ template instantiation for declarations.
 //
 //===----------------------------------------------------------------------===/
-#include "clang/Sema/SemaInternal.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/ASTMutationListener.h"
@@ -21,8 +20,10 @@
 #include "clang/AST/TypeLoc.h"
 #include "clang/Sema/Initialization.h"
 #include "clang/Sema/Lookup.h"
+#include "clang/Sema/SemaInternal.h"
 #include "clang/Sema/Template.h"
 #include "clang/Sema/TemplateInstCallback.h"
+#include "llvm/Support/TimeProfiler.h"
 
 using namespace clang;
 
@@ -4019,6 +4020,10 @@
     return;
   }
 
+  llvm::TimeTraceScope timeScope(
+      "InstantiateFunction",
+      TIME_TRACE_OR_NULL(Function->getQualifiedNameAsString().c_str()));
+
   // If we're performing recursive template instantiation, create our own
   // queue of pending implicit instantiations that we will instantiate later,
   // while we're still within our own instantiation context.
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -9,7 +9,6 @@
 //
 //===----------------------------------------------------------------------===/
 
-#include "clang/Sema/SemaInternal.h"
 #include "TreeTransform.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
@@ -22,9 +21,11 @@
 #include "clang/Sema/DeclSpec.h"
 #include "clang/Sema/Initialization.h"
 #include "clang/Sema/Lookup.h"
+#include "clang/Sema/SemaInternal.h"
 #include "clang/Sema/Template.h"
 #include "clang/Sema/TemplateDeduction.h"
 #include "clang/Sema/TemplateInstCallback.h"
+#include "llvm/Support/TimeProfiler.h"
 
 using namespace clang;
 using namespace sema;
@@ -2008,6 +2009,11 @@
                                 Instantiation->getInstantiatedFromMemberClass(),
                                      Pattern, PatternDef, TSK, Complain))
     return true;
+
+  llvm::TimeTraceScope timeScope(
+      "InstantiateClass",
+      TIME_TRACE_OR_NULL(Instantiation->getQualifiedNameAsString().c_str()));
+
   Pattern = PatternDef;
 
   // Record the point of instantiation.
Index: clang/lib/Sema/Sema.cpp
===================================================================
--- clang/lib/Sema/Sema.cpp
+++ clang/lib/Sema/Sema.cpp
@@ -39,6 +39,8 @@
 #include "clang/Sema/TemplateInstCallback.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/SmallSet.h"
+#include "llvm/Support/TimeProfiler.h"
+
 using namespace clang;
 using namespace sema;
 
@@ -92,6 +94,12 @@
       SourceManager &SM = S->getSourceManager();
       SourceLocation IncludeLoc = SM.getIncludeLoc(SM.getFileID(Loc));
       if (IncludeLoc.isValid()) {
+        if (llvm::TimeTraceProfilerEnabled()) {
+          auto fe = SM.getFileEntryForID(SM.getFileID(Loc));
+          llvm::TimeTraceProfilerBegin(
+              "Source", fe != nullptr ? fe->getName().data() : "<unknown>");
+        }
+
         IncludeStack.push_back(IncludeLoc);
         S->DiagnoseNonDefaultPragmaPack(
             Sema::PragmaPackDiagnoseKind::NonDefaultStateAtInclude, IncludeLoc);
@@ -99,10 +107,14 @@
       break;
     }
     case ExitFile:
-      if (!IncludeStack.empty())
+      if (!IncludeStack.empty()) {
+        if (llvm::TimeTraceProfilerEnabled()) {
+          llvm::TimeTraceProfilerEnd();
+        }
         S->DiagnoseNonDefaultPragmaPack(
             Sema::PragmaPackDiagnoseKind::ChangedStateAtExit,
             IncludeStack.pop_back_val());
+      }
       break;
     default:
       break;
@@ -914,7 +926,10 @@
                                    Pending.begin(), Pending.end());
     }
 
-    PerformPendingInstantiations();
+    {
+      llvm::TimeTraceScope timeScope("PerformPendingInstantiations", "");
+      PerformPendingInstantiations();
+    }
 
     assert(LateParsedInstantiations.empty() &&
            "end of TU template instantiation should not create more "
Index: clang/lib/Parse/ParseTemplate.cpp
===================================================================
--- clang/lib/Parse/ParseTemplate.cpp
+++ clang/lib/Parse/ParseTemplate.cpp
@@ -18,6 +18,7 @@
 #include "clang/Sema/DeclSpec.h"
 #include "clang/Sema/ParsedTemplate.h"
 #include "clang/Sema/Scope.h"
+#include "llvm/Support/TimeProfiler.h"
 using namespace clang;
 
 /// Parse a template declaration, explicit instantiation, or
@@ -231,6 +232,12 @@
     return nullptr;
   }
 
+  llvm::TimeTraceScope timeScope(
+      "ParseTemplate",
+      TIME_TRACE_OR_NULL(DeclaratorInfo.getIdentifier() != nullptr
+                             ? DeclaratorInfo.getIdentifier()->getName().data()
+                             : "<unknown>"));
+
   LateParsedAttrList LateParsedAttrs(true);
   if (DeclaratorInfo.isFunctionDeclarator())
     MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs);
Index: clang/lib/Parse/ParseDeclCXX.cpp
===================================================================
--- clang/lib/Parse/ParseDeclCXX.cpp
+++ clang/lib/Parse/ParseDeclCXX.cpp
@@ -10,7 +10,6 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/Parse/Parser.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/PrettyDeclStackTrace.h"
@@ -19,11 +18,13 @@
 #include "clang/Basic/OperatorKinds.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Parse/Parser.h"
 #include "clang/Parse/RAIIObjectsForParser.h"
 #include "clang/Sema/DeclSpec.h"
 #include "clang/Sema/ParsedTemplate.h"
 #include "clang/Sema/Scope.h"
 #include "llvm/ADT/SmallString.h"
+#include "llvm/Support/TimeProfiler.h"
 
 using namespace clang;
 
@@ -3109,6 +3110,12 @@
          TagType == DeclSpec::TST_union  ||
          TagType == DeclSpec::TST_class) && "Invalid TagType!");
 
+  llvm::TimeTraceScope timeScope(
+      "ParseClass",
+      TIME_TRACE_OR_NULL(
+          TagDecl != nullptr && isa<NamedDecl>(TagDecl)
+              ? cast<NamedDecl>(TagDecl)->getQualifiedNameAsString().data()
+              : "<anonymous>"));
   PrettyDeclStackTraceEntry CrashInfo(Actions.Context, TagDecl, RecordLoc,
                                       "parsing struct/union/class body");
 
Index: clang/lib/Parse/ParseAST.cpp
===================================================================
--- clang/lib/Parse/ParseAST.cpp
+++ clang/lib/Parse/ParseAST.cpp
@@ -22,6 +22,7 @@
 #include "clang/Sema/SemaConsumer.h"
 #include "clang/Sema/TemplateInstCallback.h"
 #include "llvm/Support/CrashRecoveryContext.h"
+#include "llvm/Support/TimeProfiler.h"
 #include <cstdio>
 #include <memory>
 
@@ -150,6 +151,7 @@
   bool HaveLexer = S.getPreprocessor().getCurrentLexer();
 
   if (HaveLexer) {
+    llvm::TimeTraceScope scope("Frontend", "");
     P.Initialize();
     Parser::DeclGroupPtrTy ADecl;
     for (bool AtEOF = P.ParseFirstTopLevelDecl(ADecl); !AtEOF;
@@ -166,7 +168,10 @@
   for (Decl *D : S.WeakTopLevelDecls())
     Consumer->HandleTopLevelDecl(DeclGroupRef(D));
 
-  Consumer->HandleTranslationUnit(S.getASTContext());
+  {
+    llvm::TimeTraceScope scope("Backend", "");
+    Consumer->HandleTranslationUnit(S.getASTContext());
+  }
 
   // Finalize the template instantiation observer chain.
   // FIXME: This (and init.) should be done in the Sema class, but because
Index: clang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- clang/lib/Frontend/CompilerInvocation.cpp
+++ clang/lib/Frontend/CompilerInvocation.cpp
@@ -1708,6 +1708,7 @@
   Opts.ShowHelp = Args.hasArg(OPT_help);
   Opts.ShowStats = Args.hasArg(OPT_print_stats);
   Opts.ShowTimers = Args.hasArg(OPT_ftime_report);
+  Opts.TimeTrace = Args.hasArg(OPT_ftime_trace);
   Opts.ShowVersion = Args.hasArg(OPT_version);
   Opts.ASTMergeFiles = Args.getAllArgValues(OPT_ast_merge);
   Opts.LLVMArgs = Args.getAllArgValues(OPT_mllvm);
Index: clang/lib/Frontend/CompilerInstance.cpp
===================================================================
--- clang/lib/Frontend/CompilerInstance.cpp
+++ clang/lib/Frontend/CompilerInstance.cpp
@@ -46,6 +46,7 @@
 #include "llvm/Support/Path.h"
 #include "llvm/Support/Program.h"
 #include "llvm/Support/Signals.h"
+#include "llvm/Support/TimeProfiler.h"
 #include "llvm/Support/Timer.h"
 #include "llvm/Support/raw_ostream.h"
 #include <sys/stat.h>
@@ -1033,6 +1034,8 @@
                       [](CompilerInstance &) {},
                   llvm::function_ref<void(CompilerInstance &)> PostBuildStep =
                       [](CompilerInstance &) {}) {
+  llvm::TimeTraceScope timeScope("Module Compile", ModuleName.data());
+
   // Construct a compiler invocation for creating this module.
   auto Invocation =
       std::make_shared<CompilerInvocation>(ImportingInstance.getInvocation());
@@ -1712,6 +1715,7 @@
       Timer.init("loading." + ModuleFileName, "Loading " + ModuleFileName,
                  *FrontendTimerGroup);
     llvm::TimeRegion TimeLoading(FrontendTimerGroup ? &Timer : nullptr);
+    llvm::TimeTraceScope timeScope("Module Load", ModuleName.data());
 
     // Try to load the module file. If we are not trying to load from the
     // module cache, we don't know how to rebuild modules.
Index: clang/lib/Driver/ToolChains/Clang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Clang.cpp
+++ clang/lib/Driver/ToolChains/Clang.cpp
@@ -4515,6 +4515,7 @@
   Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info);
   Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_parseable_fixits);
   Args.AddLastArg(CmdArgs, options::OPT_ftime_report);
+  Args.AddLastArg(CmdArgs, options::OPT_ftime_trace);
   Args.AddLastArg(CmdArgs, options::OPT_ftrapv);
 
   if (Arg *A = Args.getLastArg(options::OPT_ftrapv_handler_EQ)) {
Index: clang/lib/CodeGen/CodeGenModule.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenModule.cpp
+++ clang/lib/CodeGen/CodeGenModule.cpp
@@ -57,6 +57,7 @@
 #include "llvm/Support/ConvertUTF.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/MD5.h"
+#include "llvm/Support/TimeProfiler.h"
 
 using namespace clang;
 using namespace CodeGen;
@@ -2470,6 +2471,10 @@
     if (!shouldEmitFunction(GD))
       return;
 
+    llvm::TimeTraceScope timeScope(
+        "CodeGen Function",
+        TIME_TRACE_OR_NULL(FD->getQualifiedNameAsString().c_str()));
+
     if (const auto *Method = dyn_cast<CXXMethodDecl>(D)) {
       // Make sure to emit the definition(s) before we emit the thunks.
       // This is necessary for the generation of certain thunks.
Index: clang/include/clang/Frontend/FrontendOptions.h
===================================================================
--- clang/include/clang/Frontend/FrontendOptions.h
+++ clang/include/clang/Frontend/FrontendOptions.h
@@ -256,6 +256,9 @@
   /// Show timers for individual actions.
   unsigned ShowTimers : 1;
 
+  /// Output time trace profile.
+  unsigned TimeTrace : 1;
+
   /// Show the -version text.
   unsigned ShowVersion : 1;
 
@@ -437,13 +440,14 @@
 public:
   FrontendOptions()
       : DisableFree(false), RelocatablePCH(false), ShowHelp(false),
-        ShowStats(false), ShowTimers(false), ShowVersion(false),
-        FixWhatYouCan(false), FixOnlyWarnings(false), FixAndRecompile(false),
-        FixToTemporaries(false), ARCMTMigrateEmitARCErrors(false),
-        SkipFunctionBodies(false), UseGlobalModuleIndex(true),
-        GenerateGlobalModuleIndex(true), ASTDumpDecls(false),
-        ASTDumpLookups(false), BuildingImplicitModule(false),
-        ModulesEmbedAllFiles(false), IncludeTimestamps(true) {}
+        ShowStats(false), ShowTimers(false), TimeTrace(false),
+        ShowVersion(false), FixWhatYouCan(false), FixOnlyWarnings(false),
+        FixAndRecompile(false), FixToTemporaries(false),
+        ARCMTMigrateEmitARCErrors(false), SkipFunctionBodies(false),
+        UseGlobalModuleIndex(true), GenerateGlobalModuleIndex(true),
+        ASTDumpDecls(false), ASTDumpLookups(false),
+        BuildingImplicitModule(false), ModulesEmbedAllFiles(false),
+        IncludeTimestamps(true) {}
 
   /// getInputKindForExtension - Return the appropriate input kind for a file
   /// extension. For example, "c" would return InputKind::C.
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -1730,6 +1730,7 @@
 def : Flag<["-"], "fterminated-vtables">, Alias<fapple_kext>;
 def fthreadsafe_statics : Flag<["-"], "fthreadsafe-statics">, Group<f_Group>;
 def ftime_report : Flag<["-"], "ftime-report">, Group<f_Group>, Flags<[CC1Option]>;
+def ftime_trace : Flag<["-"], "ftime-trace">, Group<f_Group>, Flags<[CC1Option]>;
 def ftlsmodel_EQ : Joined<["-"], "ftls-model=">, Group<f_Group>, Flags<[CC1Option]>;
 def ftrapv : Flag<["-"], "ftrapv">, Group<f_Group>, Flags<[CC1Option]>,
   HelpText<"Trap on integer overflow">;
Index: clang/include/clang/Basic/CodeGenOptions.def
===================================================================
--- clang/include/clang/Basic/CodeGenOptions.def
+++ clang/include/clang/Basic/CodeGenOptions.def
@@ -224,6 +224,7 @@
 CODEGENOPT(StrictEnums       , 1, 0) ///< Optimize based on strict enum definition.
 CODEGENOPT(StrictVTablePointers, 1, 0) ///< Optimize based on the strict vtable pointers
 CODEGENOPT(TimePasses        , 1, 0) ///< Set when -ftime-report is enabled.
+CODEGENOPT(TimeTrace         , 1, 0) ///< Set when -ftime-trace is enabled.
 CODEGENOPT(UnrollLoops       , 1, 0) ///< Control whether loops are unrolled.
 CODEGENOPT(RerollLoops       , 1, 0) ///< Control whether loops are rerolled.
 CODEGENOPT(NoUseJumpTables   , 1, 0) ///< Set when -fno-jump-tables is enabled.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to