@@ -126,11 +126,14 @@ struct PartitioningCx<'a, 'tcx> {
126126}
127127
128128struct PlacedRootMonoItems < ' tcx > {
129+ /// The codegen units, sorted by name to make things deterministic.
129130 codegen_units : Vec < CodegenUnit < ' tcx > > ,
131+
130132 roots : FxHashSet < MonoItem < ' tcx > > ,
131133 internalization_candidates : FxHashSet < MonoItem < ' tcx > > ,
132134}
133135
136+ // The output CGUs are sorted by name.
134137fn partition < ' tcx , I > (
135138 tcx : TyCtxt < ' tcx > ,
136139 mono_items : & mut I ,
@@ -143,6 +146,7 @@ where
143146 let _prof_timer = tcx. prof . generic_activity ( "cgu_partitioning" ) ;
144147
145148 let cx = & PartitioningCx { tcx, target_cgu_count : max_cgu_count, inlining_map } ;
149+
146150 // In the first step, we place all regular monomorphizations into their
147151 // respective 'home' codegen unit. Regular monomorphizations are all
148152 // functions and statics defined in the local crate.
@@ -225,8 +229,8 @@ where
225229 dead_code_cgu. make_code_coverage_dead_code_cgu ( ) ;
226230 }
227231
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( ) ) ) ) ) ;
230234
231235 debug_dump ( tcx, "FINAL" , & codegen_units) ;
232236
@@ -301,27 +305,22 @@ where
301305 codegen_units. insert ( codegen_unit_name, CodegenUnit :: new ( codegen_unit_name) ) ;
302306 }
303307
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+
305311 PlacedRootMonoItems { codegen_units, roots, internalization_candidates }
306312}
307313
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.
308316fn merge_codegen_units < ' tcx > (
309317 cx : & PartitioningCx < ' _ , ' tcx > ,
310318 codegen_units : & mut Vec < CodegenUnit < ' tcx > > ,
311319) {
312320 assert ! ( cx. target_cgu_count >= 1 ) ;
313321
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( ) ) ) ) ) ;
325324
326325 // This map keeps track of what got merged into what.
327326 let mut cgu_contents: FxHashMap < Symbol , Vec < Symbol > > =
@@ -400,6 +399,9 @@ fn merge_codegen_units<'tcx>(
400399 cgu. set_name ( numbered_codegen_unit_name) ;
401400 }
402401 }
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 ( ) ) ) ;
403405}
404406
405407/// 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
859861 _ => Visibility :: Hidden ,
860862 }
861863}
864+
862865fn debug_dump < ' a , ' tcx : ' a > ( tcx : TyCtxt < ' tcx > , label : & str , cgus : & [ CodegenUnit < ' tcx > ] ) {
863866 let dump = move || {
864867 use std:: fmt:: Write ;
865868
866869 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 ;
870875
871876 let s = & mut String :: new ( ) ;
872877 let _ = writeln ! (
873878 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}):"
875881 ) ;
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+ ) ;
879890
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 ;
882897 let symbol_hash_start = symbol_name. rfind ( 'h' ) ;
883898 let symbol_hash = symbol_hash_start. map_or ( "<no hash>" , |i| & symbol_name[ i..] ) ;
884899
900+ let size = item. size_estimate ( tcx) ;
885901 let _ = with_no_trimmed_paths ! ( writeln!(
886902 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})"
892904 ) ) ;
893905 }
894906
0 commit comments