1 // The visitors in this module collect sizes and counts of the most important
2 // pieces of AST and HIR. The resulting numbers are good approximations but not
3 // completely accurate (some things might be counted twice, others missed).
5 use rustc_ast
::visit
as ast_visit
;
6 use rustc_ast
::{self as ast, AttrId, NodeId}
;
7 use rustc_data_structures
::fx
::{FxHashMap, FxHashSet}
;
9 use rustc_hir
::intravisit
as hir_visit
;
11 use rustc_middle
::hir
::map
::Map
;
12 use rustc_middle
::util
::common
::to_readable_str
;
15 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
27 struct StatCollector
<'k
> {
28 krate
: Option
<&'k hir
::Crate
<'k
>>,
29 data
: FxHashMap
<&'
static str, NodeData
>,
33 pub fn print_hir_stats(krate
: &hir
::Crate
<'_
>) {
34 let mut collector
= StatCollector
{
36 data
: FxHashMap
::default(),
37 seen
: FxHashSet
::default(),
39 hir_visit
::walk_crate(&mut collector
, krate
);
40 collector
.print("HIR STATS");
43 pub fn print_ast_stats(krate
: &ast
::Crate
, title
: &str) {
45 StatCollector { krate: None, data: FxHashMap::default(), seen: FxHashSet::default() }
;
46 ast_visit
::walk_crate(&mut collector
, krate
);
47 collector
.print(title
);
50 impl<'k
> StatCollector
<'k
> {
51 fn record
<T
>(&mut self, label
: &'
static str, id
: Id
, node
: &T
) {
52 if id
!= Id
::None
&& !self.seen
.insert(id
) {
56 let entry
= self.data
.entry(label
).or_insert(NodeData { count: 0, size: 0 }
);
59 entry
.size
= std
::mem
::size_of_val(node
);
62 fn print(&self, title
: &str) {
63 let mut stats
: Vec
<_
> = self.data
.iter().collect();
65 stats
.sort_by_key(|&(_
, ref d
)| d
.count
* d
.size
);
67 let mut total_size
= 0;
69 println
!("\n{}\n", title
);
71 println
!("{:<18}{:>18}{:>14}{:>14}", "Name", "Accumulated Size", "Count", "Item Size");
72 println
!("----------------------------------------------------------------");
74 for (label
, data
) in stats
{
76 "{:<18}{:>18}{:>14}{:>14}",
78 to_readable_str(data
.count
* data
.size
),
79 to_readable_str(data
.count
),
80 to_readable_str(data
.size
)
83 total_size
+= data
.count
* data
.size
;
85 println
!("----------------------------------------------------------------");
86 println
!("{:<18}{:>18}\n", "Total", to_readable_str(total_size
));
90 impl<'v
> hir_visit
::Visitor
<'v
> for StatCollector
<'v
> {
91 fn visit_param(&mut self, param
: &'v hir
::Param
<'v
>) {
92 self.record("Param", Id
::Node(param
.hir_id
), param
);
93 hir_visit
::walk_param(self, param
)
98 fn nested_visit_map(&mut self) -> hir_visit
::NestedVisitorMap
<Self::Map
> {
99 panic
!("visit_nested_xxx must be manually implemented in this visitor")
102 fn visit_nested_item(&mut self, id
: hir
::ItemId
) {
103 let nested_item
= self.krate
.unwrap().item(id
.id
);
104 self.visit_item(nested_item
)
107 fn visit_nested_trait_item(&mut self, trait_item_id
: hir
::TraitItemId
) {
108 let nested_trait_item
= self.krate
.unwrap().trait_item(trait_item_id
);
109 self.visit_trait_item(nested_trait_item
)
112 fn visit_nested_impl_item(&mut self, impl_item_id
: hir
::ImplItemId
) {
113 let nested_impl_item
= self.krate
.unwrap().impl_item(impl_item_id
);
114 self.visit_impl_item(nested_impl_item
)
117 fn visit_nested_body(&mut self, body_id
: hir
::BodyId
) {
118 let nested_body
= self.krate
.unwrap().body(body_id
);
119 self.visit_body(nested_body
)
122 fn visit_item(&mut self, i
: &'v hir
::Item
<'v
>) {
123 self.record("Item", Id
::Node(i
.hir_id
), i
);
124 hir_visit
::walk_item(self, i
)
127 fn visit_mod(&mut self, m
: &'v hir
::Mod
<'v
>, _s
: Span
, n
: hir
::HirId
) {
128 self.record("Mod", Id
::None
, m
);
129 hir_visit
::walk_mod(self, m
, n
)
132 fn visit_foreign_item(&mut self, i
: &'v hir
::ForeignItem
<'v
>) {
133 self.record("ForeignItem", Id
::Node(i
.hir_id
), i
);
134 hir_visit
::walk_foreign_item(self, i
)
137 fn visit_local(&mut self, l
: &'v hir
::Local
<'v
>) {
138 self.record("Local", Id
::Node(l
.hir_id
), l
);
139 hir_visit
::walk_local(self, l
)
142 fn visit_block(&mut self, b
: &'v hir
::Block
<'v
>) {
143 self.record("Block", Id
::Node(b
.hir_id
), b
);
144 hir_visit
::walk_block(self, b
)
147 fn visit_stmt(&mut self, s
: &'v hir
::Stmt
<'v
>) {
148 self.record("Stmt", Id
::Node(s
.hir_id
), s
);
149 hir_visit
::walk_stmt(self, s
)
152 fn visit_arm(&mut self, a
: &'v hir
::Arm
<'v
>) {
153 self.record("Arm", Id
::Node(a
.hir_id
), a
);
154 hir_visit
::walk_arm(self, a
)
157 fn visit_pat(&mut self, p
: &'v hir
::Pat
<'v
>) {
158 self.record("Pat", Id
::Node(p
.hir_id
), p
);
159 hir_visit
::walk_pat(self, p
)
162 fn visit_expr(&mut self, ex
: &'v hir
::Expr
<'v
>) {
163 self.record("Expr", Id
::Node(ex
.hir_id
), ex
);
164 hir_visit
::walk_expr(self, ex
)
167 fn visit_ty(&mut self, t
: &'v hir
::Ty
<'v
>) {
168 self.record("Ty", Id
::Node(t
.hir_id
), t
);
169 hir_visit
::walk_ty(self, t
)
174 fk
: hir_visit
::FnKind
<'v
>,
175 fd
: &'v hir
::FnDecl
<'v
>,
180 self.record("FnDecl", Id
::None
, fd
);
181 hir_visit
::walk_fn(self, fk
, fd
, b
, s
, id
)
184 fn visit_where_predicate(&mut self, predicate
: &'v hir
::WherePredicate
<'v
>) {
185 self.record("WherePredicate", Id
::None
, predicate
);
186 hir_visit
::walk_where_predicate(self, predicate
)
189 fn visit_trait_item(&mut self, ti
: &'v hir
::TraitItem
<'v
>) {
190 self.record("TraitItem", Id
::Node(ti
.hir_id
), ti
);
191 hir_visit
::walk_trait_item(self, ti
)
194 fn visit_impl_item(&mut self, ii
: &'v hir
::ImplItem
<'v
>) {
195 self.record("ImplItem", Id
::Node(ii
.hir_id
), ii
);
196 hir_visit
::walk_impl_item(self, ii
)
199 fn visit_param_bound(&mut self, bounds
: &'v hir
::GenericBound
<'v
>) {
200 self.record("GenericBound", Id
::None
, bounds
);
201 hir_visit
::walk_param_bound(self, bounds
)
204 fn visit_struct_field(&mut self, s
: &'v hir
::StructField
<'v
>) {
205 self.record("StructField", Id
::Node(s
.hir_id
), s
);
206 hir_visit
::walk_struct_field(self, s
)
211 v
: &'v hir
::Variant
<'v
>,
212 g
: &'v hir
::Generics
<'v
>,
215 self.record("Variant", Id
::None
, v
);
216 hir_visit
::walk_variant(self, v
, g
, item_id
)
219 fn visit_lifetime(&mut self, lifetime
: &'v hir
::Lifetime
) {
220 self.record("Lifetime", Id
::Node(lifetime
.hir_id
), lifetime
);
221 hir_visit
::walk_lifetime(self, lifetime
)
224 fn visit_qpath(&mut self, qpath
: &'v hir
::QPath
<'v
>, id
: hir
::HirId
, span
: Span
) {
225 self.record("QPath", Id
::None
, qpath
);
226 hir_visit
::walk_qpath(self, qpath
, id
, span
)
229 fn visit_path(&mut self, path
: &'v hir
::Path
<'v
>, _id
: hir
::HirId
) {
230 self.record("Path", Id
::None
, path
);
231 hir_visit
::walk_path(self, path
)
234 fn visit_path_segment(&mut self, path_span
: Span
, path_segment
: &'v hir
::PathSegment
<'v
>) {
235 self.record("PathSegment", Id
::None
, path_segment
);
236 hir_visit
::walk_path_segment(self, path_span
, path_segment
)
239 fn visit_assoc_type_binding(&mut self, type_binding
: &'v hir
::TypeBinding
<'v
>) {
240 self.record("TypeBinding", Id
::Node(type_binding
.hir_id
), type_binding
);
241 hir_visit
::walk_assoc_type_binding(self, type_binding
)
244 fn visit_attribute(&mut self, attr
: &'v ast
::Attribute
) {
245 self.record("Attribute", Id
::Attr(attr
.id
), attr
);
248 fn visit_macro_def(&mut self, macro_def
: &'v hir
::MacroDef
<'v
>) {
249 self.record("MacroDef", Id
::Node(macro_def
.hir_id
), macro_def
);
250 hir_visit
::walk_macro_def(self, macro_def
)
254 impl<'v
> ast_visit
::Visitor
<'v
> for StatCollector
<'v
> {
255 fn visit_mod(&mut self, m
: &'v ast
::Mod
, _s
: Span
, _a
: &[ast
::Attribute
], _n
: NodeId
) {
256 self.record("Mod", Id
::None
, m
);
257 ast_visit
::walk_mod(self, m
)
260 fn visit_foreign_item(&mut self, i
: &'v ast
::ForeignItem
) {
261 self.record("ForeignItem", Id
::None
, i
);
262 ast_visit
::walk_foreign_item(self, i
)
265 fn visit_item(&mut self, i
: &'v ast
::Item
) {
266 self.record("Item", Id
::None
, i
);
267 ast_visit
::walk_item(self, i
)
270 fn visit_local(&mut self, l
: &'v ast
::Local
) {
271 self.record("Local", Id
::None
, l
);
272 ast_visit
::walk_local(self, l
)
275 fn visit_block(&mut self, b
: &'v ast
::Block
) {
276 self.record("Block", Id
::None
, b
);
277 ast_visit
::walk_block(self, b
)
280 fn visit_stmt(&mut self, s
: &'v ast
::Stmt
) {
281 self.record("Stmt", Id
::None
, s
);
282 ast_visit
::walk_stmt(self, s
)
285 fn visit_arm(&mut self, a
: &'v ast
::Arm
) {
286 self.record("Arm", Id
::None
, a
);
287 ast_visit
::walk_arm(self, a
)
290 fn visit_pat(&mut self, p
: &'v ast
::Pat
) {
291 self.record("Pat", Id
::None
, p
);
292 ast_visit
::walk_pat(self, p
)
295 fn visit_expr(&mut self, ex
: &'v ast
::Expr
) {
296 self.record("Expr", Id
::None
, ex
);
297 ast_visit
::walk_expr(self, ex
)
300 fn visit_ty(&mut self, t
: &'v ast
::Ty
) {
301 self.record("Ty", Id
::None
, t
);
302 ast_visit
::walk_ty(self, t
)
305 fn visit_fn(&mut self, fk
: ast_visit
::FnKind
<'v
>, s
: Span
, _
: NodeId
) {
306 self.record("FnDecl", Id
::None
, fk
.decl());
307 ast_visit
::walk_fn(self, fk
, s
)
310 fn visit_assoc_item(&mut self, item
: &'v ast
::AssocItem
, ctxt
: ast_visit
::AssocCtxt
) {
311 let label
= match ctxt
{
312 ast_visit
::AssocCtxt
::Trait
=> "TraitItem",
313 ast_visit
::AssocCtxt
::Impl
=> "ImplItem",
315 self.record(label
, Id
::None
, item
);
316 ast_visit
::walk_assoc_item(self, item
, ctxt
);
319 fn visit_param_bound(&mut self, bounds
: &'v ast
::GenericBound
) {
320 self.record("GenericBound", Id
::None
, bounds
);
321 ast_visit
::walk_param_bound(self, bounds
)
324 fn visit_struct_field(&mut self, s
: &'v ast
::StructField
) {
325 self.record("StructField", Id
::None
, s
);
326 ast_visit
::walk_struct_field(self, s
)
329 fn visit_variant(&mut self, v
: &'v ast
::Variant
) {
330 self.record("Variant", Id
::None
, v
);
331 ast_visit
::walk_variant(self, v
)
334 fn visit_lifetime(&mut self, lifetime
: &'v ast
::Lifetime
) {
335 self.record("Lifetime", Id
::None
, lifetime
);
336 ast_visit
::walk_lifetime(self, lifetime
)
339 fn visit_mac(&mut self, mac
: &'v ast
::MacCall
) {
340 self.record("MacCall", Id
::None
, mac
);
343 fn visit_path_segment(&mut self, path_span
: Span
, path_segment
: &'v ast
::PathSegment
) {
344 self.record("PathSegment", Id
::None
, path_segment
);
345 ast_visit
::walk_path_segment(self, path_span
, path_segment
)
348 fn visit_assoc_ty_constraint(&mut self, constraint
: &'v ast
::AssocTyConstraint
) {
349 self.record("AssocTyConstraint", Id
::None
, constraint
);
350 ast_visit
::walk_assoc_ty_constraint(self, constraint
)
353 fn visit_attribute(&mut self, attr
: &'v ast
::Attribute
) {
354 self.record("Attribute", Id
::None
, attr
);