From 5187763cff184eda0f28fd409a4a8c6dfc57c9f9 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 4 Oct 2017 14:38:52 -0700 Subject: [PATCH] rustc: Allow target-specific default cgus Some targets, like msp430 and nvptx, don't work with multiple codegen units right now for bugs or fundamental reasons. To expose this allow targets to express a default. Closes #45000 --- src/librustc/session/config.rs | 48 ++------------------- src/librustc/session/mod.rs | 37 ++++++++++++++++ src/librustc_back/target/mod.rs | 6 +++ src/librustc_back/target/msp430_none_elf.rs | 5 +++ src/librustc_trans/back/link.rs | 2 +- src/librustc_trans/back/write.rs | 6 +-- src/librustc_trans/base.rs | 2 +- 7 files changed, 56 insertions(+), 50 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index fc1c5e187ecc7..69ff55ab2234b 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -352,7 +352,7 @@ top_level_options!( actually_rustdoc: bool [TRACKED], // Number of object files/codegen units to produce on the backend - codegen_units: usize [UNTRACKED], + cli_forced_codegen_units: Option [UNTRACKED], } ); @@ -505,7 +505,7 @@ pub fn basic_options() -> Options { unstable_features: UnstableFeatures::Disallow, debug_assertions: true, actually_rustdoc: false, - codegen_units: 1, + cli_forced_codegen_units: None, } } @@ -1711,48 +1711,6 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) let incremental = debugging_opts.incremental.as_ref().map(|m| PathBuf::from(m)); - let codegen_units = codegen_units.unwrap_or_else(|| { - match opt_level { - // If we're compiling at `-O0` then default to 16 codegen units. - // The number here shouldn't matter too too much as debug mode - // builds don't rely on performance at all, meaning that lost - // opportunities for inlining through multiple codegen units is - // a non-issue. - // - // Note that the high number here doesn't mean that we'll be - // spawning a large number of threads in parallel. The backend - // of rustc contains global rate limiting through the - // `jobserver` crate so we'll never overload the system with too - // much work, but rather we'll only be optimizing when we're - // otherwise cooperating with other instances of rustc. - // - // Rather the high number here means that we should be able to - // keep a lot of idle cpus busy. By ensuring that no codegen - // unit takes *too* long to build we'll be guaranteed that all - // cpus will finish pretty closely to one another and we should - // make relatively optimal use of system resources - // - // Another note worth mentioning here, however, is that this number - // isn't *too* high. When codegen units are increased that means we - // currently have to codegen `#[inline]` functions into each codegen - // unit, which means the more codegen units we're using the more we - // may be generating. In other words, increasing codegen units may - // increase the overall work the compiler does. If we don't have - // enough cores to make up for this loss then increasing the number - // of codegen units could become an overall loss! - // - // As a result we choose a hopefully conservative value 16, which - // should be more than the number of cpus of most hardware compiling - // Rust but also not too much for 2-4 core machines to have too much - // loss of compile time. - OptLevel::No => 16, - - // All other optimization levels default use one codegen unit, - // the historical default in Rust for a Long Time. - _ => 1, - } - }); - (Options { crate_types, optimize: opt_level, @@ -1777,7 +1735,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) unstable_features: UnstableFeatures::from_environment(), debug_assertions, actually_rustdoc: false, - codegen_units, + cli_forced_codegen_units: codegen_units, }, cfg) } diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index bd6e5eb67c87c..d8301596a9281 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -636,6 +636,43 @@ impl Session { } ret } + + /// Returns the number of codegen units that should be used for this + /// compilation + pub fn codegen_units(&self) -> usize { + if let Some(n) = self.opts.cli_forced_codegen_units { + return n + } + if let Some(n) = self.target.target.options.default_codegen_units { + return n as usize + } + + match self.opts.optimize { + // If we're compiling at `-O0` then default to 16 codegen units. + // The number here shouldn't matter too too much as debug mode + // builds don't rely on performance at all, meaning that lost + // opportunities for inlining through multiple codegen units is + // a non-issue. + // + // Note that the high number here doesn't mean that we'll be + // spawning a large number of threads in parallel. The backend + // of rustc contains global rate limiting through the + // `jobserver` crate so we'll never overload the system with too + // much work, but rather we'll only be optimizing when we're + // otherwise cooperating with other instances of rustc. + // + // Rather the high number here means that we should be able to + // keep a lot of idle cpus busy. By ensuring that no codegen + // unit takes *too* long to build we'll be guaranteed that all + // cpus will finish pretty closely to one another and we should + // make relatively optimal use of system resources + config::OptLevel::No => 16, + + // All other optimization levels default use one codegen unit, + // the historical default in Rust for a Long Time. + _ => 1, + } + } } pub fn build_session(sopts: config::Options, diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 039e015365651..1d6c3871e4529 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -430,6 +430,9 @@ pub struct TargetOptions { /// The minimum alignment for global symbols. pub min_global_align: Option, + + /// Default number of codegen units to use in debug mode + pub default_codegen_units: Option, } impl Default for TargetOptions { @@ -492,6 +495,7 @@ impl Default for TargetOptions { crt_static_respected: false, stack_probes: false, min_global_align: None, + default_codegen_units: None, } } } @@ -732,6 +736,7 @@ impl Target { key!(crt_static_respected, bool); key!(stack_probes, bool); key!(min_global_align, Option); + key!(default_codegen_units, Option); if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) { for name in array.iter().filter_map(|abi| abi.as_string()) { @@ -924,6 +929,7 @@ impl ToJson for Target { target_option_val!(crt_static_respected); target_option_val!(stack_probes); target_option_val!(min_global_align); + target_option_val!(default_codegen_units); if default.abi_blacklist != self.options.abi_blacklist { d.insert("abi-blacklist".to_string(), self.options.abi_blacklist.iter() diff --git a/src/librustc_back/target/msp430_none_elf.rs b/src/librustc_back/target/msp430_none_elf.rs index 9227a96e75049..509a7cf5e0323 100644 --- a/src/librustc_back/target/msp430_none_elf.rs +++ b/src/librustc_back/target/msp430_none_elf.rs @@ -48,6 +48,11 @@ pub fn target() -> TargetResult { // code because of the extra costs it involves. relocation_model: "static".to_string(), + // Right now we invoke an external assembler and this isn't + // compatible with multiple codegen units, and plus we probably + // don't want to invoke that many gcc instances. + default_codegen_units: Some(1), + .. Default::default( ) } }) diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 3f25c182fa22a..570a6bbac1e4e 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -467,7 +467,7 @@ fn link_rlib<'a>(sess: &'a Session, // of when we do and don't keep .#module-name#.bc files around. let user_wants_numbered_bitcode = sess.opts.output_types.contains_key(&OutputType::Bitcode) && - sess.opts.codegen_units > 1; + sess.codegen_units() > 1; if !sess.opts.cg.save_temps && !user_wants_numbered_bitcode { remove(sess, &bc_filename); } diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 22b09a0e26931..6ebf642ebca13 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -1037,10 +1037,10 @@ fn produce_final_output_artifacts(sess: &Session, let needs_crate_object = crate_output.outputs.contains_key(&OutputType::Exe); let keep_numbered_bitcode = needs_crate_bitcode || - (user_wants_bitcode && sess.opts.codegen_units > 1); + (user_wants_bitcode && sess.codegen_units() > 1); let keep_numbered_objects = needs_crate_object || - (user_wants_objects && sess.opts.codegen_units > 1); + (user_wants_objects && sess.codegen_units() > 1); for module in compiled_modules.modules.iter() { let module_name = Some(&module.name[..]); @@ -2052,7 +2052,7 @@ impl OngoingCrateTranslation { // FIXME: time_llvm_passes support - does this use a global context or // something? - if sess.opts.codegen_units == 1 && sess.time_llvm_passes() { + if sess.codegen_units() == 1 && sess.time_llvm_passes() { unsafe { llvm::LLVMRustPrintPassTimings(); } } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 17e00ac134666..6b53b5b6411d0 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1218,7 +1218,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>( let strategy = if tcx.sess.opts.debugging_opts.incremental.is_some() { PartitioningStrategy::PerModule } else { - PartitioningStrategy::FixedUnitCount(tcx.sess.opts.codegen_units) + PartitioningStrategy::FixedUnitCount(tcx.sess.codegen_units()) }; let codegen_units = time(time_passes, "codegen unit partitioning", || {