Skip to content

Commit 5d04ce6

Browse files
committed
Auto merge of #68406 - andjo403:selfprofileLlvm, r=wesleywiser
[self-profiler] add selfprofiling to llvm using pass name as event id and add additional data with name of module, function … ![image](https://user-images.githubusercontent.com/844398/72761970-205d8600-3bde-11ea-86de-87386e127944.png) r? @michaelwoerister or @wesleywiser
2 parents d538b80 + cec0ed0 commit 5d04ce6

File tree

10 files changed

+165
-4
lines changed

10 files changed

+165
-4
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -3559,6 +3559,7 @@ dependencies = [
35593559
"flate2",
35603560
"libc",
35613561
"log",
3562+
"measureme",
35623563
"rustc",
35633564
"rustc-demangle",
35643565
"rustc_attr",

src/librustc_codegen_llvm/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ doctest = false
1414
bitflags = "1.0"
1515
flate2 = "1.0"
1616
libc = "0.2"
17+
measureme = "0.7.1"
1718
log = "0.4"
1819
rustc = { path = "../librustc" }
1920
rustc-demangle = "0.1"

src/librustc_codegen_llvm/back/lto.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,7 @@ pub(crate) fn run_pass_manager(
593593
} else {
594594
opt_level
595595
};
596-
write::optimize_with_new_llvm_pass_manager(module, config, opt_level, opt_stage);
596+
write::optimize_with_new_llvm_pass_manager(cgcx, module, config, opt_level, opt_stage);
597597
debug!("lto done");
598598
return;
599599
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
use measureme::{event_id::SEPARATOR_BYTE, EventId, StringComponent, StringId};
2+
use rustc_data_structures::profiling::{SelfProfiler, TimingGuard};
3+
use std::ffi::{c_void, CStr};
4+
use std::os::raw::c_char;
5+
use std::sync::Arc;
6+
7+
fn llvm_args_to_string_id(profiler: &SelfProfiler, pass_name: &str, ir_name: &str) -> EventId {
8+
let pass_name = profiler.get_or_alloc_cached_string(pass_name);
9+
let mut components = vec![StringComponent::Ref(pass_name)];
10+
// handle that LazyCallGraph::SCC is a comma separated list within parentheses
11+
let parentheses: &[_] = &['(', ')'];
12+
let trimed = ir_name.trim_matches(parentheses);
13+
for part in trimed.split(", ") {
14+
let demangled_ir_name = rustc_demangle::demangle(part).to_string();
15+
let ir_name = profiler.get_or_alloc_cached_string(demangled_ir_name);
16+
components.push(StringComponent::Value(SEPARATOR_BYTE));
17+
components.push(StringComponent::Ref(ir_name));
18+
}
19+
EventId::from_label(profiler.alloc_string(components.as_slice()))
20+
}
21+
22+
pub struct LlvmSelfProfiler<'a> {
23+
profiler: Arc<SelfProfiler>,
24+
stack: Vec<TimingGuard<'a>>,
25+
llvm_pass_event_kind: StringId,
26+
}
27+
28+
impl<'a> LlvmSelfProfiler<'a> {
29+
pub fn new(profiler: Arc<SelfProfiler>) -> Self {
30+
let llvm_pass_event_kind = profiler.alloc_string("LLVM Pass");
31+
Self { profiler, stack: Vec::default(), llvm_pass_event_kind }
32+
}
33+
34+
fn before_pass_callback(&'a mut self, pass_name: &str, ir_name: &str) {
35+
let event_id = llvm_args_to_string_id(&self.profiler, pass_name, ir_name);
36+
37+
self.stack.push(TimingGuard::start(&self.profiler, self.llvm_pass_event_kind, event_id));
38+
}
39+
fn after_pass_callback(&mut self) {
40+
self.stack.pop();
41+
}
42+
}
43+
44+
pub unsafe extern "C" fn selfprofile_before_pass_callback(
45+
llvm_self_profiler: *mut c_void,
46+
pass_name: *const c_char,
47+
ir_name: *const c_char,
48+
) {
49+
let llvm_self_profiler = &mut *(llvm_self_profiler as *mut LlvmSelfProfiler<'_>);
50+
let pass_name = CStr::from_ptr(pass_name).to_str().expect("valid UTF-8");
51+
let ir_name = CStr::from_ptr(ir_name).to_str().expect("valid UTF-8");
52+
llvm_self_profiler.before_pass_callback(pass_name, ir_name);
53+
}
54+
55+
pub unsafe extern "C" fn selfprofile_after_pass_callback(llvm_self_profiler: *mut c_void) {
56+
let llvm_self_profiler = &mut *(llvm_self_profiler as *mut LlvmSelfProfiler<'_>);
57+
llvm_self_profiler.after_pass_callback();
58+
}

src/librustc_codegen_llvm/back/write.rs

+20-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
use crate::attributes;
22
use crate::back::bytecode;
33
use crate::back::lto::ThinBuffer;
4+
use crate::back::profiling::{
5+
selfprofile_after_pass_callback, selfprofile_before_pass_callback, LlvmSelfProfiler,
6+
};
47
use crate::base;
58
use crate::common;
69
use crate::consts;
@@ -348,6 +351,7 @@ pub(crate) fn should_use_new_llvm_pass_manager(config: &ModuleConfig) -> bool {
348351
}
349352

350353
pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
354+
cgcx: &CodegenContext<LlvmCodegenBackend>,
351355
module: &ModuleCodegen<ModuleLlvm>,
352356
config: &ModuleConfig,
353357
opt_level: config::OptLevel,
@@ -372,6 +376,13 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
372376
None
373377
};
374378

379+
let llvm_selfprofiler = if cgcx.prof.llvm_recording_enabled() {
380+
let mut llvm_profiler = LlvmSelfProfiler::new(cgcx.prof.get_self_profiler().unwrap());
381+
&mut llvm_profiler as *mut _ as *mut c_void
382+
} else {
383+
std::ptr::null_mut()
384+
};
385+
375386
// FIXME: NewPM doesn't provide a facility to pass custom InlineParams.
376387
// We would have to add upstream support for this first, before we can support
377388
// config.inline_threshold and our more aggressive default thresholds.
@@ -394,6 +405,9 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
394405
sanitizer_options.as_ref(),
395406
pgo_gen_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
396407
pgo_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
408+
llvm_selfprofiler,
409+
selfprofile_before_pass_callback,
410+
selfprofile_after_pass_callback,
397411
);
398412
}
399413

@@ -428,10 +442,15 @@ pub(crate) unsafe fn optimize(
428442
_ if cgcx.opts.cg.linker_plugin_lto.enabled() => llvm::OptStage::PreLinkThinLTO,
429443
_ => llvm::OptStage::PreLinkNoLTO,
430444
};
431-
optimize_with_new_llvm_pass_manager(module, config, opt_level, opt_stage);
445+
optimize_with_new_llvm_pass_manager(cgcx, module, config, opt_level, opt_stage);
432446
return Ok(());
433447
}
434448

449+
if cgcx.prof.llvm_recording_enabled() {
450+
diag_handler
451+
.warn("`-Z self-profile-events = llvm` requires `-Z new-llvm-pass-manager`");
452+
}
453+
435454
// Create the two optimizing pass managers. These mirror what clang
436455
// does, and are by populated by LLVM's default PassManagerBuilder.
437456
// Each manager has a different set of passes, but they also share

src/librustc_codegen_llvm/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ mod back {
4444
pub mod archive;
4545
pub mod bytecode;
4646
pub mod lto;
47+
mod profiling;
4748
pub mod write;
4849
}
4950

src/librustc_codegen_llvm/llvm/ffi.rs

+7
Original file line numberDiff line numberDiff line change
@@ -709,6 +709,10 @@ extern "C" {
709709
pub type ModuleBuffer;
710710
}
711711

712+
pub type SelfProfileBeforePassCallback =
713+
unsafe extern "C" fn(*mut c_void, *const c_char, *const c_char);
714+
pub type SelfProfileAfterPassCallback = unsafe extern "C" fn(*mut c_void);
715+
712716
extern "C" {
713717
pub fn LLVMRustInstallFatalErrorHandler();
714718

@@ -1945,6 +1949,9 @@ extern "C" {
19451949
SanitizerOptions: Option<&SanitizerOptions>,
19461950
PGOGenPath: *const c_char,
19471951
PGOUsePath: *const c_char,
1952+
llvm_selfprofiler: *mut c_void,
1953+
begin_callback: SelfProfileBeforePassCallback,
1954+
end_callback: SelfProfileAfterPassCallback,
19481955
);
19491956
pub fn LLVMRustPrintModule(
19501957
M: &'a Module,

src/librustc_data_structures/profiling.rs

+11
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ bitflags::bitflags! {
127127

128128
const QUERY_KEYS = 1 << 5;
129129
const FUNCTION_ARGS = 1 << 6;
130+
const LLVM = 1 << 7;
130131

131132
const DEFAULT = Self::GENERIC_ACTIVITIES.bits |
132133
Self::QUERY_PROVIDERS.bits |
@@ -150,6 +151,7 @@ const EVENT_FILTERS_BY_NAME: &[(&str, EventFilter)] = &[
150151
("query-keys", EventFilter::QUERY_KEYS),
151152
("function-args", EventFilter::FUNCTION_ARGS),
152153
("args", EventFilter::ARGS),
154+
("llvm", EventFilter::LLVM),
153155
];
154156

155157
/// Something that uniquely identifies a query invocation.
@@ -364,6 +366,15 @@ impl SelfProfilerRef {
364366
pub fn enabled(&self) -> bool {
365367
self.profiler.is_some()
366368
}
369+
370+
#[inline]
371+
pub fn llvm_recording_enabled(&self) -> bool {
372+
self.event_filter_mask.contains(EventFilter::LLVM)
373+
}
374+
#[inline]
375+
pub fn get_self_profiler(&self) -> Option<Arc<SelfProfiler>> {
376+
self.profiler.clone()
377+
}
367378
}
368379

369380
pub struct SelfProfiler {

src/librustc_session/options.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -940,7 +940,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
940940
"specifies which kinds of events get recorded by the self profiler;
941941
for example: `-Z self-profile-events=default,query-keys`
942942
all options: none, all, default, generic-activity, query-provider, query-cache-hit
943-
query-blocked, incr-cache-load, query-keys"),
943+
query-blocked, incr-cache-load, query-keys, function-args, args, llvm"),
944944
emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
945945
"emits a section containing stack size metadata"),
946946
plt: Option<bool> = (None, parse_opt_bool, [TRACKED],

src/rustllvm/PassWrapper.cpp

+64-1
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,62 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMPassManagerRef PMR,
640640
return LLVMRustResult::Success;
641641
}
642642

643+
extern "C" typedef void (*LLVMRustSelfProfileBeforePassCallback)(void*, // LlvmSelfProfiler
644+
const char*, // pass name
645+
const char*); // IR name
646+
extern "C" typedef void (*LLVMRustSelfProfileAfterPassCallback)(void*); // LlvmSelfProfiler
647+
648+
#if LLVM_VERSION_GE(9, 0)
649+
650+
std::string LLVMRustwrappedIrGetName(const llvm::Any &WrappedIr) {
651+
if (any_isa<const Module *>(WrappedIr))
652+
return any_cast<const Module *>(WrappedIr)->getName().str();
653+
if (any_isa<const Function *>(WrappedIr))
654+
return any_cast<const Function *>(WrappedIr)->getName().str();
655+
if (any_isa<const Loop *>(WrappedIr))
656+
return any_cast<const Loop *>(WrappedIr)->getName().str();
657+
if (any_isa<const LazyCallGraph::SCC *>(WrappedIr))
658+
return any_cast<const LazyCallGraph::SCC *>(WrappedIr)->getName();
659+
return "<UNKNOWN>";
660+
}
661+
662+
663+
void LLVMSelfProfileInitializeCallbacks(
664+
PassInstrumentationCallbacks& PIC, void* LlvmSelfProfiler,
665+
LLVMRustSelfProfileBeforePassCallback BeforePassCallback,
666+
LLVMRustSelfProfileAfterPassCallback AfterPassCallback) {
667+
PIC.registerBeforePassCallback([LlvmSelfProfiler, BeforePassCallback](
668+
StringRef Pass, llvm::Any Ir) {
669+
std::string PassName = Pass.str();
670+
std::string IrName = LLVMRustwrappedIrGetName(Ir);
671+
BeforePassCallback(LlvmSelfProfiler, PassName.c_str(), IrName.c_str());
672+
return true;
673+
});
674+
675+
PIC.registerAfterPassCallback(
676+
[LlvmSelfProfiler, AfterPassCallback](StringRef Pass, llvm::Any Ir) {
677+
AfterPassCallback(LlvmSelfProfiler);
678+
});
679+
680+
PIC.registerAfterPassInvalidatedCallback(
681+
[LlvmSelfProfiler, AfterPassCallback](StringRef Pass) {
682+
AfterPassCallback(LlvmSelfProfiler);
683+
});
684+
685+
PIC.registerBeforeAnalysisCallback([LlvmSelfProfiler, BeforePassCallback](
686+
StringRef Pass, llvm::Any Ir) {
687+
std::string PassName = Pass.str();
688+
std::string IrName = LLVMRustwrappedIrGetName(Ir);
689+
BeforePassCallback(LlvmSelfProfiler, PassName.c_str(), IrName.c_str());
690+
});
691+
692+
PIC.registerAfterAnalysisCallback(
693+
[LlvmSelfProfiler, AfterPassCallback](StringRef Pass, llvm::Any Ir) {
694+
AfterPassCallback(LlvmSelfProfiler);
695+
});
696+
}
697+
#endif
698+
643699
enum class LLVMRustOptStage {
644700
PreLinkNoLTO,
645701
PreLinkThinLTO,
@@ -666,7 +722,10 @@ LLVMRustOptimizeWithNewPassManager(
666722
bool MergeFunctions, bool UnrollLoops, bool SLPVectorize, bool LoopVectorize,
667723
bool DisableSimplifyLibCalls,
668724
LLVMRustSanitizerOptions *SanitizerOptions,
669-
const char *PGOGenPath, const char *PGOUsePath) {
725+
const char *PGOGenPath, const char *PGOUsePath,
726+
void* LlvmSelfProfiler,
727+
LLVMRustSelfProfileBeforePassCallback BeforePassCallback,
728+
LLVMRustSelfProfileAfterPassCallback AfterPassCallback) {
670729
#if LLVM_VERSION_GE(9, 0)
671730
Module *TheModule = unwrap(ModuleRef);
672731
TargetMachine *TM = unwrap(TMRef);
@@ -685,6 +744,10 @@ LLVMRustOptimizeWithNewPassManager(
685744
StandardInstrumentations SI;
686745
SI.registerCallbacks(PIC);
687746

747+
if (LlvmSelfProfiler){
748+
LLVMSelfProfileInitializeCallbacks(PIC,LlvmSelfProfiler,BeforePassCallback,AfterPassCallback);
749+
}
750+
688751
Optional<PGOOptions> PGOOpt;
689752
if (PGOGenPath) {
690753
assert(!PGOUsePath);

0 commit comments

Comments
 (0)