Skip to content

Commit

Permalink
Rollup merge of #106274 - jyn514:dump-mono-stats, r=lqd
Browse files Browse the repository at this point in the history
Add JSON output to -Zdump-mono-stats

Follow-up to #105481

r? `@lqd` cc `@wesleywiser`
  • Loading branch information
matthiaskrgr committed Jan 4, 2023
2 parents 70468af + 5c79624 commit fbfaeb6
Show file tree
Hide file tree
Showing 11 changed files with 111 additions and 26 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4243,6 +4243,8 @@ dependencies = [
"rustc_session",
"rustc_span",
"rustc_target",
"serde",
"serde_json",
"smallvec",
"tracing",
]
Expand Down
12 changes: 7 additions & 5 deletions compiler/rustc_interface/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,16 @@ use crate::interface::parse_cfgspecs;

use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig};
use rustc_session::config::InstrumentCoverage;
use rustc_session::config::Strip;
use rustc_session::config::rustc_optgroups;
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::{
BranchProtection, Externs, OomStrategy, OutputType, OutputTypes, PAuthKey, PacRet,
ProcMacroExecutionStrategy, SymbolManglingVersion, WasiExecModel,
};
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::search_paths::SearchPath;
use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
Expand Down Expand Up @@ -647,6 +646,9 @@ fn test_unstable_options_tracking_hash() {
untracked!(dump_mir_dir, String::from("abc"));
untracked!(dump_mir_exclude_pass_number, 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!(emit_stack_sizes, true);
untracked!(future_incompat_test, true);
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_monomorphize/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ edition = "2021"
[lib]

[dependencies]
serde = "1"
serde_json = "1"
smallvec = { version = "1.8.1", features = [ "union", "may_dangle" ] }
tracing = "0.1"
rustc_data_structures = { path = "../rustc_data_structures" }
Expand Down
54 changes: 35 additions & 19 deletions compiler/rustc_monomorphize/src/partitioning/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,14 @@ use std::path::{Path, PathBuf};

use rustc_data_structures::fx::{FxHashMap, FxHashSet};
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::mono::MonoItem;
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_session::config::{DumpMonoStatsFormat, SwitchWithOptPath};
use rustc_span::symbol::Symbol;

use crate::collector::InliningMap;
Expand Down Expand Up @@ -417,7 +417,7 @@ fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> (&DefIdSet, &[Co
// 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())
dump_mono_items_stats(tcx, &codegen_units, path, tcx.crate_name(LOCAL_CRATE))
{
tcx.sess.emit_fatal(CouldntDumpMonoStats { error: err.to_string() });
}
Expand Down Expand Up @@ -483,7 +483,7 @@ fn dump_mono_items_stats<'tcx>(
tcx: TyCtxt<'tcx>,
codegen_units: &[CodegenUnit<'tcx>],
output_directory: &Option<PathBuf>,
crate_name: Option<&str>,
crate_name: Symbol,
) -> Result<(), Box<dyn std::error::Error>> {
let output_directory = if let Some(ref directory) = output_directory {
fs::create_dir_all(directory)?;
Expand All @@ -492,9 +492,11 @@ fn dump_mono_items_stats<'tcx>(
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 file = File::create(output_path)?;
let file = File::create(&output_path)?;
let mut file = BufWriter::new(file);

// Gather instantiated mono items grouped by def_id
Expand All @@ -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
let mut stats: Vec<_> = items_per_def_id
.into_iter()
.map(|(def_id, items)| {
let name = with_no_trimmed_paths!(tcx.def_path_str(def_id));
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)
MonoItem { name, instantiation_count, size_estimate, total_estimate }
})
.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() {
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} |"
)?;
match format {
DumpMonoStatsFormat::Json => serde_json::to_writer(file, &stats)?,
DumpMonoStatsFormat::Markdown => {
writeln!(
file,
"| Item | Instantiation count | Estimated Cost Per Instantiation | Total Estimated Cost |"
)?;
writeln!(file, "| --- | ---: | ---: | ---: |")?;

for MonoItem { name, instantiation_count, size_estimate, total_estimate } in stats {
writeln!(
file,
"| `{name}` | {instantiation_count} | {size_estimate} | {total_estimate} |"
)?;
}
}
}
}

Expand Down
18 changes: 18 additions & 0 deletions compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2981,3 +2981,21 @@ pub enum ProcMacroExecutionStrategy {
/// Run the proc-macro code on a different thread.
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",
}
}
}
20 changes: 19 additions & 1 deletion compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,7 @@ mod desc {
pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of();
pub const parse_optimization_fuel: &str = "crate=integer";
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 =
"`all` (default), `except-unused-generics`, `except-unused-functions`, or `off`";
pub const parse_unpretty: &str = "`string` or `string=string`";
Expand Down Expand Up @@ -820,6 +821,21 @@ mod parse {
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(
slot: &mut Option<InstrumentCoverage>,
v: Option<&str>,
Expand Down Expand Up @@ -1295,7 +1311,9 @@ options! {
an additional `.html` file showing the computed coverage spans."),
dump_mono_stats: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
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],
"version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),
dylib_lto: bool = (false, parse_bool, [UNTRACKED],
Expand Down
Original file line number Diff line number Diff line change
@@ -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 changes: 14 additions & 0 deletions src/doc/unstable-book/src/compiler-flags/dump-mono-stats.md
Original file line number Diff line number Diff line change
@@ -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 changes: 5 additions & 0 deletions src/test/run-make/dump-mono-stats/Makefile
Original file line number Diff line number Diff line change
@@ -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 change: 1 addition & 0 deletions src/test/run-make/dump-mono-stats/foo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub fn bar() {}
3 changes: 2 additions & 1 deletion src/test/rustdoc-ui/z-help.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -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-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-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 dylib-lto=val -- enables LTO for dylib crate type
-Z emit-stack-sizes=val -- emit a section containing stack size metadata (default: no)
Expand Down

0 comments on commit fbfaeb6

Please sign in to comment.