about summary refs log tree commit diff
path: root/compiler/rustc_monomorphize/src
diff options
context:
space:
mode:
authorRémy Rakic <remy.rakic+github@gmail.com>2022-12-08 19:21:08 +0000
committerRémy Rakic <remy.rakic+github@gmail.com>2022-12-14 20:17:52 +0000
commit7611933e6af6909dbfb4f38596f8fdd4e3b57a8d (patch)
tree72d90033498731f96dccacc68213339266f4107a /compiler/rustc_monomorphize/src
parent74f4da44a5743e88ce2bbb76f585c02e67af83a1 (diff)
downloadrust-7611933e6af6909dbfb4f38596f8fdd4e3b57a8d.tar.gz
rust-7611933e6af6909dbfb4f38596f8fdd4e3b57a8d.zip
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.
Diffstat (limited to 'compiler/rustc_monomorphize/src')
-rw-r--r--compiler/rustc_monomorphize/src/errors.rs6
-rw-r--r--compiler/rustc_monomorphize/src/partitioning/mod.rs77
2 files changed, 82 insertions, 1 deletions
diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs
index f1ca72de8db..f15cf54718e 100644
--- a/compiler/rustc_monomorphize/src/errors.rs
+++ b/compiler/rustc_monomorphize/src/errors.rs
@@ -77,3 +77,9 @@ pub struct SymbolAlreadyDefined {
     pub span: Option<Span>,
     pub symbol: String,
 }
+
+#[derive(Diagnostic)]
+#[diag(monomorphize_couldnt_dump_mono_stats)]
+pub struct CouldntDumpMonoStats {
+    pub error: String,
+}
diff --git a/compiler/rustc_monomorphize/src/partitioning/mod.rs b/compiler/rustc_monomorphize/src/partitioning/mod.rs
index 932edc6675f..fef8c9d1634 100644
--- a/compiler/rustc_monomorphize/src/partitioning/mod.rs
+++ b/compiler/rustc_monomorphize/src/partitioning/mod.rs
@@ -95,6 +95,11 @@
 mod default;
 mod merging;
 
+use std::cmp;
+use std::fs::{self, File};
+use std::io::Write;
+use std::path::{Path, PathBuf};
+
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync;
 use rustc_hir::def_id::DefIdSet;
@@ -104,11 +109,12 @@ use rustc_middle::mir::mono::{CodegenUnit, Linkage};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
+use rustc_session::config::SwitchWithOptPath;
 use rustc_span::symbol::Symbol;
 
 use crate::collector::InliningMap;
 use crate::collector::{self, MonoItemCollectionMode};
-use crate::errors::{SymbolAlreadyDefined, UnknownPartitionStrategy};
+use crate::errors::{CouldntDumpMonoStats, SymbolAlreadyDefined, UnknownPartitionStrategy};
 
 pub struct PartitioningCx<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
@@ -411,6 +417,15 @@ fn collect_and_partition_mono_items<'tcx>(
         })
         .collect();
 
+    // Output monomorphization stats per def_id
+    if let SwitchWithOptPath::Enabled(ref path) = tcx.sess.opts.unstable_opts.dump_mono_stats {
+        if let Err(err) =
+            dump_mono_items_stats(tcx, &codegen_units, path, tcx.sess.opts.crate_name.as_deref())
+        {
+            tcx.sess.emit_fatal(CouldntDumpMonoStats { error: err.to_string() });
+        }
+    }
+
     if tcx.sess.opts.unstable_opts.print_mono_items.is_some() {
         let mut item_to_cgus: FxHashMap<_, Vec<_>> = Default::default();
 
@@ -465,6 +480,66 @@ fn collect_and_partition_mono_items<'tcx>(
     (tcx.arena.alloc(mono_items), codegen_units)
 }
 
+/// Outputs stats about instantation counts and estimated size, per `MonoItem`'s
+/// def, to a file in the given output directory.
+fn dump_mono_items_stats<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    codegen_units: &[CodegenUnit<'tcx>],
+    output_directory: &Option<PathBuf>,
+    crate_name: Option<&str>,
+) -> Result<(), Box<dyn std::error::Error>> {
+    let output_directory = if let Some(ref directory) = output_directory {
+        fs::create_dir_all(directory)?;
+        directory
+    } else {
+        Path::new(".")
+    };
+
+    let filename = format!("{}.mono_items.md", crate_name.unwrap_or("unknown-crate"));
+    let output_path = output_directory.join(&filename);
+    let mut file = File::create(output_path)?;
+
+    // Gather instantiated mono items grouped by def_id
+    let mut items_per_def_id: FxHashMap<_, Vec<_>> = Default::default();
+    for cgu in codegen_units {
+        for (&mono_item, _) in cgu.items() {
+            // Avoid variable-sized compiler-generated shims
+            if mono_item.is_user_defined() {
+                items_per_def_id.entry(mono_item.def_id()).or_default().push(mono_item);
+            }
+        }
+    }
+
+    // Output stats sorted by total instantiated size, from heaviest to lightest
+    let mut stats: Vec<_> = items_per_def_id
+        .into_iter()
+        .map(|(def_id, items)| {
+            let instantiation_count = items.len();
+            let size_estimate = items[0].size_estimate(tcx);
+            let total_estimate = instantiation_count * size_estimate;
+            (def_id, instantiation_count, size_estimate, total_estimate)
+        })
+        .collect();
+    stats.sort_unstable_by_key(|(_, _, _, total_estimate)| cmp::Reverse(*total_estimate));
+
+    if !stats.is_empty() {
+        writeln!(
+            file,
+            "| Item | Instantiation count | Estimated Cost Per Instantiation | Total Estimated Cost |"
+        )?;
+        writeln!(file, "| --- | ---: | ---: | ---: |")?;
+        for (def_id, instantiation_count, size_estimate, total_estimate) in stats {
+            let item = with_no_trimmed_paths!(tcx.def_path_str(def_id));
+            writeln!(
+                file,
+                "| {item} | {instantiation_count} | {size_estimate} | {total_estimate} |"
+            )?;
+        }
+    }
+
+    Ok(())
+}
+
 fn codegened_and_inlined_items<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> &'tcx DefIdSet {
     let (items, cgus) = tcx.collect_and_partition_mono_items(());
     let mut visited = DefIdSet::default();