Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add basic PGO support. #48346

Merged
merged 18 commits into from
Mar 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
e8a1575
profiler-builtins: define COMPILER_RT_HAS_UNAME on non-msvc platforms.
emilio Feb 19, 2018
804f959
session: Add two tracked, exclusive codegen options for PGO profile u…
emilio Feb 19, 2018
50a3872
rustc_metadata: Load the profiler runtime if we're generating PGO pro…
emilio Feb 19, 2018
324ca7a
rustc_llvm: rustc_trans: Thread the PGO config down to the pass manag…
emilio Feb 19, 2018
99127ab
rustc_trans: disable probestack when using pgo-gen.
emilio Feb 19, 2018
9c61c72
rustc_trans: Fix PGO generation linking on Linux by adding the releva…
emilio Feb 19, 2018
e2183d3
Test that pgo-gen works properly.
emilio Feb 19, 2018
aaeb40a
profiler_builtins: Add missing ProfilingNameVar file to the profiler …
emilio Feb 19, 2018
a95c8c6
librustc_llvm: Show PGO diagnostics properly.
emilio Mar 12, 2018
036e0d7
librustc_trans: disable profiling pre-inlining.
emilio Mar 12, 2018
688275a
librustc: Convert -C pgo-gen and -C pgo-use into -Z flags.
emilio Mar 12, 2018
e31addf
librustc_trans: Gate the preinliner with another -Z flag.
emilio Mar 12, 2018
8a4cebd
librustc_trans: Turn PGO diagnostics into warnings.
emilio Mar 12, 2018
4053e25
librustc_trans: Mark some profiler symbols as exported to avoid LTO r…
emilio Mar 13, 2018
e155ecd
try to fix the build on older LLVM versions.
emilio Mar 15, 2018
96b8729
Move linker code to the Linker trait instead.
emilio Mar 19, 2018
5af2f80
pgo: Move the tests to run-make-fulldeps, and make the profile file b…
emilio Mar 25, 2018
1e1d907
pgo: Blindly try to fix Windows build.
emilio Mar 25, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/libprofiler_builtins/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ fn main() {
"InstrProfilingFile.c",
"InstrProfilingMerge.c",
"InstrProfilingMergeFile.c",
"InstrProfilingNameVar.c",
"InstrProfilingPlatformDarwin.c",
"InstrProfilingPlatformLinux.c",
"InstrProfilingPlatformOther.c",
Expand All @@ -42,6 +43,8 @@ fn main() {
cfg.define("strdup", Some("_strdup"));
cfg.define("open", Some("_open"));
cfg.define("fdopen", Some("_fdopen"));
cfg.define("getpid", Some("_getpid"));
cfg.define("fileno", Some("_fileno"));
} else {
// Turn off various features of gcc and such, mostly copying
// compiler-rt's build system already
Expand All @@ -50,6 +53,7 @@ fn main() {
cfg.flag("-fomit-frame-pointer");
cfg.flag("-ffreestanding");
cfg.define("VISIBILITY_HIDDEN", None);
cfg.define("COMPILER_RT_HAS_UNAME", Some("1"));
}

for src in profile_sources {
Expand Down
23 changes: 23 additions & 0 deletions src/librustc/session/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1249,6 +1249,14 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"extra arguments to prepend to the linker invocation (space separated)"),
profile: bool = (false, parse_bool, [TRACKED],
"insert profiling code"),
pgo_gen: Option<String> = (None, parse_opt_string, [TRACKED],
"Generate PGO profile data, to a given file, or to the default \
location if it's empty."),
pgo_use: String = (String::new(), parse_string, [TRACKED],
"Use PGO profile data from the given profile file."),
disable_instrumentation_preinliner: bool =
(false, parse_bool, [TRACKED], "Disable the instrumentation pre-inliner, \
useful for profiling / PGO."),
relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED],
"choose which RELRO level to use"),
nll: bool = (false, parse_bool, [UNTRACKED],
Expand Down Expand Up @@ -1771,6 +1779,13 @@ pub fn build_session_options_and_crate_config(
);
}

if debugging_opts.pgo_gen.is_some() && !debugging_opts.pgo_use.is_empty() {
early_error(
error_format,
"options `-Z pgo-gen` and `-Z pgo-use` are exclusive",
);
}

let mut output_types = BTreeMap::new();
if !debugging_opts.parse_only {
for list in matches.opt_strs("emit") {
Expand Down Expand Up @@ -2884,6 +2899,14 @@ mod tests {
opts.debugging_opts.tls_model = Some(String::from("tls model"));
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());

opts = reference.clone();
opts.debugging_opts.pgo_gen = Some(String::from("abc"));
assert_ne!(reference.dep_tracking_hash(), opts.dep_tracking_hash());

opts = reference.clone();
opts.debugging_opts.pgo_use = String::from("abc");
assert_ne!(reference.dep_tracking_hash(), opts.dep_tracking_hash());

opts = reference.clone();
opts.cg.metadata = vec![String::from("A"), String::from("B")];
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
Expand Down
5 changes: 5 additions & 0 deletions src/librustc_llvm/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ impl InlineAsmDiagnostic {
pub enum Diagnostic {
Optimization(OptimizationDiagnostic),
InlineAsm(InlineAsmDiagnostic),
PGO(DiagnosticInfoRef),

/// LLVM has other types that we do not wrap here.
UnknownDiagnostic(DiagnosticInfoRef),
Expand Down Expand Up @@ -160,6 +161,10 @@ impl Diagnostic {
Optimization(OptimizationDiagnostic::unpack(OptimizationFailure, di))
}

Dk::PGOProfile => {
PGO(di)
}

_ => UnknownDiagnostic(di),
}
}
Expand Down
6 changes: 5 additions & 1 deletion src/librustc_llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ pub enum DiagnosticKind {
OptimizationRemarkAnalysisAliasing,
OptimizationRemarkOther,
OptimizationFailure,
PGOProfile,
}

/// LLVMRustArchiveKind
Expand Down Expand Up @@ -1641,7 +1642,9 @@ extern "C" {
OptLevel: CodeGenOptLevel,
MergeFunctions: bool,
SLPVectorize: bool,
LoopVectorize: bool);
LoopVectorize: bool,
PGOGenPath: *const c_char,
PGOUsePath: *const c_char);
pub fn LLVMRustAddLibraryInfo(PM: PassManagerRef,
M: ModuleRef,
DisableSimplifyLibCalls: bool);
Expand Down Expand Up @@ -1736,6 +1739,7 @@ extern "C" {
pub fn LLVMRustModuleCost(M: ModuleRef) -> u64;

pub fn LLVMRustThinLTOAvailable() -> bool;
pub fn LLVMRustPGOAvailable() -> bool;
pub fn LLVMRustWriteThinBitcodeToFile(PMR: PassManagerRef,
M: ModuleRef,
BC: *const c_char) -> bool;
Expand Down
4 changes: 3 additions & 1 deletion src/librustc_metadata/creader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -784,7 +784,9 @@ impl<'a> CrateLoader<'a> {
}

fn inject_profiler_runtime(&mut self) {
if self.sess.opts.debugging_opts.profile {
if self.sess.opts.debugging_opts.profile ||
self.sess.opts.debugging_opts.pgo_gen.is_some()
{
info!("loading profiler");

let symbol = Symbol::intern("profiler_builtins");
Expand Down
5 changes: 5 additions & 0 deletions src/librustc_trans/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@ pub fn set_probestack(cx: &CodegenCx, llfn: ValueRef) {
_ => {}
}

// probestack doesn't play nice either with pgo-gen.
if cx.sess().opts.debugging_opts.pgo_gen.is_some() {
return;
}

// Flag our internal `__rust_probestack` function as the stack probe symbol.
// This is defined in the `compiler-builtins` crate for each architecture.
llvm::AddFunctionAttrStringValue(
Expand Down
4 changes: 4 additions & 0 deletions src/librustc_trans/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1085,6 +1085,10 @@ fn link_args(cmd: &mut Linker,
cmd.build_static_executable();
}

if sess.opts.debugging_opts.pgo_gen.is_some() {
cmd.pgo_gen();
}

// FIXME (#2397): At some point we want to rpath our guesses as to
// where extern libraries might live, based on the
// addl_lib_search_paths
Expand Down
30 changes: 30 additions & 0 deletions src/librustc_trans/back/linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ pub trait Linker {
fn partial_relro(&mut self);
fn no_relro(&mut self);
fn optimize(&mut self);
fn pgo_gen(&mut self);
fn debuginfo(&mut self);
fn no_default_libraries(&mut self);
fn build_dylib(&mut self, out_filename: &Path);
Expand Down Expand Up @@ -280,6 +281,24 @@ impl<'a> Linker for GccLinker<'a> {
}
}

fn pgo_gen(&mut self) {
if !self.sess.target.target.options.linker_is_gnu { return }

// If we're doing PGO generation stuff and on a GNU-like linker, use the
// "-u" flag to properly pull in the profiler runtime bits.
//
// This is because LLVM otherwise won't add the needed initialization
// for us on Linux (though the extra flag should be harmless if it
// does).
//
// See https://reviews.llvm.org/D14033 and https://reviews.llvm.org/D14030.
//
// Though it may be worth to try to revert those changes upstream, since
// the overhead of the initialization should be minor.
self.cmd.arg("-u");
self.cmd.arg("__llvm_profile_runtime");
}

fn debuginfo(&mut self) {
// Don't do anything special here for GNU-style linkers.
}
Expand Down Expand Up @@ -509,6 +528,10 @@ impl<'a> Linker for MsvcLinker<'a> {
// Needs more investigation of `/OPT` arguments
}

fn pgo_gen(&mut self) {
// Nothing needed here.
}

fn debuginfo(&mut self) {
// This will cause the Microsoft linker to generate a PDB file
// from the CodeView line tables in the object files.
Expand Down Expand Up @@ -712,6 +735,10 @@ impl<'a> Linker for EmLinker<'a> {
self.cmd.args(&["--memory-init-file", "0"]);
}

fn pgo_gen(&mut self) {
// noop, but maybe we need something like the gnu linker?
}

fn debuginfo(&mut self) {
// Preserve names or generate source maps depending on debug info
self.cmd.arg(match self.sess.opts.debuginfo {
Expand Down Expand Up @@ -877,6 +904,9 @@ impl Linker for WasmLd {
fn optimize(&mut self) {
}

fn pgo_gen(&mut self) {
}

fn debuginfo(&mut self) {
}

Expand Down
14 changes: 14 additions & 0 deletions src/librustc_trans/back/symbol_export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,20 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
}

if tcx.sess.opts.debugging_opts.pgo_gen.is_some() {
// These are weak symbols that point to the profile version and the
// profile name, which need to be treated as exported so LTO doesn't nix
// them.
const PROFILER_WEAK_SYMBOLS: [&'static str; 2] = [
"__llvm_profile_raw_version",
"__llvm_profile_filename",
];
for sym in &PROFILER_WEAK_SYMBOLS {
let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(sym));
symbols.push((exported_symbol, SymbolExportLevel::C));
}
}

if tcx.sess.crate_types.borrow().contains(&config::CrateTypeDylib) {
let symbol_name = metadata_symbol_name(tcx);
let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name));
Expand Down
46 changes: 39 additions & 7 deletions src/librustc_trans/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,9 @@ pub struct ModuleConfig {
/// Some(level) to optimize binary size, or None to not affect program size.
opt_size: Option<llvm::CodeGenOptSize>,

pgo_gen: Option<String>,
pgo_use: String,

// Flags indicating which outputs to produce.
emit_no_opt_bc: bool,
emit_bc: bool,
Expand Down Expand Up @@ -274,6 +277,9 @@ impl ModuleConfig {
opt_level: None,
opt_size: None,

pgo_gen: None,
pgo_use: String::new(),

emit_no_opt_bc: false,
emit_bc: false,
emit_bc_compressed: false,
Expand Down Expand Up @@ -492,8 +498,13 @@ unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_vo
opt.message));
}
}

_ => (),
llvm::diagnostic::PGO(diagnostic_ref) => {
let msg = llvm::build_string(|s| {
llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s)
}).expect("non-UTF8 PGO diagnostic");
diag_handler.warn(&msg);
}
llvm::diagnostic::UnknownDiagnostic(..) => {},
}
}

Expand Down Expand Up @@ -932,6 +943,9 @@ pub fn start_async_translation(tcx: TyCtxt,
modules_config.passes.push("insert-gcov-profiling".to_owned())
}

modules_config.pgo_gen = sess.opts.debugging_opts.pgo_gen.clone();
modules_config.pgo_use = sess.opts.debugging_opts.pgo_use.clone();

modules_config.opt_level = Some(get_llvm_opt_level(sess.opts.optimize));
modules_config.opt_size = Some(get_llvm_opt_size(sess.opts.optimize));

Expand Down Expand Up @@ -2046,18 +2060,36 @@ pub unsafe fn with_llvm_pmb(llmod: ModuleRef,
config: &ModuleConfig,
opt_level: llvm::CodeGenOptLevel,
f: &mut FnMut(llvm::PassManagerBuilderRef)) {
use std::ptr;

// Create the PassManagerBuilder for LLVM. We configure it with
// reasonable defaults and prepare it to actually populate the pass
// manager.
let builder = llvm::LLVMPassManagerBuilderCreate();
let opt_size = config.opt_size.unwrap_or(llvm::CodeGenOptSizeNone);
let inline_threshold = config.inline_threshold;

llvm::LLVMRustConfigurePassManagerBuilder(builder,
opt_level,
config.merge_functions,
config.vectorize_slp,
config.vectorize_loop);
let pgo_gen_path = config.pgo_gen.as_ref().map(|s| {
let s = if s.is_empty() { "default_%m.profraw" } else { s };
CString::new(s.as_bytes()).unwrap()
});

let pgo_use_path = if config.pgo_use.is_empty() {
None
} else {
Some(CString::new(config.pgo_use.as_bytes()).unwrap())
};

llvm::LLVMRustConfigurePassManagerBuilder(
builder,
opt_level,
config.merge_functions,
config.vectorize_slp,
config.vectorize_loop,
pgo_gen_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
pgo_use_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
);

llvm::LLVMPassManagerBuilderSetSizeLevel(builder, opt_size as u32);

if opt_size != llvm::CodeGenOptSizeNone {
Expand Down
7 changes: 7 additions & 0 deletions src/librustc_trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,13 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
}

if (tcx.sess.opts.debugging_opts.pgo_gen.is_some() ||
!tcx.sess.opts.debugging_opts.pgo_use.is_empty()) &&
unsafe { !llvm::LLVMRustPGOAvailable() }
{
tcx.sess.fatal("this compiler's LLVM does not support PGO");
}

let crate_hash = tcx.crate_hash(LOCAL_CRATE);
let link_meta = link::build_link_meta(crate_hash);

Expand Down
3 changes: 3 additions & 0 deletions src/librustc_trans/llvm_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ unsafe fn configure_llvm(sess: &Session) {
add("rustc"); // fake program name
if sess.time_llvm_passes() { add("-time-passes"); }
if sess.print_llvm_passes() { add("-debug-pass=Structure"); }
if sess.opts.debugging_opts.disable_instrumentation_preinliner {
add("-disable-preinline");
}

for arg in &sess.opts.cg.llvm_args {
add(&(*arg));
Expand Down
Loading