From f5f86be1d40f30b3183ec148f443afa73d0cbe15 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Fri, 31 Jan 2020 18:58:28 -0500 Subject: [PATCH] Add support for enabling the LLVM time-trace feature I found this helpful while investigating an LLVM performance issue. Passing `-Z llvm-time-trace` causes a `llvm_timings.json` file to be created. This file can be inspected in either the Chrome Profiler tools or with any other compatible tool like SpeedScope. More information on the LLVM feature: - https://aras-p.info/blog/2019/01/16/time-trace-timeline-flame-chart-profiler-for-Clang/ - https://reviews.llvm.org/rL357340 --- src/librustc_codegen_llvm/lib.rs | 6 ++++++ src/librustc_codegen_llvm/llvm/ffi.rs | 4 ++++ src/librustc_codegen_llvm/llvm_util.rs | 18 ++++++++++++++++++ src/librustc_session/options.rs | 2 ++ src/rustllvm/PassWrapper.cpp | 18 ++++++++++++++++++ 5 files changed, 48 insertions(+) diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index 70e3874035b60..60771d385aea5 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -332,6 +332,12 @@ impl CodegenBackend for LlvmCodegenBackend { // any more, we can finalize it (which involves renaming it) rustc_incremental::finalize_session_directory(sess, codegen_results.crate_hash); + sess.time("llvm_dump_timing_file", || { + if sess.opts.debugging_opts.llvm_time_trace { + llvm_util::time_trace_profiler_finish("llvm_timings.json"); + } + }); + Ok(()) } } diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs index 875b2c47b3b36..3f37f86676c98 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/src/librustc_codegen_llvm/llvm/ffi.rs @@ -1454,6 +1454,10 @@ extern "C" { pub fn LLVMInitializePasses(); + pub fn LLVMTimeTraceProfilerInitialize(); + + pub fn LLVMTimeTraceProfilerFinish(FileName: *const c_char); + pub fn LLVMAddAnalysisPasses(T: &'a TargetMachine, PM: &PassManager<'a>); pub fn LLVMPassManagerBuilderCreate() -> &'static mut PassManagerBuilder; diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs index 4823fe10c463f..6d3498f8b800b 100644 --- a/src/librustc_codegen_llvm/llvm_util.rs +++ b/src/librustc_codegen_llvm/llvm_util.rs @@ -113,6 +113,15 @@ unsafe fn configure_llvm(sess: &Session) { } } + if sess.opts.debugging_opts.llvm_time_trace && get_major_version() >= 9 { + // time-trace is not thread safe and running it in parallel will cause seg faults. + if !sess.opts.debugging_opts.no_parallel_llvm { + bug!("`-Z llvm-time-trace` requires `-Z no-parallel-llvm") + } + + llvm::LLVMTimeTraceProfilerInitialize(); + } + llvm::LLVMInitializePasses(); ::rustc_llvm::initialize_available_targets(); @@ -120,6 +129,15 @@ unsafe fn configure_llvm(sess: &Session) { llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int, llvm_args.as_ptr()); } +pub fn time_trace_profiler_finish(file_name: &str) { + unsafe { + if get_major_version() >= 9 { + let file_name = CString::new(file_name).unwrap(); + llvm::LLVMTimeTraceProfilerFinish(file_name.as_ptr()); + } + } +} + // WARNING: the features after applying `to_llvm_feature` must be known // to LLVM or the feature detection code will walk past the end of the feature // array, leading to crashes. diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs index 34da2188a51d2..a18b6eb4402fb 100644 --- a/src/librustc_session/options.rs +++ b/src/librustc_session/options.rs @@ -718,6 +718,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "measure time of rustc processes"), time_llvm_passes: bool = (false, parse_bool, [UNTRACKED], "measure time of each LLVM pass"), + llvm_time_trace: bool = (false, parse_bool, [UNTRACKED], + "generate JSON tracing data file from LLVM data"), input_stats: bool = (false, parse_bool, [UNTRACKED], "gather statistics about the input"), asm_comments: bool = (false, parse_bool, [TRACKED], diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index fad703698075d..4ac7e0e6e1fc0 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -26,6 +26,7 @@ #include "llvm/Transforms/Instrumentation.h" #if LLVM_VERSION_GE(9, 0) #include "llvm/Transforms/Instrumentation/AddressSanitizer.h" +#include "llvm/Support/TimeProfiler.h" #endif #if LLVM_VERSION_GE(8, 0) #include "llvm/Transforms/Instrumentation/ThreadSanitizer.h" @@ -57,6 +58,23 @@ extern "C" void LLVMInitializePasses() { initializeTarget(Registry); } +extern "C" void LLVMTimeTraceProfilerInitialize() { +#if LLVM_VERSION_GE(9, 0) + timeTraceProfilerInitialize(); +#endif +} + +extern "C" void LLVMTimeTraceProfilerFinish(const char* FileName) { +#if LLVM_VERSION_GE(9, 0) + StringRef FN(FileName); + std::error_code EC; + raw_fd_ostream OS(FN, EC, sys::fs::CD_CreateAlways); + + timeTraceProfilerWrite(OS); + timeTraceProfilerCleanup(); +#endif +} + enum class LLVMRustPassKind { Other, Function,