Make stats code nicer.

Taking inspiration from `-Zmacro-stats`:
- Use "{prefix}" consistently.
- Use names for column widths.
- Write output in a single `eprint!` call, in an attempt to minimize
  interleaving of output from different rustc processes.
- Use `repeat` for the long `---` banners.
This commit is contained in:
Nicholas Nethercote
2025-06-24 10:11:52 +10:00
parent 111e9bc64b
commit 8b1abd6578
3 changed files with 62 additions and 30 deletions

View File

@@ -68,13 +68,13 @@ pub fn print_hir_stats(tcx: TyCtxt<'_>) {
collector.print("HIR STATS", "hir-stats");
}
pub fn print_ast_stats(krate: &ast::Crate, title: &str, prefix: &str) {
pub fn print_ast_stats(krate: &ast::Crate) {
use rustc_ast::visit::Visitor;
let mut collector =
StatCollector { tcx: None, nodes: FxHashMap::default(), seen: FxHashSet::default() };
collector.visit_crate(krate);
collector.print(title, prefix);
collector.print("POST EXPANSION AST STATS", "ast-stats");
}
impl<'k> StatCollector<'k> {
@@ -117,28 +117,45 @@ impl<'k> StatCollector<'k> {
}
fn print(&self, title: &str, prefix: &str) {
use std::fmt::Write;
// We will soon sort, so the initial order does not matter.
#[allow(rustc::potential_query_instability)]
let mut nodes: Vec<_> = self.nodes.iter().collect();
nodes.sort_by_cached_key(|(label, node)| (node.stats.accum_size(), label.to_owned()));
let name_w = 18;
let acc_size1_w = 10;
let acc_size2_w = 8; // " (NN.N%)"
let acc_size_w = acc_size1_w + acc_size2_w;
let count_w = 14;
let item_size_w = 14;
let banner_w = name_w + acc_size_w + count_w + item_size_w;
let total_size = nodes.iter().map(|(_, node)| node.stats.accum_size()).sum();
let total_count = nodes.iter().map(|(_, node)| node.stats.count).sum();
eprintln!("{prefix} {title}");
eprintln!(
"{} {:<18}{:>18}{:>14}{:>14}",
prefix, "Name", "Accumulated Size", "Count", "Item Size"
// We write all the text into a string and print it with a single
// `eprint!`. This is an attempt to minimize interleaved text if multiple
// rustc processes are printing macro-stats at the same time (e.g. with
// `RUSTFLAGS='-Zinput-stats' cargo build`). It still doesn't guarantee
// non-interleaving, though.
let mut s = String::new();
_ = writeln!(s, "{prefix} {title}");
_ = writeln!(
s,
"{prefix} {:<name_w$}{:>acc_size_w$}{:>count_w$}{:>item_size_w$}",
"Name", "Accumulated Size", "Count", "Item Size"
);
eprintln!("{prefix} ----------------------------------------------------------------");
_ = writeln!(s, "{prefix} {}", "-".repeat(banner_w));
let percent = |m, n| (m * 100) as f64 / n as f64;
for (label, node) in nodes {
let size = node.stats.accum_size();
eprintln!(
"{} {:<18}{:>10} ({:4.1}%){:>14}{:>14}",
prefix,
_ = writeln!(
s,
"{prefix} {:<name_w$}{:>acc_size1_w$} ({:4.1}%){:>count_w$}{:>item_size_w$}",
label,
usize_with_underscores(size),
percent(size, total_size),
@@ -155,9 +172,9 @@ impl<'k> StatCollector<'k> {
for (label, subnode) in subnodes {
let size = subnode.accum_size();
eprintln!(
"{} - {:<18}{:>10} ({:4.1}%){:>14}",
prefix,
_ = writeln!(
s,
"{prefix} - {:<name_w$}{:>acc_size1_w$} ({:4.1}%){:>count_w$}",
label,
usize_with_underscores(size),
percent(size, total_size),
@@ -166,15 +183,17 @@ impl<'k> StatCollector<'k> {
}
}
}
eprintln!("{prefix} ----------------------------------------------------------------");
eprintln!(
"{} {:<18}{:>10} {:>14}",
prefix,
_ = writeln!(s, "{prefix} {}", "-".repeat(banner_w));
_ = writeln!(
s,
"{prefix} {:<name_w$}{:>acc_size1_w$}{:>acc_size2_w$}{:>count_w$}",
"Total",
usize_with_underscores(total_size),
"",
usize_with_underscores(total_count),
);
eprintln!("{prefix}");
_ = writeln!(s, "{prefix}");
eprint!("{s}");
}
}