95
95
mod default;
96
96
mod merging;
97
97
98
+ use std:: cmp;
99
+ use std:: fs:: { self , File } ;
100
+ use std:: io:: Write ;
101
+ use std:: path:: { Path , PathBuf } ;
102
+
98
103
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
99
104
use rustc_data_structures:: sync;
100
105
use rustc_hir:: def_id:: DefIdSet ;
@@ -104,11 +109,12 @@ use rustc_middle::mir::mono::{CodegenUnit, Linkage};
104
109
use rustc_middle:: ty:: print:: with_no_trimmed_paths;
105
110
use rustc_middle:: ty:: query:: Providers ;
106
111
use rustc_middle:: ty:: TyCtxt ;
112
+ use rustc_session:: config:: SwitchWithOptPath ;
107
113
use rustc_span:: symbol:: Symbol ;
108
114
109
115
use crate :: collector:: InliningMap ;
110
116
use crate :: collector:: { self , MonoItemCollectionMode } ;
111
- use crate :: errors:: { SymbolAlreadyDefined , UnknownPartitionStrategy } ;
117
+ use crate :: errors:: { CouldntDumpMonoStats , SymbolAlreadyDefined , UnknownPartitionStrategy } ;
112
118
113
119
pub struct PartitioningCx < ' a , ' tcx > {
114
120
tcx : TyCtxt < ' tcx > ,
@@ -411,6 +417,15 @@ fn collect_and_partition_mono_items<'tcx>(
411
417
} )
412
418
. collect ( ) ;
413
419
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
+
414
429
if tcx. sess . opts . unstable_opts . print_mono_items . is_some ( ) {
415
430
let mut item_to_cgus: FxHashMap < _ , Vec < _ > > = Default :: default ( ) ;
416
431
@@ -465,6 +480,66 @@ fn collect_and_partition_mono_items<'tcx>(
465
480
( tcx. arena . alloc ( mono_items) , codegen_units)
466
481
}
467
482
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
+
468
543
fn codegened_and_inlined_items < ' tcx > ( tcx : TyCtxt < ' tcx > , ( ) : ( ) ) -> & ' tcx DefIdSet {
469
544
let ( items, cgus) = tcx. collect_and_partition_mono_items ( ( ) ) ;
470
545
let mut visited = DefIdSet :: default ( ) ;
0 commit comments