Skip to content

Commit 7611933

Browse files
committed
add -Z dump-mono-stats
This option will output some stats from the monomorphization collection pass to a file, to show estimated sizes from each instantiation.
1 parent 74f4da4 commit 7611933

File tree

4 files changed

+88
-1
lines changed

4 files changed

+88
-1
lines changed

compiler/rustc_error_messages/locales/en-US/monomorphize.ftl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,6 @@ monomorphize_large_assignments =
2121
moving {$size} bytes
2222
.label = value moved from here
2323
.note = The current maximum size is {$limit}, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
24+
25+
monomorphize_couldnt_dump_mono_stats =
26+
unexpected error occurred while dumping monomorphization stats: {$error}

compiler/rustc_monomorphize/src/errors.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,9 @@ pub struct SymbolAlreadyDefined {
7777
pub span: Option<Span>,
7878
pub symbol: String,
7979
}
80+
81+
#[derive(Diagnostic)]
82+
#[diag(monomorphize_couldnt_dump_mono_stats)]
83+
pub struct CouldntDumpMonoStats {
84+
pub error: String,
85+
}

compiler/rustc_monomorphize/src/partitioning/mod.rs

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,11 @@
9595
mod default;
9696
mod merging;
9797

98+
use std::cmp;
99+
use std::fs::{self, File};
100+
use std::io::Write;
101+
use std::path::{Path, PathBuf};
102+
98103
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
99104
use rustc_data_structures::sync;
100105
use rustc_hir::def_id::DefIdSet;
@@ -104,11 +109,12 @@ use rustc_middle::mir::mono::{CodegenUnit, Linkage};
104109
use rustc_middle::ty::print::with_no_trimmed_paths;
105110
use rustc_middle::ty::query::Providers;
106111
use rustc_middle::ty::TyCtxt;
112+
use rustc_session::config::SwitchWithOptPath;
107113
use rustc_span::symbol::Symbol;
108114

109115
use crate::collector::InliningMap;
110116
use crate::collector::{self, MonoItemCollectionMode};
111-
use crate::errors::{SymbolAlreadyDefined, UnknownPartitionStrategy};
117+
use crate::errors::{CouldntDumpMonoStats, SymbolAlreadyDefined, UnknownPartitionStrategy};
112118

113119
pub 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+
468543
fn 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();

compiler/rustc_session/src/options.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,6 +1294,9 @@ options! {
12941294
computed `block` spans (one span encompassing a block's terminator and \
12951295
all statements). If `-Z instrument-coverage` is also enabled, create \
12961296
an additional `.html` file showing the computed coverage spans."),
1297+
dump_mono_stats: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
1298+
parse_switch_with_opt_path, [UNTRACKED],
1299+
"output statistics about monomorphization collection (format: markdown)"),
12971300
dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED],
12981301
"version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),
12991302
dylib_lto: bool = (false, parse_bool, [UNTRACKED],

0 commit comments

Comments
 (0)