Skip to content

Commit f0ea016

Browse files
committed
Auto merge of #65281 - andjo403:partitioning, r=<try>
for a more even partitioning inline before merge consider the size of the inlined items for a more even partitioning for me this change take the compile time for script-servo-opt from 306s to 249s edit: the times is for a 32 thread cpu. cc #64913
2 parents 7e49800 + a465d97 commit f0ea016

File tree

2 files changed

+95
-89
lines changed

2 files changed

+95
-89
lines changed

Diff for: src/librustc/mir/mono.rs

+10-28
Original file line numberDiff line numberDiff line change
@@ -47,20 +47,6 @@ pub enum MonoItem<'tcx> {
4747
}
4848

4949
impl<'tcx> MonoItem<'tcx> {
50-
pub fn size_estimate(&self, tcx: TyCtxt<'tcx>) -> usize {
51-
match *self {
52-
MonoItem::Fn(instance) => {
53-
// Estimate the size of a function based on how many statements
54-
// it contains.
55-
tcx.instance_def_size_estimate(instance.def)
56-
},
57-
// Conservatively estimate the size of a static declaration
58-
// or assembly to be 1.
59-
MonoItem::Static(_) |
60-
MonoItem::GlobalAsm(_) => 1,
61-
}
62-
}
63-
6450
pub fn is_generic_fn(&self) -> bool {
6551
match *self {
6652
MonoItem::Fn(ref instance) => {
@@ -248,7 +234,7 @@ pub struct CodegenUnit<'tcx> {
248234
/// as well as the crate name and disambiguator.
249235
name: InternedString,
250236
items: FxHashMap<MonoItem<'tcx>, (Linkage, Visibility)>,
251-
size_estimate: Option<usize>,
237+
size_estimate: usize,
252238
}
253239

254240
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
@@ -298,7 +284,7 @@ impl<'tcx> CodegenUnit<'tcx> {
298284
CodegenUnit {
299285
name: name,
300286
items: Default::default(),
301-
size_estimate: None,
287+
size_estimate: 0,
302288
}
303289
}
304290

@@ -330,21 +316,17 @@ impl<'tcx> CodegenUnit<'tcx> {
330316
base_n::encode(hash, base_n::CASE_INSENSITIVE)
331317
}
332318

333-
pub fn estimate_size(&mut self, tcx: TyCtxt<'tcx>) {
334-
// Estimate the size of a codegen unit as (approximately) the number of MIR
335-
// statements it corresponds to.
336-
self.size_estimate = Some(self.items.keys().map(|mi| mi.size_estimate(tcx)).sum());
337-
}
338-
339319
pub fn size_estimate(&self) -> usize {
340-
// Should only be called if `estimate_size` has previously been called.
341-
self.size_estimate.expect("estimate_size must be called before getting a size_estimate")
320+
self.size_estimate
342321
}
343322

344-
pub fn modify_size_estimate(&mut self, delta: usize) {
345-
assert!(self.size_estimate.is_some());
346-
if let Some(size_estimate) = self.size_estimate {
347-
self.size_estimate = Some(size_estimate + delta);
323+
pub fn add_item(
324+
&mut self,
325+
item: MonoItem<'tcx>,
326+
linkage: (Linkage, Visibility),
327+
item_size: usize ) {
328+
if self.items.insert(item, linkage).is_none() {
329+
self.size_estimate += item_size;
348330
}
349331
}
350332

Diff for: src/librustc_mir/monomorphize/partitioning.rs

+85-61
Original file line numberDiff line numberDiff line change
@@ -136,25 +136,21 @@ where
136136
{
137137
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning");
138138

139+
let mut estimator = SizeEstimator::new();
140+
139141
// In the first step, we place all regular monomorphizations into their
140142
// respective 'home' codegen unit. Regular monomorphizations are all
141143
// functions and statics defined in the local crate.
142-
let mut initial_partitioning = {
144+
let initial_partitioning = {
143145
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_roots");
144-
place_root_mono_items(tcx, mono_items)
146+
place_root_mono_items(tcx, mono_items, &mut estimator)
145147
};
146148

147-
initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx));
148-
149-
debug_dump(tcx, "INITIAL PARTITIONING:", initial_partitioning.codegen_units.iter());
150-
151-
// If the partitioning should produce a fixed count of codegen units, merge
152-
// until that count is reached.
153-
if let PartitioningStrategy::FixedUnitCount(count) = strategy {
154-
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_merge_cgus");
155-
merge_codegen_units(tcx, &mut initial_partitioning, count);
156-
debug_dump(tcx, "POST MERGING:", initial_partitioning.codegen_units.iter());
157-
}
149+
debug_dump(
150+
tcx,
151+
"INITIAL PARTITIONING:",
152+
initial_partitioning.codegen_units.iter(),
153+
&mut estimator);
158154

159155
// In the next step, we use the inlining map to determine which additional
160156
// monomorphizations have to go into each codegen unit. These additional
@@ -163,12 +159,18 @@ where
163159
let mut post_inlining = {
164160
let _prof_timer =
165161
tcx.prof.generic_activity("cgu_partitioning_place_inline_items");
166-
place_inlined_mono_items(initial_partitioning, inlining_map)
162+
place_inlined_mono_items(tcx, initial_partitioning, inlining_map, &mut estimator)
167163
};
168164

169-
post_inlining.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx));
165+
debug_dump(tcx, "POST INLINING:", post_inlining.codegen_units.iter(), &mut estimator);
170166

171-
debug_dump(tcx, "POST INLINING:", post_inlining.codegen_units.iter());
167+
// If the partitioning should produce a fixed count of codegen units, merge
168+
// until that count is reached.
169+
if let PartitioningStrategy::FixedUnitCount(count) = strategy {
170+
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_merge_cgus");
171+
merge_codegen_units(tcx, &mut post_inlining, count, &mut estimator);
172+
debug_dump(tcx, "POST MERGING:", post_inlining.codegen_units.iter(), &mut estimator);
173+
}
172174

173175
// Next we try to make as many symbols "internal" as possible, so LLVM has
174176
// more freedom to optimize.
@@ -181,7 +183,6 @@ where
181183
// Finally, sort by codegen unit name, so that we get deterministic results.
182184
let PostInliningPartitioning {
183185
codegen_units: mut result,
184-
mono_item_placements: _,
185186
internalization_candidates: _,
186187
} = post_inlining;
187188

@@ -192,6 +193,27 @@ where
192193
result
193194
}
194195

196+
struct SizeEstimator<'tcx> {
197+
cache: FxHashMap<MonoItem<'tcx>, usize>,
198+
}
199+
impl<'tcx> SizeEstimator<'tcx> {
200+
pub fn new() -> SizeEstimator<'tcx> {
201+
SizeEstimator { cache: Default::default() }
202+
}
203+
pub fn size_estimate(&mut self, tcx: TyCtxt<'tcx>, mono_item: MonoItem<'tcx>) -> usize {
204+
*self.cache.entry(mono_item).or_insert_with(|| match mono_item {
205+
MonoItem::Fn(instance) => {
206+
// Estimate the size of a function based on how many statements
207+
// it contains.
208+
tcx.instance_def_size_estimate(instance.def)
209+
}
210+
// Conservatively estimate the size of a static declaration
211+
// or assembly to be 1.
212+
MonoItem::Static(_) | MonoItem::GlobalAsm(_) => 1,
213+
})
214+
}
215+
}
216+
195217
struct PreInliningPartitioning<'tcx> {
196218
codegen_units: Vec<CodegenUnit<'tcx>>,
197219
roots: FxHashSet<MonoItem<'tcx>>,
@@ -209,11 +231,14 @@ enum MonoItemPlacement {
209231

210232
struct PostInliningPartitioning<'tcx> {
211233
codegen_units: Vec<CodegenUnit<'tcx>>,
212-
mono_item_placements: FxHashMap<MonoItem<'tcx>, MonoItemPlacement>,
213234
internalization_candidates: FxHashSet<MonoItem<'tcx>>,
214235
}
215236

216-
fn place_root_mono_items<'tcx, I>(tcx: TyCtxt<'tcx>, mono_items: I) -> PreInliningPartitioning<'tcx>
237+
fn place_root_mono_items<'tcx, I>(
238+
tcx: TyCtxt<'tcx>,
239+
mono_items: I,
240+
estimator: &mut SizeEstimator<'tcx>,
241+
) -> PreInliningPartitioning<'tcx>
217242
where
218243
I: Iterator<Item = MonoItem<'tcx>>,
219244
{
@@ -264,8 +289,8 @@ where
264289
if visibility == Visibility::Hidden && can_be_internalized {
265290
internalization_candidates.insert(mono_item);
266291
}
267-
268-
codegen_unit.items_mut().insert(mono_item, (linkage, visibility));
292+
let item_size = estimator.size_estimate(tcx, mono_item);
293+
codegen_unit.add_item(mono_item, (linkage, visibility), item_size);
269294
roots.insert(mono_item);
270295
}
271296

@@ -477,11 +502,12 @@ fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibilit
477502

478503
fn merge_codegen_units<'tcx>(
479504
tcx: TyCtxt<'tcx>,
480-
initial_partitioning: &mut PreInliningPartitioning<'tcx>,
505+
partitioning: &mut PostInliningPartitioning<'tcx>,
481506
target_cgu_count: usize,
507+
estimator: &mut SizeEstimator<'tcx>,
482508
) {
483509
assert!(target_cgu_count >= 1);
484-
let codegen_units = &mut initial_partitioning.codegen_units;
510+
let codegen_units = &mut partitioning.codegen_units;
485511

486512
// Note that at this point in time the `codegen_units` here may not be in a
487513
// deterministic order (but we know they're deterministically the same set).
@@ -501,9 +527,9 @@ fn merge_codegen_units<'tcx>(
501527
let mut smallest = codegen_units.pop().unwrap();
502528
let second_smallest = codegen_units.last_mut().unwrap();
503529

504-
second_smallest.modify_size_estimate(smallest.size_estimate());
505-
for (k, v) in smallest.items_mut().drain() {
506-
second_smallest.items_mut().insert(k, v);
530+
for (mono_item, v) in smallest.items_mut().drain() {
531+
let item_size = estimator.size_estimate(tcx, mono_item);
532+
second_smallest.add_item(mono_item, v, item_size);
507533
}
508534
debug!("CodegenUnit {} merged in to CodegenUnit {}",
509535
smallest.name(),
@@ -516,20 +542,19 @@ fn merge_codegen_units<'tcx>(
516542
}
517543
}
518544

519-
fn place_inlined_mono_items<'tcx>(initial_partitioning: PreInliningPartitioning<'tcx>,
520-
inlining_map: &InliningMap<'tcx>)
521-
-> PostInliningPartitioning<'tcx> {
545+
fn place_inlined_mono_items<'tcx>(tcx: TyCtxt<'tcx>,
546+
initial_partitioning: PreInliningPartitioning<'tcx>,
547+
inlining_map: &InliningMap<'tcx>,
548+
estimator: &mut SizeEstimator<'tcx>,
549+
) -> PostInliningPartitioning<'tcx> {
522550
let mut new_partitioning = Vec::new();
523-
let mut mono_item_placements = FxHashMap::default();
524551

525552
let PreInliningPartitioning {
526553
codegen_units: initial_cgus,
527554
roots,
528555
internalization_candidates,
529556
} = initial_partitioning;
530557

531-
let single_codegen_unit = initial_cgus.len() == 1;
532-
533558
for old_codegen_unit in initial_cgus {
534559
// Collect all items that need to be available in this codegen unit.
535560
let mut reachable = FxHashSet::default();
@@ -543,40 +568,20 @@ fn place_inlined_mono_items<'tcx>(initial_partitioning: PreInliningPartitioning<
543568
for mono_item in reachable {
544569
if let Some(linkage) = old_codegen_unit.items().get(&mono_item) {
545570
// This is a root, just copy it over.
546-
new_codegen_unit.items_mut().insert(mono_item, *linkage);
571+
let item_size = estimator.size_estimate(tcx, mono_item);
572+
new_codegen_unit.add_item(mono_item, *linkage, item_size);
547573
} else {
548574
if roots.contains(&mono_item) {
549575
bug!("GloballyShared mono-item inlined into other CGU: \
550576
{:?}", mono_item);
551577
}
552578

553579
// This is a CGU-private copy.
554-
new_codegen_unit.items_mut().insert(
580+
let item_size = estimator.size_estimate(tcx, mono_item);
581+
new_codegen_unit.add_item(
555582
mono_item,
556583
(Linkage::Internal, Visibility::Default),
557-
);
558-
}
559-
560-
if !single_codegen_unit {
561-
// If there is more than one codegen unit, we need to keep track
562-
// in which codegen units each monomorphization is placed.
563-
match mono_item_placements.entry(mono_item) {
564-
Entry::Occupied(e) => {
565-
let placement = e.into_mut();
566-
debug_assert!(match *placement {
567-
MonoItemPlacement::SingleCgu { ref cgu_name } => {
568-
*cgu_name != *new_codegen_unit.name()
569-
}
570-
MonoItemPlacement::MultipleCgus => true,
571-
});
572-
*placement = MonoItemPlacement::MultipleCgus;
573-
}
574-
Entry::Vacant(e) => {
575-
e.insert(MonoItemPlacement::SingleCgu {
576-
cgu_name: new_codegen_unit.name().clone()
577-
});
578-
}
579-
}
584+
item_size);
580585
}
581586
}
582587

@@ -585,7 +590,6 @@ fn place_inlined_mono_items<'tcx>(initial_partitioning: PreInliningPartitioning<
585590

586591
return PostInliningPartitioning {
587592
codegen_units: new_partitioning,
588-
mono_item_placements,
589593
internalization_candidates,
590594
};
591595

@@ -632,7 +636,24 @@ fn internalize_symbols<'tcx>(
632636
}
633637
});
634638

635-
let mono_item_placements = &partitioning.mono_item_placements;
639+
// If there is more than one codegen unit, we need to keep track
640+
// in which codegen units each monomorphization is placed.
641+
let mut mono_item_placements = FxHashMap::default();
642+
643+
for cgu in &partitioning.codegen_units {
644+
for mono_item in cgu.items().keys() {
645+
match mono_item_placements.entry(*mono_item) {
646+
Entry::Occupied(e) => {
647+
*e.into_mut() = MonoItemPlacement::MultipleCgus;
648+
}
649+
Entry::Vacant(e) => {
650+
e.insert(MonoItemPlacement::SingleCgu {
651+
cgu_name: cgu.name().clone()
652+
});
653+
}
654+
}
655+
}
656+
}
636657

637658
// For each internalization candidates in each codegen unit, check if it is
638659
// accessed from outside its defining codegen unit.
@@ -781,7 +802,10 @@ fn numbered_codegen_unit_name(
781802
name_builder.build_cgu_name_no_mangle(LOCAL_CRATE, &["cgu"], Some(index))
782803
}
783804

784-
fn debug_dump<'a, 'tcx, I>(tcx: TyCtxt<'tcx>, label: &str, cgus: I)
805+
fn debug_dump<'a, 'tcx, I>(tcx: TyCtxt<'tcx>,
806+
label: &str,
807+
cgus: I,
808+
estimator: &mut SizeEstimator<'tcx>)
785809
where
786810
I: Iterator<Item = &'a CodegenUnit<'tcx>>,
787811
'tcx: 'a,
@@ -801,7 +825,7 @@ where
801825
mono_item.to_string(tcx, true),
802826
linkage,
803827
symbol_hash,
804-
mono_item.size_estimate(tcx));
828+
estimator.size_estimate(tcx, *mono_item));
805829
}
806830

807831
debug!("");

0 commit comments

Comments
 (0)