@@ -110,11 +110,12 @@ use rustc::mir::mono::{Linkage, Visibility};
110
110
use rustc:: ty:: { self , TyCtxt , InstanceDef } ;
111
111
use rustc:: ty:: item_path:: characteristic_def_id_of_type;
112
112
use rustc:: util:: nodemap:: { FxHashMap , FxHashSet } ;
113
- use std:: collections:: hash_map:: Entry ;
113
+ use std:: collections:: hash_map:: { HashMap , Entry } ;
114
114
use syntax:: ast:: NodeId ;
115
115
use syntax:: symbol:: { Symbol , InternedString } ;
116
116
use rustc:: mir:: mono:: MonoItem ;
117
117
use monomorphize:: item:: { MonoItemExt , InstantiationMode } ;
118
+ use core:: usize;
118
119
119
120
pub use rustc:: mir:: mono:: CodegenUnit ;
120
121
@@ -229,7 +230,7 @@ pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
229
230
// If the partitioning should produce a fixed count of codegen units, merge
230
231
// until that count is reached.
231
232
if let PartitioningStrategy :: FixedUnitCount ( count) = strategy {
232
- merge_codegen_units ( & mut initial_partitioning, count, & tcx. crate_name . as_str ( ) ) ;
233
+ merge_codegen_units ( tcx , & mut initial_partitioning, count, & tcx. crate_name . as_str ( ) ) ;
233
234
234
235
debug_dump ( tcx, "POST MERGING:" , initial_partitioning. codegen_units . iter ( ) ) ;
235
236
}
@@ -404,7 +405,8 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
404
405
}
405
406
}
406
407
407
- fn merge_codegen_units < ' tcx > ( initial_partitioning : & mut PreInliningPartitioning < ' tcx > ,
408
+ fn merge_codegen_units < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
409
+ initial_partitioning : & mut PreInliningPartitioning < ' tcx > ,
408
410
target_cgu_count : usize ,
409
411
crate_name : & str ) {
410
412
assert ! ( target_cgu_count >= 1 ) ;
@@ -421,12 +423,48 @@ fn merge_codegen_units<'tcx>(initial_partitioning: &mut PreInliningPartitioning<
421
423
// the stable sort below will keep everything nice and deterministic.
422
424
codegen_units. sort_by_key ( |cgu| cgu. name ( ) . clone ( ) ) ;
423
425
426
+ // Estimate the size of a codegen unit as (approximately) the number of MIR
427
+ // statements it corresponds to.
428
+ fn codegen_unit_size_estimate < ' a , ' tcx > ( cgu : & CodegenUnit < ' tcx > ,
429
+ mono_item_sizes : & HashMap < MonoItem , usize > )
430
+ -> usize {
431
+ cgu. items ( ) . keys ( ) . map ( |mi| mono_item_sizes. get ( mi) . unwrap ( ) ) . sum ( )
432
+ }
433
+
434
+ fn mono_item_size_estimate < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
435
+ item : & MonoItem < ' tcx > )
436
+ -> usize {
437
+ match item {
438
+ MonoItem :: Fn ( instance) => {
439
+ // Estimate the size of a function based on how many statements
440
+ // it contains.
441
+ let mir = tcx. instance_mir ( instance. def ) ;
442
+ mir. basic_blocks ( ) . iter ( ) . map ( |bb| bb. statements . len ( ) ) . sum ( )
443
+ } ,
444
+ // Conservatively estimate the size of a static declaration
445
+ // or assembly to be 1.
446
+ MonoItem :: Static ( _) | MonoItem :: GlobalAsm ( _) => 1 ,
447
+ }
448
+ }
449
+
450
+ // Since `sort_by_key` currently recomputes the keys for each comparison,
451
+ // we can save unnecessary recomputations by storing size estimates for
452
+ // each `MonoItem`. Storing estimates for `CodegenUnit` might be preferable,
453
+ // but its structure makes it awkward to use as a key and additionally their
454
+ // sizes change as the merging occurs, requiring the map to be updated.
455
+ let mut sizes: HashMap < MonoItem , usize > = HashMap :: new ( ) ;
456
+ for mis in codegen_units. iter ( ) . map ( |cgu| cgu. items ( ) . keys ( ) ) {
457
+ mis. for_each ( |mi| {
458
+ sizes. entry ( * mi) . or_insert_with ( || mono_item_size_estimate ( tcx, mi) ) ;
459
+ } ) ;
460
+ }
461
+
424
462
// Merge the two smallest codegen units until the target size is reached.
425
463
// Note that "size" is estimated here rather inaccurately as the number of
426
464
// translation items in a given unit. This could be improved on.
427
465
while codegen_units. len ( ) > target_cgu_count {
428
466
// Sort small cgus to the back
429
- codegen_units. sort_by_key ( |cgu| - ( cgu. items ( ) . len ( ) as i64 ) ) ;
467
+ codegen_units. sort_by_key ( |cgu| usize :: MAX - codegen_unit_size_estimate ( cgu, & sizes ) ) ;
430
468
let mut smallest = codegen_units. pop ( ) . unwrap ( ) ;
431
469
let second_smallest = codegen_units. last_mut ( ) . unwrap ( ) ;
432
470
0 commit comments