Skip to content

Commit a465d97

Browse files
committed
locally caching the sizes of each mono-item
1 parent 0bbc9fa commit a465d97

File tree

2 files changed

+69
-50
lines changed

2 files changed

+69
-50
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

+59-22
Original file line numberDiff line numberDiff line change
@@ -136,15 +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.
142144
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-
debug_dump(tcx, "INITIAL PARTITIONING:", initial_partitioning.codegen_units.iter());
149+
debug_dump(
150+
tcx,
151+
"INITIAL PARTITIONING:",
152+
initial_partitioning.codegen_units.iter(),
153+
&mut estimator);
148154

149155
// In the next step, we use the inlining map to determine which additional
150156
// monomorphizations have to go into each codegen unit. These additional
@@ -153,19 +159,17 @@ where
153159
let mut post_inlining = {
154160
let _prof_timer =
155161
tcx.prof.generic_activity("cgu_partitioning_place_inline_items");
156-
place_inlined_mono_items(initial_partitioning, inlining_map)
162+
place_inlined_mono_items(tcx, initial_partitioning, inlining_map, &mut estimator)
157163
};
158164

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

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

171175
// Next we try to make as many symbols "internal" as possible, so LLVM has
@@ -189,6 +193,27 @@ where
189193
result
190194
}
191195

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+
192217
struct PreInliningPartitioning<'tcx> {
193218
codegen_units: Vec<CodegenUnit<'tcx>>,
194219
roots: FxHashSet<MonoItem<'tcx>>,
@@ -209,7 +234,11 @@ struct PostInliningPartitioning<'tcx> {
209234
internalization_candidates: FxHashSet<MonoItem<'tcx>>,
210235
}
211236

212-
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>
213242
where
214243
I: Iterator<Item = MonoItem<'tcx>>,
215244
{
@@ -260,8 +289,8 @@ where
260289
if visibility == Visibility::Hidden && can_be_internalized {
261290
internalization_candidates.insert(mono_item);
262291
}
263-
264-
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);
265294
roots.insert(mono_item);
266295
}
267296

@@ -475,6 +504,7 @@ fn merge_codegen_units<'tcx>(
475504
tcx: TyCtxt<'tcx>,
476505
partitioning: &mut PostInliningPartitioning<'tcx>,
477506
target_cgu_count: usize,
507+
estimator: &mut SizeEstimator<'tcx>,
478508
) {
479509
assert!(target_cgu_count >= 1);
480510
let codegen_units = &mut partitioning.codegen_units;
@@ -497,10 +527,10 @@ fn merge_codegen_units<'tcx>(
497527
let mut smallest = codegen_units.pop().unwrap();
498528
let second_smallest = codegen_units.last_mut().unwrap();
499529

500-
for (k, v) in smallest.items_mut().drain() {
501-
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);
502533
}
503-
second_smallest.estimate_size(tcx);
504534
debug!("CodegenUnit {} merged in to CodegenUnit {}",
505535
smallest.name(),
506536
second_smallest.name());
@@ -512,9 +542,11 @@ fn merge_codegen_units<'tcx>(
512542
}
513543
}
514544

515-
fn place_inlined_mono_items<'tcx>(initial_partitioning: PreInliningPartitioning<'tcx>,
516-
inlining_map: &InliningMap<'tcx>)
517-
-> 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> {
518550
let mut new_partitioning = Vec::new();
519551

520552
let PreInliningPartitioning {
@@ -536,18 +568,20 @@ fn place_inlined_mono_items<'tcx>(initial_partitioning: PreInliningPartitioning<
536568
for mono_item in reachable {
537569
if let Some(linkage) = old_codegen_unit.items().get(&mono_item) {
538570
// This is a root, just copy it over.
539-
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);
540573
} else {
541574
if roots.contains(&mono_item) {
542575
bug!("GloballyShared mono-item inlined into other CGU: \
543576
{:?}", mono_item);
544577
}
545578

546579
// This is a CGU-private copy.
547-
new_codegen_unit.items_mut().insert(
580+
let item_size = estimator.size_estimate(tcx, mono_item);
581+
new_codegen_unit.add_item(
548582
mono_item,
549583
(Linkage::Internal, Visibility::Default),
550-
);
584+
item_size);
551585
}
552586
}
553587

@@ -768,7 +802,10 @@ fn numbered_codegen_unit_name(
768802
name_builder.build_cgu_name_no_mangle(LOCAL_CRATE, &["cgu"], Some(index))
769803
}
770804

771-
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>)
772809
where
773810
I: Iterator<Item = &'a CodegenUnit<'tcx>>,
774811
'tcx: 'a,
@@ -788,7 +825,7 @@ where
788825
mono_item.to_string(tcx, true),
789826
linkage,
790827
symbol_hash,
791-
mono_item.size_estimate(tcx));
828+
estimator.size_estimate(tcx, *mono_item));
792829
}
793830

794831
debug!("");

0 commit comments

Comments
 (0)