9595mod default;
9696mod merging;
9797
98+ use std:: cmp;
99+ use std:: fs:: { self , File } ;
100+ use std:: io:: Write ;
101+ use std:: path:: { Path , PathBuf } ;
102+
98103use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
99104use rustc_data_structures:: sync;
100105use rustc_hir:: def_id:: DefIdSet ;
@@ -104,11 +109,12 @@ use rustc_middle::mir::mono::{CodegenUnit, Linkage};
104109use rustc_middle:: ty:: print:: with_no_trimmed_paths;
105110use rustc_middle:: ty:: query:: Providers ;
106111use rustc_middle:: ty:: TyCtxt ;
112+ use rustc_session:: config:: SwitchWithOptPath ;
107113use rustc_span:: symbol:: Symbol ;
108114
109115use crate :: collector:: InliningMap ;
110116use crate :: collector:: { self , MonoItemCollectionMode } ;
111- use crate :: errors:: { SymbolAlreadyDefined , UnknownPartitionStrategy } ;
117+ use crate :: errors:: { CouldntDumpMonoStats , SymbolAlreadyDefined , UnknownPartitionStrategy } ;
112118
113119pub struct PartitioningCx < ' a , ' tcx > {
114120 tcx : TyCtxt < ' tcx > ,
@@ -411,6 +417,15 @@ fn collect_and_partition_mono_items<'tcx>(
411417 } )
412418 . collect ( ) ;
413419
420+ // Output monomorphization stats per def_id
421+ if let SwitchWithOptPath :: Enabled ( ref path) = tcx. sess . opts . unstable_opts . dump_mono_stats {
422+ if let Err ( err) =
423+ dump_mono_items_stats ( tcx, & codegen_units, path, tcx. sess . opts . crate_name . as_deref ( ) )
424+ {
425+ tcx. sess . emit_fatal ( CouldntDumpMonoStats { error : err. to_string ( ) } ) ;
426+ }
427+ }
428+
414429 if tcx. sess . opts . unstable_opts . print_mono_items . is_some ( ) {
415430 let mut item_to_cgus: FxHashMap < _ , Vec < _ > > = Default :: default ( ) ;
416431
@@ -465,6 +480,66 @@ fn collect_and_partition_mono_items<'tcx>(
465480 ( tcx. arena . alloc ( mono_items) , codegen_units)
466481}
467482
483+ /// Outputs stats about instantation counts and estimated size, per `MonoItem`'s
484+ /// def, to a file in the given output directory.
485+ fn dump_mono_items_stats < ' tcx > (
486+ tcx : TyCtxt < ' tcx > ,
487+ codegen_units : & [ CodegenUnit < ' tcx > ] ,
488+ output_directory : & Option < PathBuf > ,
489+ crate_name : Option < & str > ,
490+ ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
491+ let output_directory = if let Some ( ref directory) = output_directory {
492+ fs:: create_dir_all ( directory) ?;
493+ directory
494+ } else {
495+ Path :: new ( "." )
496+ } ;
497+
498+ let filename = format ! ( "{}.mono_items.md" , crate_name. unwrap_or( "unknown-crate" ) ) ;
499+ let output_path = output_directory. join ( & filename) ;
500+ let mut file = File :: create ( output_path) ?;
501+
502+ // Gather instantiated mono items grouped by def_id
503+ let mut items_per_def_id: FxHashMap < _ , Vec < _ > > = Default :: default ( ) ;
504+ for cgu in codegen_units {
505+ for ( & mono_item, _) in cgu. items ( ) {
506+ // Avoid variable-sized compiler-generated shims
507+ if mono_item. is_user_defined ( ) {
508+ items_per_def_id. entry ( mono_item. def_id ( ) ) . or_default ( ) . push ( mono_item) ;
509+ }
510+ }
511+ }
512+
513+ // Output stats sorted by total instantiated size, from heaviest to lightest
514+ let mut stats: Vec < _ > = items_per_def_id
515+ . into_iter ( )
516+ . map ( |( def_id, items) | {
517+ let instantiation_count = items. len ( ) ;
518+ let size_estimate = items[ 0 ] . size_estimate ( tcx) ;
519+ let total_estimate = instantiation_count * size_estimate;
520+ ( def_id, instantiation_count, size_estimate, total_estimate)
521+ } )
522+ . collect ( ) ;
523+ stats. sort_unstable_by_key ( |( _, _, _, total_estimate) | cmp:: Reverse ( * total_estimate) ) ;
524+
525+ if !stats. is_empty ( ) {
526+ writeln ! (
527+ file,
528+ "| Item | Instantiation count | Estimated Cost Per Instantiation | Total Estimated Cost |"
529+ ) ?;
530+ writeln ! ( file, "| --- | ---: | ---: | ---: |" ) ?;
531+ for ( def_id, instantiation_count, size_estimate, total_estimate) in stats {
532+ let item = with_no_trimmed_paths ! ( tcx. def_path_str( def_id) ) ;
533+ writeln ! (
534+ file,
535+ "| {item} | {instantiation_count} | {size_estimate} | {total_estimate} |"
536+ ) ?;
537+ }
538+ }
539+
540+ Ok ( ( ) )
541+ }
542+
468543fn codegened_and_inlined_items < ' tcx > ( tcx : TyCtxt < ' tcx > , ( ) : ( ) ) -> & ' tcx DefIdSet {
469544 let ( items, cgus) = tcx. collect_and_partition_mono_items ( ( ) ) ;
470545 let mut visited = DefIdSet :: default ( ) ;
0 commit comments