Commit 83e0a49ba4

Min-Yih Hsu <minyihh@uci.edu>
2021-06-04 09:32:37
llvm: Add support for collecting time trace (#8546)
LLVM time profiler can collect time traces and present them in a hierarchical view. Which breakdowns the time spent in each Pass or even IR unit. The result is also exported into a format that can be easily visualized by the Chrome browser. Currently this features is controlled by the following environment variables: - `ZIG_LLVM_TIME_TRACE_FILE` toggles this feature and specifies the output time trace file. - `ZIG_LLVM_TIME_TRACE_GRANULARITY` controls the time granularity in ms (default to 500).
1 parent 9c08a33
Changed files (1)
src/zig_llvm.cpp
@@ -46,7 +46,9 @@
 #include <llvm/Support/CommandLine.h>
 #include <llvm/Support/Host.h>
 #include <llvm/Support/FileSystem.h>
+#include <llvm/Support/Process.h>
 #include <llvm/Support/TargetParser.h>
+#include <llvm/Support/TimeProfiler.h>
 #include <llvm/Support/Timer.h>
 #include <llvm/Support/raw_ostream.h>
 #include <llvm/Support/TargetRegistry.h>
@@ -187,13 +189,48 @@ unsigned ZigLLVMDataLayoutGetProgramAddressSpace(LLVMTargetDataRef TD) {
     return unwrap(TD)->getProgramAddressSpace();
 }
 
+namespace {
+// LLVM's time profiler can provide a hierarchy view of the time spent
+// in each component. It generates JSON report in Chrome's "Trace Event"
+// format. So the report can be easily visualized by the Chrome browser.
+struct TimeTracerRAII {
+  // Granularity in ms
+  unsigned TimeTraceGranularity;
+  StringRef TimeTraceFile, OutputFilename;
+  bool EnableTimeTrace;
+
+  TimeTracerRAII(StringRef ProgramName, StringRef OF)
+    : TimeTraceGranularity(500U),
+      TimeTraceFile(std::getenv("ZIG_LLVM_TIME_TRACE_FILE")),
+      OutputFilename(OF),
+      EnableTimeTrace(!TimeTraceFile.empty()) {
+    if (EnableTimeTrace) {
+      if (const char *G = std::getenv("ZIG_LLVM_TIME_TRACE_GRANULARITY"))
+        TimeTraceGranularity = (unsigned)std::atoi(G);
+
+      llvm::timeTraceProfilerInitialize(TimeTraceGranularity, ProgramName);
+    }
+  }
+
+  ~TimeTracerRAII() {
+    if (EnableTimeTrace) {
+      if (auto E = llvm::timeTraceProfilerWrite(TimeTraceFile, OutputFilename)) {
+        handleAllErrors(std::move(E), [&](const StringError &SE) {
+          errs() << SE.getMessage() << "\n";
+        });
+        return;
+      }
+      timeTraceProfilerCleanup();
+    }
+  }
+};
+} // end anonymous namespace
+
 bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
         char **error_message, bool is_debug,
         bool is_small, bool time_report, bool tsan, bool lto,
         const char *asm_filename, const char *bin_filename, const char *llvm_ir_filename)
 {
-    // TODO: Maybe we should collect time trace rather than using timer
-    // to get a more hierarchical timeline view
     TimePassesIsEnabled = time_report;
 
     raw_fd_ostream *dest_asm_ptr = nullptr;
@@ -219,6 +256,12 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
     std::unique_ptr<raw_fd_ostream> dest_asm(dest_asm_ptr),
                                     dest_bin(dest_bin_ptr);
 
+    auto PID = sys::Process::getProcessId();
+    std::string ProcName = "zig-";
+    ProcName += std::to_string(PID);
+    TimeTracerRAII TimeTracer(ProcName,
+                              bin_filename? bin_filename : asm_filename);
+
     TargetMachine &target_machine = *reinterpret_cast<TargetMachine*>(targ_machine_ref);
     target_machine.setO0WantsFastISel(true);