Skip to content

Commit fbfaeb6

Browse files
authored
Rollup merge of #106274 - jyn514:dump-mono-stats, r=lqd
Add JSON output to -Zdump-mono-stats Follow-up to #105481 r? `@lqd` cc `@wesleywiser`
2 parents 70468af + 5c79624 commit fbfaeb6

File tree

11 files changed

+111
-26
lines changed

11 files changed

+111
-26
lines changed

Cargo.lock

+2
Original file line numberDiff line numberDiff line change
@@ -4243,6 +4243,8 @@ dependencies = [
42434243
"rustc_session",
42444244
"rustc_span",
42454245
"rustc_target",
4246+
"serde",
4247+
"serde_json",
42464248
"smallvec",
42474249
"tracing",
42484250
]

compiler/rustc_interface/src/tests.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,16 @@ use crate::interface::parse_cfgspecs;
33

44
use rustc_data_structures::fx::FxHashSet;
55
use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig};
6-
use rustc_session::config::InstrumentCoverage;
7-
use rustc_session::config::Strip;
6+
use rustc_session::config::rustc_optgroups;
87
use rustc_session::config::{build_configuration, build_session_options, to_crate_config};
9-
use rustc_session::config::{
10-
rustc_optgroups, ErrorOutputType, ExternLocation, LocationDetail, Options, Passes,
11-
};
128
use rustc_session::config::{
139
BranchProtection, Externs, OomStrategy, OutputType, OutputTypes, PAuthKey, PacRet,
1410
ProcMacroExecutionStrategy, SymbolManglingVersion, WasiExecModel,
1511
};
1612
use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath};
13+
use rustc_session::config::{DumpMonoStatsFormat, MirSpanview};
14+
use rustc_session::config::{ErrorOutputType, ExternLocation, LocationDetail, Options, Strip};
15+
use rustc_session::config::{InstrumentCoverage, Passes};
1716
use rustc_session::lint::Level;
1817
use rustc_session::search_paths::SearchPath;
1918
use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
@@ -647,6 +646,9 @@ fn test_unstable_options_tracking_hash() {
647646
untracked!(dump_mir_dir, String::from("abc"));
648647
untracked!(dump_mir_exclude_pass_number, true);
649648
untracked!(dump_mir_graphviz, true);
649+
untracked!(dump_mir_spanview, Some(MirSpanview::Statement));
650+
untracked!(dump_mono_stats, SwitchWithOptPath::Enabled(Some("mono-items-dir/".into())));
651+
untracked!(dump_mono_stats_format, DumpMonoStatsFormat::Json);
650652
untracked!(dylib_lto, true);
651653
untracked!(emit_stack_sizes, true);
652654
untracked!(future_incompat_test, true);

compiler/rustc_monomorphize/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ edition = "2021"
66
[lib]
77

88
[dependencies]
9+
serde = "1"
10+
serde_json = "1"
911
smallvec = { version = "1.8.1", features = [ "union", "may_dangle" ] }
1012
tracing = "0.1"
1113
rustc_data_structures = { path = "../rustc_data_structures" }

compiler/rustc_monomorphize/src/partitioning/mod.rs

+35-19
Original file line numberDiff line numberDiff line change
@@ -102,14 +102,14 @@ use std::path::{Path, PathBuf};
102102

103103
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
104104
use rustc_data_structures::sync;
105-
use rustc_hir::def_id::DefIdSet;
105+
use rustc_hir::def_id::{DefIdSet, LOCAL_CRATE};
106106
use rustc_middle::mir;
107107
use rustc_middle::mir::mono::MonoItem;
108108
use rustc_middle::mir::mono::{CodegenUnit, Linkage};
109109
use rustc_middle::ty::print::with_no_trimmed_paths;
110110
use rustc_middle::ty::query::Providers;
111111
use rustc_middle::ty::TyCtxt;
112-
use rustc_session::config::SwitchWithOptPath;
112+
use rustc_session::config::{DumpMonoStatsFormat, SwitchWithOptPath};
113113
use rustc_span::symbol::Symbol;
114114

115115
use crate::collector::InliningMap;
@@ -417,7 +417,7 @@ fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> (&DefIdSet, &[Co
417417
// Output monomorphization stats per def_id
418418
if let SwitchWithOptPath::Enabled(ref path) = tcx.sess.opts.unstable_opts.dump_mono_stats {
419419
if let Err(err) =
420-
dump_mono_items_stats(tcx, &codegen_units, path, tcx.sess.opts.crate_name.as_deref())
420+
dump_mono_items_stats(tcx, &codegen_units, path, tcx.crate_name(LOCAL_CRATE))
421421
{
422422
tcx.sess.emit_fatal(CouldntDumpMonoStats { error: err.to_string() });
423423
}
@@ -483,7 +483,7 @@ fn dump_mono_items_stats<'tcx>(
483483
tcx: TyCtxt<'tcx>,
484484
codegen_units: &[CodegenUnit<'tcx>],
485485
output_directory: &Option<PathBuf>,
486-
crate_name: Option<&str>,
486+
crate_name: Symbol,
487487
) -> Result<(), Box<dyn std::error::Error>> {
488488
let output_directory = if let Some(ref directory) = output_directory {
489489
fs::create_dir_all(directory)?;
@@ -492,9 +492,11 @@ fn dump_mono_items_stats<'tcx>(
492492
Path::new(".")
493493
};
494494

495-
let filename = format!("{}.mono_items.md", crate_name.unwrap_or("unknown-crate"));
495+
let format = tcx.sess.opts.unstable_opts.dump_mono_stats_format;
496+
let ext = format.extension();
497+
let filename = format!("{crate_name}.mono_items.{ext}");
496498
let output_path = output_directory.join(&filename);
497-
let file = File::create(output_path)?;
499+
let file = File::create(&output_path)?;
498500
let mut file = BufWriter::new(file);
499501

500502
// Gather instantiated mono items grouped by def_id
@@ -508,30 +510,44 @@ fn dump_mono_items_stats<'tcx>(
508510
}
509511
}
510512

513+
#[derive(serde::Serialize)]
514+
struct MonoItem {
515+
name: String,
516+
instantiation_count: usize,
517+
size_estimate: usize,
518+
total_estimate: usize,
519+
}
520+
511521
// Output stats sorted by total instantiated size, from heaviest to lightest
512522
let mut stats: Vec<_> = items_per_def_id
513523
.into_iter()
514524
.map(|(def_id, items)| {
525+
let name = with_no_trimmed_paths!(tcx.def_path_str(def_id));
515526
let instantiation_count = items.len();
516527
let size_estimate = items[0].size_estimate(tcx);
517528
let total_estimate = instantiation_count * size_estimate;
518-
(def_id, instantiation_count, size_estimate, total_estimate)
529+
MonoItem { name, instantiation_count, size_estimate, total_estimate }
519530
})
520531
.collect();
521-
stats.sort_unstable_by_key(|(_, _, _, total_estimate)| cmp::Reverse(*total_estimate));
532+
stats.sort_unstable_by_key(|item| cmp::Reverse(item.total_estimate));
522533

523534
if !stats.is_empty() {
524-
writeln!(
525-
file,
526-
"| Item | Instantiation count | Estimated Cost Per Instantiation | Total Estimated Cost |"
527-
)?;
528-
writeln!(file, "| --- | ---: | ---: | ---: |")?;
529-
for (def_id, instantiation_count, size_estimate, total_estimate) in stats {
530-
let item = with_no_trimmed_paths!(tcx.def_path_str(def_id));
531-
writeln!(
532-
file,
533-
"| {item} | {instantiation_count} | {size_estimate} | {total_estimate} |"
534-
)?;
535+
match format {
536+
DumpMonoStatsFormat::Json => serde_json::to_writer(file, &stats)?,
537+
DumpMonoStatsFormat::Markdown => {
538+
writeln!(
539+
file,
540+
"| Item | Instantiation count | Estimated Cost Per Instantiation | Total Estimated Cost |"
541+
)?;
542+
writeln!(file, "| --- | ---: | ---: | ---: |")?;
543+
544+
for MonoItem { name, instantiation_count, size_estimate, total_estimate } in stats {
545+
writeln!(
546+
file,
547+
"| `{name}` | {instantiation_count} | {size_estimate} | {total_estimate} |"
548+
)?;
549+
}
550+
}
535551
}
536552
}
537553

compiler/rustc_session/src/config.rs

+18
Original file line numberDiff line numberDiff line change
@@ -2981,3 +2981,21 @@ pub enum ProcMacroExecutionStrategy {
29812981
/// Run the proc-macro code on a different thread.
29822982
CrossThread,
29832983
}
2984+
2985+
/// Which format to use for `-Z dump-mono-stats`
2986+
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
2987+
pub enum DumpMonoStatsFormat {
2988+
/// Pretty-print a markdown table
2989+
Markdown,
2990+
/// Emit structured JSON
2991+
Json,
2992+
}
2993+
2994+
impl DumpMonoStatsFormat {
2995+
pub fn extension(self) -> &'static str {
2996+
match self {
2997+
Self::Markdown => "md",
2998+
Self::Json => "json",
2999+
}
3000+
}
3001+
}

compiler/rustc_session/src/options.rs

+19-1
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ mod desc {
377377
pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of();
378378
pub const parse_optimization_fuel: &str = "crate=integer";
379379
pub const parse_mir_spanview: &str = "`statement` (default), `terminator`, or `block`";
380+
pub const parse_dump_mono_stats: &str = "`markdown` (default) or `json`";
380381
pub const parse_instrument_coverage: &str =
381382
"`all` (default), `except-unused-generics`, `except-unused-functions`, or `off`";
382383
pub const parse_unpretty: &str = "`string` or `string=string`";
@@ -820,6 +821,21 @@ mod parse {
820821
true
821822
}
822823

824+
pub(crate) fn parse_dump_mono_stats(slot: &mut DumpMonoStatsFormat, v: Option<&str>) -> bool {
825+
match v {
826+
None => true,
827+
Some("json") => {
828+
*slot = DumpMonoStatsFormat::Json;
829+
true
830+
}
831+
Some("markdown") => {
832+
*slot = DumpMonoStatsFormat::Markdown;
833+
true
834+
}
835+
Some(_) => false,
836+
}
837+
}
838+
823839
pub(crate) fn parse_instrument_coverage(
824840
slot: &mut Option<InstrumentCoverage>,
825841
v: Option<&str>,
@@ -1295,7 +1311,9 @@ options! {
12951311
an additional `.html` file showing the computed coverage spans."),
12961312
dump_mono_stats: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
12971313
parse_switch_with_opt_path, [UNTRACKED],
1298-
"output statistics about monomorphization collection (format: markdown)"),
1314+
"output statistics about monomorphization collection"),
1315+
dump_mono_stats_format: DumpMonoStatsFormat = (DumpMonoStatsFormat::Markdown, parse_dump_mono_stats, [UNTRACKED],
1316+
"the format to use for -Z dump-mono-stats (`markdown` (default) or `json`)"),
12991317
dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED],
13001318
"version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),
13011319
dylib_lto: bool = (false, parse_bool, [UNTRACKED],
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# `dump-mono-stats-format`
2+
3+
--------------------
4+
5+
The `-Z dump-mono-stats-format` compiler flag controls what file format to use for `-Z dump-mono-stats`.
6+
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).
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# `dump-mono-stats`
2+
3+
--------------------
4+
5+
The `-Z dump-mono-stats` compiler flag generates a file with a list of the monomorphized items in the current crate.
6+
It is useful for investigating compile times.
7+
8+
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.
9+
10+
See also `-Z dump-mono-stats-format` and `-Z print-mono-items`. Unlike `print-mono-items`,
11+
`dump-mono-stats` aggregates monomorphized items by definition and includes a size estimate of how
12+
large the item is when codegened.
13+
14+
See <https://rustc-dev-guide.rust-lang.org/backend/monomorph.html> for an overview of monomorphized items.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
include ../../run-make-fulldeps/tools.mk
2+
3+
all:
4+
$(RUSTC) --crate-type lib foo.rs -Z dump-mono-stats=$(TMPDIR) -Zdump-mono-stats-format=json
5+
cat $(TMPDIR)/foo.mono_items.json | $(CGREP) '"name":"bar"'
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub fn bar() {}

src/test/rustdoc-ui/z-help.stdout

+2-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@
3535
-Z dump-mir-exclude-pass-number=val -- exclude the pass number when dumping MIR (used in tests) (default: no)
3636
-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)
3737
-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.
38-
-Z dump-mono-stats=val -- output statistics about monomorphization collection (format: markdown)
38+
-Z dump-mono-stats=val -- output statistics about monomorphization collection
39+
-Z dump-mono-stats-format=val -- the format to use for -Z dump-mono-stats (`markdown` (default) or `json`)
3940
-Z dwarf-version=val -- version of DWARF debug information to emit (default: 2 or 4, depending on platform)
4041
-Z dylib-lto=val -- enables LTO for dylib crate type
4142
-Z emit-stack-sizes=val -- emit a section containing stack size metadata (default: no)

0 commit comments

Comments
 (0)