Skip to content

Commit 903f08a

Browse files
committed
Auto merge of #47415 - varkor:cgu-partition-heuristic, r=michaelwoerister
Add CGU size heuristic for partitioning This addresses the concern of #47316 by estimating CGU size based on the size of its MIR. Looking at the size estimate differences for a small selection of crates, this heuristic produces different orderings, which should more accurately reflect optimisation time. (Fixes #47316.) r? @michaelwoerister
2 parents 5669050 + 62703cf commit 903f08a

File tree

8 files changed

+81
-9
lines changed

8 files changed

+81
-9
lines changed

src/librustc/dep_graph/dep_node.rs

+1
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,7 @@ define_dep_nodes!( <'tcx>
638638
[input] TargetFeaturesWhitelist,
639639
[] TargetFeaturesEnabled(DefId),
640640

641+
[] InstanceDefSizeEstimate { instance_def: InstanceDef<'tcx> },
641642
);
642643

643644
trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug {

src/librustc/mir/mono.rs

+38-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
use syntax::ast::NodeId;
1212
use syntax::symbol::InternedString;
13-
use ty::Instance;
13+
use ty::{Instance, TyCtxt};
1414
use util::nodemap::FxHashMap;
1515
use rustc_data_structures::base_n;
1616
use rustc_data_structures::stable_hasher::{HashStable, StableHasherResult,
@@ -25,6 +25,21 @@ pub enum MonoItem<'tcx> {
2525
GlobalAsm(NodeId),
2626
}
2727

28+
impl<'tcx> MonoItem<'tcx> {
29+
pub fn size_estimate<'a>(&self, tcx: &TyCtxt<'a, 'tcx, 'tcx>) -> usize {
30+
match *self {
31+
MonoItem::Fn(instance) => {
32+
// Estimate the size of a function based on how many statements
33+
// it contains.
34+
tcx.instance_def_size_estimate(instance.def)
35+
},
36+
// Conservatively estimate the size of a static declaration
37+
// or assembly to be 1.
38+
MonoItem::Static(_) | MonoItem::GlobalAsm(_) => 1,
39+
}
40+
}
41+
}
42+
2843
impl<'tcx> HashStable<StableHashingContext<'tcx>> for MonoItem<'tcx> {
2944
fn hash_stable<W: StableHasherResult>(&self,
3045
hcx: &mut StableHashingContext<'tcx>,
@@ -52,6 +67,7 @@ pub struct CodegenUnit<'tcx> {
5267
/// as well as the crate name and disambiguator.
5368
name: InternedString,
5469
items: FxHashMap<MonoItem<'tcx>, (Linkage, Visibility)>,
70+
size_estimate: Option<usize>,
5571
}
5672

5773
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
@@ -101,6 +117,7 @@ impl<'tcx> CodegenUnit<'tcx> {
101117
CodegenUnit {
102118
name: name,
103119
items: FxHashMap(),
120+
size_estimate: None,
104121
}
105122
}
106123

@@ -131,6 +148,24 @@ impl<'tcx> CodegenUnit<'tcx> {
131148
let hash = hash & ((1u128 << 80) - 1);
132149
base_n::encode(hash, base_n::CASE_INSENSITIVE)
133150
}
151+
152+
pub fn estimate_size<'a>(&mut self, tcx: &TyCtxt<'a, 'tcx, 'tcx>) {
153+
// Estimate the size of a codegen unit as (approximately) the number of MIR
154+
// statements it corresponds to.
155+
self.size_estimate = Some(self.items.keys().map(|mi| mi.size_estimate(tcx)).sum());
156+
}
157+
158+
pub fn size_estimate(&self) -> usize {
159+
// Should only be called if `estimate_size` has previously been called.
160+
self.size_estimate.expect("estimate_size must be called before getting a size_estimate")
161+
}
162+
163+
pub fn modify_size_estimate(&mut self, delta: usize) {
164+
assert!(self.size_estimate.is_some());
165+
if let Some(size_estimate) = self.size_estimate {
166+
self.size_estimate = Some(size_estimate + delta);
167+
}
168+
}
134169
}
135170

136171
impl<'tcx> HashStable<StableHashingContext<'tcx>> for CodegenUnit<'tcx> {
@@ -140,6 +175,8 @@ impl<'tcx> HashStable<StableHashingContext<'tcx>> for CodegenUnit<'tcx> {
140175
let CodegenUnit {
141176
ref items,
142177
name,
178+
// The size estimate is not relevant to the hash
179+
size_estimate: _,
143180
} = *self;
144181

145182
name.hash_stable(hcx, hasher);

src/librustc/ty/maps/config.rs

+6
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::target_features_whitelist<'tcx> {
637637
}
638638
}
639639

640+
impl<'tcx> QueryDescription<'tcx> for queries::instance_def_size_estimate<'tcx> {
641+
fn describe(tcx: TyCtxt, def: ty::InstanceDef<'tcx>) -> String {
642+
format!("estimating size for `{}`", tcx.item_path_str(def.def_id()))
643+
}
644+
}
645+
640646
macro_rules! impl_disk_cacheable_query(
641647
($query_name:ident, |$key:tt| $cond:expr) => {
642648
impl<'tcx> QueryDescription<'tcx> for queries::$query_name<'tcx> {

src/librustc/ty/maps/mod.rs

+10
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,9 @@ define_maps! { <'tcx>
365365
target_features_whitelist_node(CrateNum) -> Rc<FxHashSet<String>>,
366366
[] fn target_features_enabled: TargetFeaturesEnabled(DefId) -> Rc<Vec<String>>,
367367

368+
// Get an estimate of the size of an InstanceDef based on its MIR for CGU partitioning.
369+
[] fn instance_def_size_estimate: instance_def_size_estimate_dep_node(ty::InstanceDef<'tcx>)
370+
-> usize,
368371
}
369372

370373
//////////////////////////////////////////////////////////////////////
@@ -514,3 +517,10 @@ fn substitute_normalize_and_test_predicates_node<'tcx>(key: (DefId, &'tcx Substs
514517
fn target_features_whitelist_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
515518
DepConstructor::TargetFeaturesWhitelist
516519
}
520+
521+
fn instance_def_size_estimate_dep_node<'tcx>(instance_def: ty::InstanceDef<'tcx>)
522+
-> DepConstructor<'tcx> {
523+
DepConstructor::InstanceDefSizeEstimate {
524+
instance_def
525+
}
526+
}

src/librustc/ty/maps/plumbing.rs

+1
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
761761
DepKind::EraseRegionsTy |
762762
DepKind::NormalizeTy |
763763
DepKind::SubstituteNormalizeAndTestPredicates |
764+
DepKind::InstanceDefSizeEstimate |
764765

765766
// This one should never occur in this context
766767
DepKind::Null => {

src/librustc/ty/mod.rs

+15
Original file line numberDiff line numberDiff line change
@@ -2695,6 +2695,20 @@ fn crate_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
26952695
tcx.hir.crate_hash
26962696
}
26972697

2698+
fn instance_def_size_estimate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
2699+
instance_def: InstanceDef<'tcx>)
2700+
-> usize {
2701+
match instance_def {
2702+
InstanceDef::Item(..) |
2703+
InstanceDef::DropGlue(..) => {
2704+
let mir = tcx.instance_mir(instance_def);
2705+
mir.basic_blocks().iter().map(|bb| bb.statements.len()).sum()
2706+
},
2707+
// Estimate the size of other compiler-generated shims to be 1.
2708+
_ => 1
2709+
}
2710+
}
2711+
26982712
pub fn provide(providers: &mut ty::maps::Providers) {
26992713
context::provide(providers);
27002714
erase_regions::provide(providers);
@@ -2712,6 +2726,7 @@ pub fn provide(providers: &mut ty::maps::Providers) {
27122726
original_crate_name,
27132727
crate_hash,
27142728
trait_impls_of: trait_def::trait_impls_of_provider,
2729+
instance_def_size_estimate,
27152730
..*providers
27162731
};
27172732
}

src/librustc_mir/monomorphize/partitioning.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ use syntax::ast::NodeId;
115115
use syntax::symbol::{Symbol, InternedString};
116116
use rustc::mir::mono::MonoItem;
117117
use monomorphize::item::{MonoItemExt, InstantiationMode};
118+
use core::usize;
118119

119120
pub use rustc::mir::mono::CodegenUnit;
120121

@@ -224,6 +225,8 @@ pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
224225
let mut initial_partitioning = place_root_translation_items(tcx,
225226
trans_items);
226227

228+
initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(&tcx));
229+
227230
debug_dump(tcx, "INITIAL PARTITIONING:", initial_partitioning.codegen_units.iter());
228231

229232
// If the partitioning should produce a fixed count of codegen units, merge
@@ -241,6 +244,8 @@ pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
241244
let mut post_inlining = place_inlined_translation_items(initial_partitioning,
242245
inlining_map);
243246

247+
post_inlining.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(&tcx));
248+
244249
debug_dump(tcx, "POST INLINING:", post_inlining.codegen_units.iter());
245250

246251
// Next we try to make as many symbols "internal" as possible, so LLVM has
@@ -422,14 +427,13 @@ fn merge_codegen_units<'tcx>(initial_partitioning: &mut PreInliningPartitioning<
422427
codegen_units.sort_by_key(|cgu| cgu.name().clone());
423428

424429
// Merge the two smallest codegen units until the target size is reached.
425-
// Note that "size" is estimated here rather inaccurately as the number of
426-
// translation items in a given unit. This could be improved on.
427430
while codegen_units.len() > target_cgu_count {
428431
// Sort small cgus to the back
429-
codegen_units.sort_by_key(|cgu| -(cgu.items().len() as i64));
432+
codegen_units.sort_by_key(|cgu| usize::MAX - cgu.size_estimate());
430433
let mut smallest = codegen_units.pop().unwrap();
431434
let second_smallest = codegen_units.last_mut().unwrap();
432435

436+
second_smallest.modify_size_estimate(smallest.size_estimate());
433437
for (k, v) in smallest.items_mut().drain() {
434438
second_smallest.items_mut().insert(k, v);
435439
}

src/librustc_trans/base.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ use std::ffi::CString;
7878
use std::str;
7979
use std::sync::Arc;
8080
use std::time::{Instant, Duration};
81-
use std::i32;
81+
use std::{i32, usize};
8282
use std::iter;
8383
use std::sync::mpsc;
8484
use syntax_pos::Span;
@@ -823,12 +823,10 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
823823
ongoing_translation.submit_pre_translated_module_to_llvm(tcx, metadata_module);
824824

825825
// We sort the codegen units by size. This way we can schedule work for LLVM
826-
// a bit more efficiently. Note that "size" is defined rather crudely at the
827-
// moment as it is just the number of TransItems in the CGU, not taking into
828-
// account the size of each TransItem.
826+
// a bit more efficiently.
829827
let codegen_units = {
830828
let mut codegen_units = codegen_units;
831-
codegen_units.sort_by_key(|cgu| -(cgu.items().len() as isize));
829+
codegen_units.sort_by_key(|cgu| usize::MAX - cgu.size_estimate());
832830
codegen_units
833831
};
834832

0 commit comments

Comments
 (0)