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
This commit is contained in:
Wesley Wiser 2020-01-31 18:58:28 -05:00
parent cd1ef390e7
commit f5f86be1d4
5 changed files with 48 additions and 0 deletions

View file

@ -332,6 +332,12 @@ impl CodegenBackend for LlvmCodegenBackend {
// any more, we can finalize it (which involves renaming it) // any more, we can finalize it (which involves renaming it)
rustc_incremental::finalize_session_directory(sess, codegen_results.crate_hash); 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(()) Ok(())
} }
} }

View file

@ -1454,6 +1454,10 @@ extern "C" {
pub fn LLVMInitializePasses(); pub fn LLVMInitializePasses();
pub fn LLVMTimeTraceProfilerInitialize();
pub fn LLVMTimeTraceProfilerFinish(FileName: *const c_char);
pub fn LLVMAddAnalysisPasses(T: &'a TargetMachine, PM: &PassManager<'a>); pub fn LLVMAddAnalysisPasses(T: &'a TargetMachine, PM: &PassManager<'a>);
pub fn LLVMPassManagerBuilderCreate() -> &'static mut PassManagerBuilder; pub fn LLVMPassManagerBuilderCreate() -> &'static mut PassManagerBuilder;

View file

@ -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(); llvm::LLVMInitializePasses();
::rustc_llvm::initialize_available_targets(); ::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()); 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 // 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 // to LLVM or the feature detection code will walk past the end of the feature
// array, leading to crashes. // array, leading to crashes.

View file

@ -718,6 +718,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"measure time of rustc processes"), "measure time of rustc processes"),
time_llvm_passes: bool = (false, parse_bool, [UNTRACKED], time_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
"measure time of each LLVM pass"), "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], input_stats: bool = (false, parse_bool, [UNTRACKED],
"gather statistics about the input"), "gather statistics about the input"),
asm_comments: bool = (false, parse_bool, [TRACKED], asm_comments: bool = (false, parse_bool, [TRACKED],

View file

@ -26,6 +26,7 @@
#include "llvm/Transforms/Instrumentation.h" #include "llvm/Transforms/Instrumentation.h"
#if LLVM_VERSION_GE(9, 0) #if LLVM_VERSION_GE(9, 0)
#include "llvm/Transforms/Instrumentation/AddressSanitizer.h" #include "llvm/Transforms/Instrumentation/AddressSanitizer.h"
#include "llvm/Support/TimeProfiler.h"
#endif #endif
#if LLVM_VERSION_GE(8, 0) #if LLVM_VERSION_GE(8, 0)
#include "llvm/Transforms/Instrumentation/ThreadSanitizer.h" #include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
@ -57,6 +58,23 @@ extern "C" void LLVMInitializePasses() {
initializeTarget(Registry); 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 { enum class LLVMRustPassKind {
Other, Other,
Function, Function,