add selfprofiling for new llvm passmanager

This commit is contained in:
Andreas Jonson 2020-02-11 22:37:16 +01:00
parent ba18875557
commit cec0ed0219
10 changed files with 165 additions and 4 deletions

View File

@ -3559,6 +3559,7 @@ dependencies = [
"flate2", "flate2",
"libc", "libc",
"log", "log",
"measureme",
"rustc", "rustc",
"rustc-demangle", "rustc-demangle",
"rustc_attr", "rustc_attr",

View File

@ -14,6 +14,7 @@ doctest = false
bitflags = "1.0" bitflags = "1.0"
flate2 = "1.0" flate2 = "1.0"
libc = "0.2" libc = "0.2"
measureme = "0.7.1"
log = "0.4" log = "0.4"
rustc = { path = "../librustc" } rustc = { path = "../librustc" }
rustc-demangle = "0.1" rustc-demangle = "0.1"

View File

@ -593,7 +593,7 @@ pub(crate) fn run_pass_manager(
} else { } else {
opt_level opt_level
}; };
write::optimize_with_new_llvm_pass_manager(module, config, opt_level, opt_stage); write::optimize_with_new_llvm_pass_manager(cgcx, module, config, opt_level, opt_stage);
debug!("lto done"); debug!("lto done");
return; return;
} }

View File

@ -0,0 +1,58 @@
use measureme::{event_id::SEPARATOR_BYTE, EventId, StringComponent, StringId};
use rustc_data_structures::profiling::{SelfProfiler, TimingGuard};
use std::ffi::{c_void, CStr};
use std::os::raw::c_char;
use std::sync::Arc;
fn llvm_args_to_string_id(profiler: &SelfProfiler, pass_name: &str, ir_name: &str) -> EventId {
let pass_name = profiler.get_or_alloc_cached_string(pass_name);
let mut components = vec![StringComponent::Ref(pass_name)];
// handle that LazyCallGraph::SCC is a comma separated list within parentheses
let parentheses: &[_] = &['(', ')'];
let trimed = ir_name.trim_matches(parentheses);
for part in trimed.split(", ") {
let demangled_ir_name = rustc_demangle::demangle(part).to_string();
let ir_name = profiler.get_or_alloc_cached_string(demangled_ir_name);
components.push(StringComponent::Value(SEPARATOR_BYTE));
components.push(StringComponent::Ref(ir_name));
}
EventId::from_label(profiler.alloc_string(components.as_slice()))
}
pub struct LlvmSelfProfiler<'a> {
profiler: Arc<SelfProfiler>,
stack: Vec<TimingGuard<'a>>,
llvm_pass_event_kind: StringId,
}
impl<'a> LlvmSelfProfiler<'a> {
pub fn new(profiler: Arc<SelfProfiler>) -> Self {
let llvm_pass_event_kind = profiler.alloc_string("LLVM Pass");
Self { profiler, stack: Vec::default(), llvm_pass_event_kind }
}
fn before_pass_callback(&'a mut self, pass_name: &str, ir_name: &str) {
let event_id = llvm_args_to_string_id(&self.profiler, pass_name, ir_name);
self.stack.push(TimingGuard::start(&self.profiler, self.llvm_pass_event_kind, event_id));
}
fn after_pass_callback(&mut self) {
self.stack.pop();
}
}
pub unsafe extern "C" fn selfprofile_before_pass_callback(
llvm_self_profiler: *mut c_void,
pass_name: *const c_char,
ir_name: *const c_char,
) {
let llvm_self_profiler = &mut *(llvm_self_profiler as *mut LlvmSelfProfiler<'_>);
let pass_name = CStr::from_ptr(pass_name).to_str().expect("valid UTF-8");
let ir_name = CStr::from_ptr(ir_name).to_str().expect("valid UTF-8");
llvm_self_profiler.before_pass_callback(pass_name, ir_name);
}
pub unsafe extern "C" fn selfprofile_after_pass_callback(llvm_self_profiler: *mut c_void) {
let llvm_self_profiler = &mut *(llvm_self_profiler as *mut LlvmSelfProfiler<'_>);
llvm_self_profiler.after_pass_callback();
}

View File

@ -1,6 +1,9 @@
use crate::attributes; use crate::attributes;
use crate::back::bytecode; use crate::back::bytecode;
use crate::back::lto::ThinBuffer; use crate::back::lto::ThinBuffer;
use crate::back::profiling::{
selfprofile_after_pass_callback, selfprofile_before_pass_callback, LlvmSelfProfiler,
};
use crate::base; use crate::base;
use crate::common; use crate::common;
use crate::consts; use crate::consts;
@ -348,6 +351,7 @@ pub(crate) fn should_use_new_llvm_pass_manager(config: &ModuleConfig) -> bool {
} }
pub(crate) unsafe fn optimize_with_new_llvm_pass_manager( pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
cgcx: &CodegenContext<LlvmCodegenBackend>,
module: &ModuleCodegen<ModuleLlvm>, module: &ModuleCodegen<ModuleLlvm>,
config: &ModuleConfig, config: &ModuleConfig,
opt_level: config::OptLevel, opt_level: config::OptLevel,
@ -372,6 +376,13 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
None None
}; };
let llvm_selfprofiler = if cgcx.prof.llvm_recording_enabled() {
let mut llvm_profiler = LlvmSelfProfiler::new(cgcx.prof.get_self_profiler().unwrap());
&mut llvm_profiler as *mut _ as *mut c_void
} else {
std::ptr::null_mut()
};
// FIXME: NewPM doesn't provide a facility to pass custom InlineParams. // FIXME: NewPM doesn't provide a facility to pass custom InlineParams.
// We would have to add upstream support for this first, before we can support // We would have to add upstream support for this first, before we can support
// config.inline_threshold and our more aggressive default thresholds. // config.inline_threshold and our more aggressive default thresholds.
@ -394,6 +405,9 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
sanitizer_options.as_ref(), sanitizer_options.as_ref(),
pgo_gen_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), pgo_gen_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
pgo_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()), pgo_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
llvm_selfprofiler,
selfprofile_before_pass_callback,
selfprofile_after_pass_callback,
); );
} }
@ -428,10 +442,15 @@ pub(crate) unsafe fn optimize(
_ if cgcx.opts.cg.linker_plugin_lto.enabled() => llvm::OptStage::PreLinkThinLTO, _ if cgcx.opts.cg.linker_plugin_lto.enabled() => llvm::OptStage::PreLinkThinLTO,
_ => llvm::OptStage::PreLinkNoLTO, _ => llvm::OptStage::PreLinkNoLTO,
}; };
optimize_with_new_llvm_pass_manager(module, config, opt_level, opt_stage); optimize_with_new_llvm_pass_manager(cgcx, module, config, opt_level, opt_stage);
return Ok(()); return Ok(());
} }
if cgcx.prof.llvm_recording_enabled() {
diag_handler
.warn("`-Z self-profile-events = llvm` requires `-Z new-llvm-pass-manager`");
}
// Create the two optimizing pass managers. These mirror what clang // Create the two optimizing pass managers. These mirror what clang
// does, and are by populated by LLVM's default PassManagerBuilder. // does, and are by populated by LLVM's default PassManagerBuilder.
// Each manager has a different set of passes, but they also share // Each manager has a different set of passes, but they also share

View File

@ -44,6 +44,7 @@ mod back {
pub mod archive; pub mod archive;
pub mod bytecode; pub mod bytecode;
pub mod lto; pub mod lto;
mod profiling;
pub mod write; pub mod write;
} }

View File

@ -709,6 +709,10 @@ extern "C" {
pub type ModuleBuffer; pub type ModuleBuffer;
} }
pub type SelfProfileBeforePassCallback =
unsafe extern "C" fn(*mut c_void, *const c_char, *const c_char);
pub type SelfProfileAfterPassCallback = unsafe extern "C" fn(*mut c_void);
extern "C" { extern "C" {
pub fn LLVMRustInstallFatalErrorHandler(); pub fn LLVMRustInstallFatalErrorHandler();
@ -1945,6 +1949,9 @@ extern "C" {
SanitizerOptions: Option<&SanitizerOptions>, SanitizerOptions: Option<&SanitizerOptions>,
PGOGenPath: *const c_char, PGOGenPath: *const c_char,
PGOUsePath: *const c_char, PGOUsePath: *const c_char,
llvm_selfprofiler: *mut c_void,
begin_callback: SelfProfileBeforePassCallback,
end_callback: SelfProfileAfterPassCallback,
); );
pub fn LLVMRustPrintModule( pub fn LLVMRustPrintModule(
M: &'a Module, M: &'a Module,

View File

@ -127,6 +127,7 @@ bitflags::bitflags! {
const QUERY_KEYS = 1 << 5; const QUERY_KEYS = 1 << 5;
const FUNCTION_ARGS = 1 << 6; const FUNCTION_ARGS = 1 << 6;
const LLVM = 1 << 7;
const DEFAULT = Self::GENERIC_ACTIVITIES.bits | const DEFAULT = Self::GENERIC_ACTIVITIES.bits |
Self::QUERY_PROVIDERS.bits | Self::QUERY_PROVIDERS.bits |
@ -150,6 +151,7 @@ const EVENT_FILTERS_BY_NAME: &[(&str, EventFilter)] = &[
("query-keys", EventFilter::QUERY_KEYS), ("query-keys", EventFilter::QUERY_KEYS),
("function-args", EventFilter::FUNCTION_ARGS), ("function-args", EventFilter::FUNCTION_ARGS),
("args", EventFilter::ARGS), ("args", EventFilter::ARGS),
("llvm", EventFilter::LLVM),
]; ];
/// Something that uniquely identifies a query invocation. /// Something that uniquely identifies a query invocation.
@ -364,6 +366,15 @@ impl SelfProfilerRef {
pub fn enabled(&self) -> bool { pub fn enabled(&self) -> bool {
self.profiler.is_some() self.profiler.is_some()
} }
#[inline]
pub fn llvm_recording_enabled(&self) -> bool {
self.event_filter_mask.contains(EventFilter::LLVM)
}
#[inline]
pub fn get_self_profiler(&self) -> Option<Arc<SelfProfiler>> {
self.profiler.clone()
}
} }
pub struct SelfProfiler { pub struct SelfProfiler {

View File

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

View File

@ -640,6 +640,62 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMPassManagerRef PMR,
return LLVMRustResult::Success; return LLVMRustResult::Success;
} }
extern "C" typedef void (*LLVMRustSelfProfileBeforePassCallback)(void*, // LlvmSelfProfiler
const char*, // pass name
const char*); // IR name
extern "C" typedef void (*LLVMRustSelfProfileAfterPassCallback)(void*); // LlvmSelfProfiler
#if LLVM_VERSION_GE(9, 0)
std::string LLVMRustwrappedIrGetName(const llvm::Any &WrappedIr) {
if (any_isa<const Module *>(WrappedIr))
return any_cast<const Module *>(WrappedIr)->getName().str();
if (any_isa<const Function *>(WrappedIr))
return any_cast<const Function *>(WrappedIr)->getName().str();
if (any_isa<const Loop *>(WrappedIr))
return any_cast<const Loop *>(WrappedIr)->getName().str();
if (any_isa<const LazyCallGraph::SCC *>(WrappedIr))
return any_cast<const LazyCallGraph::SCC *>(WrappedIr)->getName();
return "<UNKNOWN>";
}
void LLVMSelfProfileInitializeCallbacks(
PassInstrumentationCallbacks& PIC, void* LlvmSelfProfiler,
LLVMRustSelfProfileBeforePassCallback BeforePassCallback,
LLVMRustSelfProfileAfterPassCallback AfterPassCallback) {
PIC.registerBeforePassCallback([LlvmSelfProfiler, BeforePassCallback](
StringRef Pass, llvm::Any Ir) {
std::string PassName = Pass.str();
std::string IrName = LLVMRustwrappedIrGetName(Ir);
BeforePassCallback(LlvmSelfProfiler, PassName.c_str(), IrName.c_str());
return true;
});
PIC.registerAfterPassCallback(
[LlvmSelfProfiler, AfterPassCallback](StringRef Pass, llvm::Any Ir) {
AfterPassCallback(LlvmSelfProfiler);
});
PIC.registerAfterPassInvalidatedCallback(
[LlvmSelfProfiler, AfterPassCallback](StringRef Pass) {
AfterPassCallback(LlvmSelfProfiler);
});
PIC.registerBeforeAnalysisCallback([LlvmSelfProfiler, BeforePassCallback](
StringRef Pass, llvm::Any Ir) {
std::string PassName = Pass.str();
std::string IrName = LLVMRustwrappedIrGetName(Ir);
BeforePassCallback(LlvmSelfProfiler, PassName.c_str(), IrName.c_str());
});
PIC.registerAfterAnalysisCallback(
[LlvmSelfProfiler, AfterPassCallback](StringRef Pass, llvm::Any Ir) {
AfterPassCallback(LlvmSelfProfiler);
});
}
#endif
enum class LLVMRustOptStage { enum class LLVMRustOptStage {
PreLinkNoLTO, PreLinkNoLTO,
PreLinkThinLTO, PreLinkThinLTO,
@ -666,7 +722,10 @@ LLVMRustOptimizeWithNewPassManager(
bool MergeFunctions, bool UnrollLoops, bool SLPVectorize, bool LoopVectorize, bool MergeFunctions, bool UnrollLoops, bool SLPVectorize, bool LoopVectorize,
bool DisableSimplifyLibCalls, bool DisableSimplifyLibCalls,
LLVMRustSanitizerOptions *SanitizerOptions, LLVMRustSanitizerOptions *SanitizerOptions,
const char *PGOGenPath, const char *PGOUsePath) { const char *PGOGenPath, const char *PGOUsePath,
void* LlvmSelfProfiler,
LLVMRustSelfProfileBeforePassCallback BeforePassCallback,
LLVMRustSelfProfileAfterPassCallback AfterPassCallback) {
#if LLVM_VERSION_GE(9, 0) #if LLVM_VERSION_GE(9, 0)
Module *TheModule = unwrap(ModuleRef); Module *TheModule = unwrap(ModuleRef);
TargetMachine *TM = unwrap(TMRef); TargetMachine *TM = unwrap(TMRef);
@ -685,6 +744,10 @@ LLVMRustOptimizeWithNewPassManager(
StandardInstrumentations SI; StandardInstrumentations SI;
SI.registerCallbacks(PIC); SI.registerCallbacks(PIC);
if (LlvmSelfProfiler){
LLVMSelfProfileInitializeCallbacks(PIC,LlvmSelfProfiler,BeforePassCallback,AfterPassCallback);
}
Optional<PGOOptions> PGOOpt; Optional<PGOOptions> PGOOpt;
if (PGOGenPath) { if (PGOGenPath) {
assert(!PGOUsePath); assert(!PGOUsePath);