Rollup merge of #106274 - jyn514:dump-mono-stats, r=lqd
Add JSON output to -Zdump-mono-stats Follow-up to https://github.com/rust-lang/rust/pull/105481 r? `@lqd` cc `@wesleywiser`
This commit is contained in:
commit
fbfaeb6795
11 changed files with 111 additions and 26 deletions
|
@ -4243,6 +4243,8 @@ dependencies = [
|
||||||
"rustc_session",
|
"rustc_session",
|
||||||
"rustc_span",
|
"rustc_span",
|
||||||
"rustc_target",
|
"rustc_target",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
|
@ -3,17 +3,16 @@ use crate::interface::parse_cfgspecs;
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig};
|
use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig};
|
||||||
use rustc_session::config::InstrumentCoverage;
|
use rustc_session::config::rustc_optgroups;
|
||||||
use rustc_session::config::Strip;
|
|
||||||
use rustc_session::config::{build_configuration, build_session_options, to_crate_config};
|
use rustc_session::config::{build_configuration, build_session_options, to_crate_config};
|
||||||
use rustc_session::config::{
|
|
||||||
rustc_optgroups, ErrorOutputType, ExternLocation, LocationDetail, Options, Passes,
|
|
||||||
};
|
|
||||||
use rustc_session::config::{
|
use rustc_session::config::{
|
||||||
BranchProtection, Externs, OomStrategy, OutputType, OutputTypes, PAuthKey, PacRet,
|
BranchProtection, Externs, OomStrategy, OutputType, OutputTypes, PAuthKey, PacRet,
|
||||||
ProcMacroExecutionStrategy, SymbolManglingVersion, WasiExecModel,
|
ProcMacroExecutionStrategy, SymbolManglingVersion, WasiExecModel,
|
||||||
};
|
};
|
||||||
use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath};
|
use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath};
|
||||||
|
use rustc_session::config::{DumpMonoStatsFormat, MirSpanview};
|
||||||
|
use rustc_session::config::{ErrorOutputType, ExternLocation, LocationDetail, Options, Strip};
|
||||||
|
use rustc_session::config::{InstrumentCoverage, Passes};
|
||||||
use rustc_session::lint::Level;
|
use rustc_session::lint::Level;
|
||||||
use rustc_session::search_paths::SearchPath;
|
use rustc_session::search_paths::SearchPath;
|
||||||
use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
|
use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
|
||||||
|
@ -647,6 +646,9 @@ fn test_unstable_options_tracking_hash() {
|
||||||
untracked!(dump_mir_dir, String::from("abc"));
|
untracked!(dump_mir_dir, String::from("abc"));
|
||||||
untracked!(dump_mir_exclude_pass_number, true);
|
untracked!(dump_mir_exclude_pass_number, true);
|
||||||
untracked!(dump_mir_graphviz, true);
|
untracked!(dump_mir_graphviz, true);
|
||||||
|
untracked!(dump_mir_spanview, Some(MirSpanview::Statement));
|
||||||
|
untracked!(dump_mono_stats, SwitchWithOptPath::Enabled(Some("mono-items-dir/".into())));
|
||||||
|
untracked!(dump_mono_stats_format, DumpMonoStatsFormat::Json);
|
||||||
untracked!(dylib_lto, true);
|
untracked!(dylib_lto, true);
|
||||||
untracked!(emit_stack_sizes, true);
|
untracked!(emit_stack_sizes, true);
|
||||||
untracked!(future_incompat_test, true);
|
untracked!(future_incompat_test, true);
|
||||||
|
|
|
@ -6,6 +6,8 @@ edition = "2021"
|
||||||
[lib]
|
[lib]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
serde = "1"
|
||||||
|
serde_json = "1"
|
||||||
smallvec = { version = "1.8.1", features = [ "union", "may_dangle" ] }
|
smallvec = { version = "1.8.1", features = [ "union", "may_dangle" ] }
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||||
|
|
|
@ -102,14 +102,14 @@ use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
use rustc_data_structures::sync;
|
use rustc_data_structures::sync;
|
||||||
use rustc_hir::def_id::DefIdSet;
|
use rustc_hir::def_id::{DefIdSet, LOCAL_CRATE};
|
||||||
use rustc_middle::mir;
|
use rustc_middle::mir;
|
||||||
use rustc_middle::mir::mono::MonoItem;
|
use rustc_middle::mir::mono::MonoItem;
|
||||||
use rustc_middle::mir::mono::{CodegenUnit, Linkage};
|
use rustc_middle::mir::mono::{CodegenUnit, Linkage};
|
||||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||||
use rustc_middle::ty::query::Providers;
|
use rustc_middle::ty::query::Providers;
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_session::config::SwitchWithOptPath;
|
use rustc_session::config::{DumpMonoStatsFormat, SwitchWithOptPath};
|
||||||
use rustc_span::symbol::Symbol;
|
use rustc_span::symbol::Symbol;
|
||||||
|
|
||||||
use crate::collector::InliningMap;
|
use crate::collector::InliningMap;
|
||||||
|
@ -417,7 +417,7 @@ fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> (&DefIdSet, &[Co
|
||||||
// Output monomorphization stats per def_id
|
// Output monomorphization stats per def_id
|
||||||
if let SwitchWithOptPath::Enabled(ref path) = tcx.sess.opts.unstable_opts.dump_mono_stats {
|
if let SwitchWithOptPath::Enabled(ref path) = tcx.sess.opts.unstable_opts.dump_mono_stats {
|
||||||
if let Err(err) =
|
if let Err(err) =
|
||||||
dump_mono_items_stats(tcx, &codegen_units, path, tcx.sess.opts.crate_name.as_deref())
|
dump_mono_items_stats(tcx, &codegen_units, path, tcx.crate_name(LOCAL_CRATE))
|
||||||
{
|
{
|
||||||
tcx.sess.emit_fatal(CouldntDumpMonoStats { error: err.to_string() });
|
tcx.sess.emit_fatal(CouldntDumpMonoStats { error: err.to_string() });
|
||||||
}
|
}
|
||||||
|
@ -483,7 +483,7 @@ fn dump_mono_items_stats<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
codegen_units: &[CodegenUnit<'tcx>],
|
codegen_units: &[CodegenUnit<'tcx>],
|
||||||
output_directory: &Option<PathBuf>,
|
output_directory: &Option<PathBuf>,
|
||||||
crate_name: Option<&str>,
|
crate_name: Symbol,
|
||||||
) -> Result<(), Box<dyn std::error::Error>> {
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let output_directory = if let Some(ref directory) = output_directory {
|
let output_directory = if let Some(ref directory) = output_directory {
|
||||||
fs::create_dir_all(directory)?;
|
fs::create_dir_all(directory)?;
|
||||||
|
@ -492,9 +492,11 @@ fn dump_mono_items_stats<'tcx>(
|
||||||
Path::new(".")
|
Path::new(".")
|
||||||
};
|
};
|
||||||
|
|
||||||
let filename = format!("{}.mono_items.md", crate_name.unwrap_or("unknown-crate"));
|
let format = tcx.sess.opts.unstable_opts.dump_mono_stats_format;
|
||||||
|
let ext = format.extension();
|
||||||
|
let filename = format!("{crate_name}.mono_items.{ext}");
|
||||||
let output_path = output_directory.join(&filename);
|
let output_path = output_directory.join(&filename);
|
||||||
let file = File::create(output_path)?;
|
let file = File::create(&output_path)?;
|
||||||
let mut file = BufWriter::new(file);
|
let mut file = BufWriter::new(file);
|
||||||
|
|
||||||
// Gather instantiated mono items grouped by def_id
|
// Gather instantiated mono items grouped by def_id
|
||||||
|
@ -508,30 +510,44 @@ fn dump_mono_items_stats<'tcx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Serialize)]
|
||||||
|
struct MonoItem {
|
||||||
|
name: String,
|
||||||
|
instantiation_count: usize,
|
||||||
|
size_estimate: usize,
|
||||||
|
total_estimate: usize,
|
||||||
|
}
|
||||||
|
|
||||||
// Output stats sorted by total instantiated size, from heaviest to lightest
|
// Output stats sorted by total instantiated size, from heaviest to lightest
|
||||||
let mut stats: Vec<_> = items_per_def_id
|
let mut stats: Vec<_> = items_per_def_id
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(def_id, items)| {
|
.map(|(def_id, items)| {
|
||||||
|
let name = with_no_trimmed_paths!(tcx.def_path_str(def_id));
|
||||||
let instantiation_count = items.len();
|
let instantiation_count = items.len();
|
||||||
let size_estimate = items[0].size_estimate(tcx);
|
let size_estimate = items[0].size_estimate(tcx);
|
||||||
let total_estimate = instantiation_count * size_estimate;
|
let total_estimate = instantiation_count * size_estimate;
|
||||||
(def_id, instantiation_count, size_estimate, total_estimate)
|
MonoItem { name, instantiation_count, size_estimate, total_estimate }
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
stats.sort_unstable_by_key(|(_, _, _, total_estimate)| cmp::Reverse(*total_estimate));
|
stats.sort_unstable_by_key(|item| cmp::Reverse(item.total_estimate));
|
||||||
|
|
||||||
if !stats.is_empty() {
|
if !stats.is_empty() {
|
||||||
writeln!(
|
match format {
|
||||||
file,
|
DumpMonoStatsFormat::Json => serde_json::to_writer(file, &stats)?,
|
||||||
"| Item | Instantiation count | Estimated Cost Per Instantiation | Total Estimated Cost |"
|
DumpMonoStatsFormat::Markdown => {
|
||||||
)?;
|
writeln!(
|
||||||
writeln!(file, "| --- | ---: | ---: | ---: |")?;
|
file,
|
||||||
for (def_id, instantiation_count, size_estimate, total_estimate) in stats {
|
"| Item | Instantiation count | Estimated Cost Per Instantiation | Total Estimated Cost |"
|
||||||
let item = with_no_trimmed_paths!(tcx.def_path_str(def_id));
|
)?;
|
||||||
writeln!(
|
writeln!(file, "| --- | ---: | ---: | ---: |")?;
|
||||||
file,
|
|
||||||
"| {item} | {instantiation_count} | {size_estimate} | {total_estimate} |"
|
for MonoItem { name, instantiation_count, size_estimate, total_estimate } in stats {
|
||||||
)?;
|
writeln!(
|
||||||
|
file,
|
||||||
|
"| `{name}` | {instantiation_count} | {size_estimate} | {total_estimate} |"
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2981,3 +2981,21 @@ pub enum ProcMacroExecutionStrategy {
|
||||||
/// Run the proc-macro code on a different thread.
|
/// Run the proc-macro code on a different thread.
|
||||||
CrossThread,
|
CrossThread,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Which format to use for `-Z dump-mono-stats`
|
||||||
|
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
|
||||||
|
pub enum DumpMonoStatsFormat {
|
||||||
|
/// Pretty-print a markdown table
|
||||||
|
Markdown,
|
||||||
|
/// Emit structured JSON
|
||||||
|
Json,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DumpMonoStatsFormat {
|
||||||
|
pub fn extension(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Markdown => "md",
|
||||||
|
Self::Json => "json",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -377,6 +377,7 @@ mod desc {
|
||||||
pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of();
|
pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of();
|
||||||
pub const parse_optimization_fuel: &str = "crate=integer";
|
pub const parse_optimization_fuel: &str = "crate=integer";
|
||||||
pub const parse_mir_spanview: &str = "`statement` (default), `terminator`, or `block`";
|
pub const parse_mir_spanview: &str = "`statement` (default), `terminator`, or `block`";
|
||||||
|
pub const parse_dump_mono_stats: &str = "`markdown` (default) or `json`";
|
||||||
pub const parse_instrument_coverage: &str =
|
pub const parse_instrument_coverage: &str =
|
||||||
"`all` (default), `except-unused-generics`, `except-unused-functions`, or `off`";
|
"`all` (default), `except-unused-generics`, `except-unused-functions`, or `off`";
|
||||||
pub const parse_unpretty: &str = "`string` or `string=string`";
|
pub const parse_unpretty: &str = "`string` or `string=string`";
|
||||||
|
@ -820,6 +821,21 @@ mod parse {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn parse_dump_mono_stats(slot: &mut DumpMonoStatsFormat, v: Option<&str>) -> bool {
|
||||||
|
match v {
|
||||||
|
None => true,
|
||||||
|
Some("json") => {
|
||||||
|
*slot = DumpMonoStatsFormat::Json;
|
||||||
|
true
|
||||||
|
}
|
||||||
|
Some("markdown") => {
|
||||||
|
*slot = DumpMonoStatsFormat::Markdown;
|
||||||
|
true
|
||||||
|
}
|
||||||
|
Some(_) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn parse_instrument_coverage(
|
pub(crate) fn parse_instrument_coverage(
|
||||||
slot: &mut Option<InstrumentCoverage>,
|
slot: &mut Option<InstrumentCoverage>,
|
||||||
v: Option<&str>,
|
v: Option<&str>,
|
||||||
|
@ -1295,7 +1311,9 @@ options! {
|
||||||
an additional `.html` file showing the computed coverage spans."),
|
an additional `.html` file showing the computed coverage spans."),
|
||||||
dump_mono_stats: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
|
dump_mono_stats: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
|
||||||
parse_switch_with_opt_path, [UNTRACKED],
|
parse_switch_with_opt_path, [UNTRACKED],
|
||||||
"output statistics about monomorphization collection (format: markdown)"),
|
"output statistics about monomorphization collection"),
|
||||||
|
dump_mono_stats_format: DumpMonoStatsFormat = (DumpMonoStatsFormat::Markdown, parse_dump_mono_stats, [UNTRACKED],
|
||||||
|
"the format to use for -Z dump-mono-stats (`markdown` (default) or `json`)"),
|
||||||
dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED],
|
dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED],
|
||||||
"version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),
|
"version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),
|
||||||
dylib_lto: bool = (false, parse_bool, [UNTRACKED],
|
dylib_lto: bool = (false, parse_bool, [UNTRACKED],
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
# `dump-mono-stats-format`
|
||||||
|
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
The `-Z dump-mono-stats-format` compiler flag controls what file format to use for `-Z dump-mono-stats`.
|
||||||
|
The default is markdown; currently JSON is also supported. JSON can be useful for programatically manipulating the results (e.g. to find the item that took the longest to compile).
|
14
src/doc/unstable-book/src/compiler-flags/dump-mono-stats.md
Normal file
14
src/doc/unstable-book/src/compiler-flags/dump-mono-stats.md
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
# `dump-mono-stats`
|
||||||
|
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
The `-Z dump-mono-stats` compiler flag generates a file with a list of the monomorphized items in the current crate.
|
||||||
|
It is useful for investigating compile times.
|
||||||
|
|
||||||
|
It accepts an optional directory where the file will be located. If no directory is specified, the file will be placed in the current directory.
|
||||||
|
|
||||||
|
See also `-Z dump-mono-stats-format` and `-Z print-mono-items`. Unlike `print-mono-items`,
|
||||||
|
`dump-mono-stats` aggregates monomorphized items by definition and includes a size estimate of how
|
||||||
|
large the item is when codegened.
|
||||||
|
|
||||||
|
See <https://rustc-dev-guide.rust-lang.org/backend/monomorph.html> for an overview of monomorphized items.
|
5
src/test/run-make/dump-mono-stats/Makefile
Normal file
5
src/test/run-make/dump-mono-stats/Makefile
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
include ../../run-make-fulldeps/tools.mk
|
||||||
|
|
||||||
|
all:
|
||||||
|
$(RUSTC) --crate-type lib foo.rs -Z dump-mono-stats=$(TMPDIR) -Zdump-mono-stats-format=json
|
||||||
|
cat $(TMPDIR)/foo.mono_items.json | $(CGREP) '"name":"bar"'
|
1
src/test/run-make/dump-mono-stats/foo.rs
Normal file
1
src/test/run-make/dump-mono-stats/foo.rs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
pub fn bar() {}
|
|
@ -35,7 +35,8 @@
|
||||||
-Z dump-mir-exclude-pass-number=val -- exclude the pass number when dumping MIR (used in tests) (default: no)
|
-Z dump-mir-exclude-pass-number=val -- exclude the pass number when dumping MIR (used in tests) (default: no)
|
||||||
-Z dump-mir-graphviz=val -- in addition to `.mir` files, create graphviz `.dot` files (and with `-Z instrument-coverage`, also create a `.dot` file for the MIR-derived coverage graph) (default: no)
|
-Z dump-mir-graphviz=val -- in addition to `.mir` files, create graphviz `.dot` files (and with `-Z instrument-coverage`, also create a `.dot` file for the MIR-derived coverage graph) (default: no)
|
||||||
-Z dump-mir-spanview=val -- in addition to `.mir` files, create `.html` files to view spans for all `statement`s (including terminators), only `terminator` spans, or computed `block` spans (one span encompassing a block's terminator and all statements). If `-Z instrument-coverage` is also enabled, create an additional `.html` file showing the computed coverage spans.
|
-Z dump-mir-spanview=val -- in addition to `.mir` files, create `.html` files to view spans for all `statement`s (including terminators), only `terminator` spans, or computed `block` spans (one span encompassing a block's terminator and all statements). If `-Z instrument-coverage` is also enabled, create an additional `.html` file showing the computed coverage spans.
|
||||||
-Z dump-mono-stats=val -- output statistics about monomorphization collection (format: markdown)
|
-Z dump-mono-stats=val -- output statistics about monomorphization collection
|
||||||
|
-Z dump-mono-stats-format=val -- the format to use for -Z dump-mono-stats (`markdown` (default) or `json`)
|
||||||
-Z dwarf-version=val -- version of DWARF debug information to emit (default: 2 or 4, depending on platform)
|
-Z dwarf-version=val -- version of DWARF debug information to emit (default: 2 or 4, depending on platform)
|
||||||
-Z dylib-lto=val -- enables LTO for dylib crate type
|
-Z dylib-lto=val -- enables LTO for dylib crate type
|
||||||
-Z emit-stack-sizes=val -- emit a section containing stack size metadata (default: no)
|
-Z emit-stack-sizes=val -- emit a section containing stack size metadata (default: no)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue