@@ -126,11 +126,14 @@ struct PartitioningCx<'a, 'tcx> {
126
126
}
127
127
128
128
struct PlacedRootMonoItems < ' tcx > {
129
+ /// The codegen units, sorted by name to make things deterministic.
129
130
codegen_units : Vec < CodegenUnit < ' tcx > > ,
131
+
130
132
roots : FxHashSet < MonoItem < ' tcx > > ,
131
133
internalization_candidates : FxHashSet < MonoItem < ' tcx > > ,
132
134
}
133
135
136
+ // The output CGUs are sorted by name.
134
137
fn partition < ' tcx , I > (
135
138
tcx : TyCtxt < ' tcx > ,
136
139
mono_items : & mut I ,
@@ -143,6 +146,7 @@ where
143
146
let _prof_timer = tcx. prof . generic_activity ( "cgu_partitioning" ) ;
144
147
145
148
let cx = & PartitioningCx { tcx, target_cgu_count : max_cgu_count, inlining_map } ;
149
+
146
150
// In the first step, we place all regular monomorphizations into their
147
151
// respective 'home' codegen unit. Regular monomorphizations are all
148
152
// functions and statics defined in the local crate.
@@ -225,8 +229,8 @@ where
225
229
dead_code_cgu. make_code_coverage_dead_code_cgu ( ) ;
226
230
}
227
231
228
- // Finally, sort by codegen unit name, so that we get deterministic results.
229
- codegen_units. sort_by ( |a, b| a. name ( ) . as_str ( ) . cmp ( b. name ( ) . as_str ( ) ) ) ;
232
+ // Ensure CGUs are sorted by name, so that we get deterministic results.
233
+ assert ! ( codegen_units. is_sorted_by ( |a, b| Some ( a. name( ) . as_str( ) . cmp( b. name( ) . as_str( ) ) ) ) ) ;
230
234
231
235
debug_dump ( tcx, "FINAL" , & codegen_units) ;
232
236
@@ -301,27 +305,22 @@ where
301
305
codegen_units. insert ( codegen_unit_name, CodegenUnit :: new ( codegen_unit_name) ) ;
302
306
}
303
307
304
- let codegen_units = codegen_units. into_values ( ) . collect ( ) ;
308
+ let mut codegen_units: Vec < _ > = codegen_units. into_values ( ) . collect ( ) ;
309
+ codegen_units. sort_by ( |a, b| a. name ( ) . as_str ( ) . cmp ( b. name ( ) . as_str ( ) ) ) ;
310
+
305
311
PlacedRootMonoItems { codegen_units, roots, internalization_candidates }
306
312
}
307
313
314
+ // This function requires the CGUs to be sorted by name on input, and ensures
315
+ // they are sorted by name on return, for deterministic behaviour.
308
316
fn merge_codegen_units < ' tcx > (
309
317
cx : & PartitioningCx < ' _ , ' tcx > ,
310
318
codegen_units : & mut Vec < CodegenUnit < ' tcx > > ,
311
319
) {
312
320
assert ! ( cx. target_cgu_count >= 1 ) ;
313
321
314
- // Note that at this point in time the `codegen_units` here may not be
315
- // in a deterministic order (but we know they're deterministically the
316
- // same set). We want this merging to produce a deterministic ordering
317
- // of codegen units from the input.
318
- //
319
- // Due to basically how we've implemented the merging below (merge the
320
- // two smallest into each other) we're sure to start off with a
321
- // deterministic order (sorted by name). This'll mean that if two cgus
322
- // have the same size the stable sort below will keep everything nice
323
- // and deterministic.
324
- codegen_units. sort_by ( |a, b| a. name ( ) . as_str ( ) . cmp ( b. name ( ) . as_str ( ) ) ) ;
322
+ // A sorted order here ensures merging is deterministic.
323
+ assert ! ( codegen_units. is_sorted_by( |a, b| Some ( a. name( ) . as_str( ) . cmp( b. name( ) . as_str( ) ) ) ) ) ;
325
324
326
325
// This map keeps track of what got merged into what.
327
326
let mut cgu_contents: FxHashMap < Symbol , Vec < Symbol > > =
@@ -400,6 +399,9 @@ fn merge_codegen_units<'tcx>(
400
399
cgu. set_name ( numbered_codegen_unit_name) ;
401
400
}
402
401
}
402
+
403
+ // A sorted order here ensures what follows can be deterministic.
404
+ codegen_units. sort_by ( |a, b| a. name ( ) . as_str ( ) . cmp ( b. name ( ) . as_str ( ) ) ) ;
403
405
}
404
406
405
407
/// For symbol internalization, we need to know whether a symbol/mono-item is
@@ -859,36 +861,46 @@ fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibilit
859
861
_ => Visibility :: Hidden ,
860
862
}
861
863
}
864
+
862
865
fn debug_dump < ' a , ' tcx : ' a > ( tcx : TyCtxt < ' tcx > , label : & str , cgus : & [ CodegenUnit < ' tcx > ] ) {
863
866
let dump = move || {
864
867
use std:: fmt:: Write ;
865
868
866
869
let num_cgus = cgus. len ( ) ;
867
- let max = cgus. iter ( ) . map ( |cgu| cgu. size_estimate ( ) ) . max ( ) . unwrap ( ) ;
868
- let min = cgus. iter ( ) . map ( |cgu| cgu. size_estimate ( ) ) . min ( ) . unwrap ( ) ;
869
- let ratio = max as f64 / min as f64 ;
870
+ let num_items: usize = cgus. iter ( ) . map ( |cgu| cgu. items ( ) . len ( ) ) . sum ( ) ;
871
+ let total_size: usize = cgus. iter ( ) . map ( |cgu| cgu. size_estimate ( ) ) . sum ( ) ;
872
+ let max_size = cgus. iter ( ) . map ( |cgu| cgu. size_estimate ( ) ) . max ( ) . unwrap ( ) ;
873
+ let min_size = cgus. iter ( ) . map ( |cgu| cgu. size_estimate ( ) ) . min ( ) . unwrap ( ) ;
874
+ let max_min_size_ratio = max_size as f64 / min_size as f64 ;
870
875
871
876
let s = & mut String :: new ( ) ;
872
877
let _ = writeln ! (
873
878
s,
874
- "{label} ({num_cgus} CodegenUnits, max={max}, min={min}, max/min={ratio:.1}):"
879
+ "{label} ({num_items} items, total_size={total_size}; {num_cgus} CGUs, \
880
+ max_size={max_size}, min_size={min_size}, max_size/min_size={max_min_size_ratio:.1}):"
875
881
) ;
876
- for cgu in cgus {
877
- let _ =
878
- writeln ! ( s, "CodegenUnit {} estimated size {}:" , cgu. name( ) , cgu. size_estimate( ) ) ;
882
+ for ( i, cgu) in cgus. iter ( ) . enumerate ( ) {
883
+ let num_items = cgu. items ( ) . len ( ) ;
884
+ let _ = writeln ! (
885
+ s,
886
+ "- CGU[{i}] {} ({num_items} items, size={}):" ,
887
+ cgu. name( ) ,
888
+ cgu. size_estimate( )
889
+ ) ;
879
890
880
- for ( mono_item, linkage) in cgu. items ( ) {
881
- let symbol_name = mono_item. symbol_name ( tcx) . name ;
891
+ // The order of `cgu.items()` is non-deterministic; sort it by name
892
+ // to give deterministic output.
893
+ let mut items: Vec < _ > = cgu. items ( ) . iter ( ) . collect ( ) ;
894
+ items. sort_by_key ( |( item, _) | item. symbol_name ( tcx) . name ) ;
895
+ for ( item, linkage) in items {
896
+ let symbol_name = item. symbol_name ( tcx) . name ;
882
897
let symbol_hash_start = symbol_name. rfind ( 'h' ) ;
883
898
let symbol_hash = symbol_hash_start. map_or ( "<no hash>" , |i| & symbol_name[ i..] ) ;
884
899
900
+ let size = item. size_estimate ( tcx) ;
885
901
let _ = with_no_trimmed_paths ! ( writeln!(
886
902
s,
887
- " - {} [{:?}] [{}] estimated size {}" ,
888
- mono_item,
889
- linkage,
890
- symbol_hash,
891
- mono_item. size_estimate( tcx)
903
+ " - {item} [{linkage:?}] [{symbol_hash}] (size={size})"
892
904
) ) ;
893
905
}
894
906
0 commit comments