Improve AST stat collector.

This commit:
- Adds a comment explaining which `visit_*` methods should be
  implemented.
- Adds and removes some `visit_*` methods accordingly, improving
  coverage, and avoiding some double counting.
This commit is contained in:
Nicholas Nethercote 2022-08-11 12:18:21 +10:00
parent bf20777d13
commit 288b6672be
2 changed files with 81 additions and 18 deletions

View File

@ -26,6 +26,23 @@ struct NodeData {
size: usize,
}
/// This type measures the size of AST and HIR nodes, by implementing the AST
/// and HIR `Visitor` traits. But we don't measure every visited type because
/// that could cause double counting.
///
/// For example, `ast::Visitor` has `visit_ident`, but `Ident`s are always
/// stored inline within other AST nodes, so we don't implement `visit_ident`
/// here. In constrast, we do implement `visit_expr` because `ast::Expr` is
/// always stored as `P<ast::Expr>`, and every such expression should be
/// measured separately.
///
/// In general, a `visit_foo` method should be implemented here if the
/// corresponding `Foo` type is always stored on its own, e.g.: `P<Foo>`,
/// `Box<Foo>`, `Vec<Foo>`, `Box<[Foo]>`.
///
/// There are some types in the AST and HIR tree that the visitors do not have
/// a `visit_*` method for, and so we cannot measure these, which is
/// unfortunate.
struct StatCollector<'k> {
krate: Option<Map<'k>>,
data: FxHashMap<&'static str, NodeData>,
@ -44,9 +61,11 @@ pub fn print_hir_stats(tcx: TyCtxt<'_>) {
}
pub fn print_ast_stats(krate: &ast::Crate, title: &str) {
use rustc_ast::visit::Visitor;
let mut collector =
StatCollector { krate: None, data: FxHashMap::default(), seen: FxHashSet::default() };
ast_visit::walk_crate(&mut collector, krate);
collector.visit_crate(krate);
collector.print(title);
}
@ -228,6 +247,10 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
hir_visit::walk_path(self, path)
}
// `PathSegment` has one inline use (in `ast::ExprKind::MethodCall`) and
// one non-inline use (in `Path::segments`). The latter case is more common
// than the former case, so we implement this visitor and tolerate the
// double counting in the former case.
fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v hir::PathSegment<'v>) {
self.record("PathSegment", Id::None, path_segment);
hir_visit::walk_path_segment(self, path_span, path_segment)
@ -269,6 +292,11 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
ast_visit::walk_stmt(self, s)
}
fn visit_param(&mut self, p: &'v ast::Param) {
self.record("Param", Id::None, p);
ast_visit::walk_param(self, p)
}
fn visit_arm(&mut self, a: &'v ast::Arm) {
self.record("Arm", Id::None, a);
ast_visit::walk_arm(self, a)
@ -289,6 +317,16 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
ast_visit::walk_ty(self, t)
}
fn visit_generic_param(&mut self, g: &'v ast::GenericParam) {
self.record("GenericParam", Id::None, g);
ast_visit::walk_generic_param(self, g)
}
fn visit_where_predicate(&mut self, p: &'v ast::WherePredicate) {
self.record("WherePredicate", Id::None, p);
ast_visit::walk_where_predicate(self, p)
}
fn visit_fn(&mut self, fk: ast_visit::FnKind<'v>, s: Span, _: NodeId) {
self.record("FnDecl", Id::None, fk.decl());
ast_visit::walk_fn(self, fk, s)
@ -318,27 +356,42 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
ast_visit::walk_variant(self, v)
}
fn visit_lifetime(&mut self, lifetime: &'v ast::Lifetime, _: ast_visit::LifetimeCtxt) {
self.record("Lifetime", Id::None, lifetime);
ast_visit::walk_lifetime(self, lifetime)
}
fn visit_mac_call(&mut self, mac: &'v ast::MacCall) {
self.record("MacCall", Id::None, mac);
ast_visit::walk_mac(self, mac)
}
// `UseTree` has one inline use (in `ast::ItemKind::Use`) and one
// non-inline use (in `ast::UseTreeKind::Nested). The former case is more
// common, so we don't implement `visit_use_tree` and tolerate the missed
// coverage in the latter case.
fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v ast::PathSegment) {
self.record("PathSegment", Id::None, path_segment);
ast_visit::walk_path_segment(self, path_span, path_segment)
}
fn visit_assoc_constraint(&mut self, constraint: &'v ast::AssocConstraint) {
self.record("AssocConstraint", Id::None, constraint);
ast_visit::walk_assoc_constraint(self, constraint)
// `GenericArgs` has one inline use (in `ast::AssocConstraint::gen_args`) and one
// non-inline use (in `ast::PathSegment::args`). The latter case is more
// common, so we implement `visit_generic_args` and tolerate the double
// counting in the former case.
fn visit_generic_args(&mut self, sp: Span, g: &'v ast::GenericArgs) {
self.record("GenericArgs", Id::None, g);
ast_visit::walk_generic_args(self, sp, g)
}
fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
self.record("Attribute", Id::None, attr);
ast_visit::walk_attribute(self, attr)
}
fn visit_expr_field(&mut self, f: &'v ast::ExprField) {
self.record("ExprField", Id::None, f);
ast_visit::walk_expr_field(self, f)
}
fn visit_crate(&mut self, krate: &'v ast::Crate) {
self.record("Crate", Id::None, krate);
ast_visit::walk_crate(self, krate)
}
fn visit_inline_asm(&mut self, asm: &'v ast::InlineAsm) {
self.record("InlineAsm", Id::None, asm);
ast_visit::walk_inline_asm(self, asm)
}
}

View File

@ -3,13 +3,16 @@ PRE EXPANSION AST STATS
Name Accumulated Size Count Item Size
----------------------------------------------------------------
Lifetime 32 2 16
MacCall 64 1 64
ExprField 48 1 48
GenericArgs 64 1 64
Local 72 1 72
WherePredicate 72 1 72
Crate 72 1 72
Arm 96 2 48
FieldDef 160 2 80
ForeignItem 160 1 160
Stmt 160 5 32
Param 160 4 40
FnDecl 200 5 40
Variant 240 2 120
Block 288 6 48
@ -17,31 +20,38 @@ Attribute 304 2 152
ImplItem 320 2 160
TraitItem 320 2 160
GenericBound 352 4 88
GenericParam 520 5 104
PathSegment 720 30 24
Expr 832 8 104
Pat 840 7 120
Ty 1_344 14 96
Item 1_800 9 200
----------------------------------------------------------------
Total 8_304
Total 9_144
POST EXPANSION AST STATS
Name Accumulated Size Count Item Size
----------------------------------------------------------------
Lifetime 32 2 16
ExprField 48 1 48
GenericArgs 64 1 64
Local 72 1 72
WherePredicate 72 1 72
Crate 72 1 72
Arm 96 2 48
InlineAsm 120 1 120
FieldDef 160 2 80
ForeignItem 160 1 160
Stmt 160 5 32
Param 160 4 40
FnDecl 200 5 40
Variant 240 2 120
Block 288 6 48
ImplItem 320 2 160
TraitItem 320 2 160
GenericBound 352 4 88
GenericParam 520 5 104
Attribute 608 4 152
PathSegment 792 33 24
Pat 840 7 120
@ -49,7 +59,7 @@ Expr 936 9 104
Ty 1_344 14 96
Item 2_200 11 200
----------------------------------------------------------------
Total 9_120
Total 10_144
HIR STATS