]>
Commit | Line | Data |
---|---|---|
c30ab7b3 SL |
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). | |
4 | ||
74b04a01 XL |
5 | use rustc_ast::ast::{self, AttrId, NodeId}; |
6 | use rustc_ast::visit as ast_visit; | |
dfeec247 XL |
7 | use rustc_data_structures::fx::{FxHashMap, FxHashSet}; |
8 | use rustc_hir as hir; | |
9 | use rustc_hir::intravisit as hir_visit; | |
10 | use rustc_hir::HirId; | |
ba9703b0 XL |
11 | use rustc_middle::hir::map::Map; |
12 | use rustc_middle::util::common::to_readable_str; | |
dfeec247 | 13 | use rustc_span::Span; |
c30ab7b3 SL |
14 | |
15 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] | |
16 | enum Id { | |
532ac7d7 | 17 | Node(HirId), |
c30ab7b3 SL |
18 | Attr(AttrId), |
19 | None, | |
20 | } | |
21 | ||
22 | struct NodeData { | |
23 | count: usize, | |
24 | size: usize, | |
25 | } | |
26 | ||
27 | struct StatCollector<'k> { | |
dfeec247 | 28 | krate: Option<&'k hir::Crate<'k>>, |
476ff2be SL |
29 | data: FxHashMap<&'static str, NodeData>, |
30 | seen: FxHashSet<Id>, | |
c30ab7b3 SL |
31 | } |
32 | ||
dfeec247 | 33 | pub fn print_hir_stats(krate: &hir::Crate<'_>) { |
c30ab7b3 SL |
34 | let mut collector = StatCollector { |
35 | krate: Some(krate), | |
0bf4aa26 XL |
36 | data: FxHashMap::default(), |
37 | seen: FxHashSet::default(), | |
c30ab7b3 SL |
38 | }; |
39 | hir_visit::walk_crate(&mut collector, krate); | |
40 | collector.print("HIR STATS"); | |
41 | } | |
42 | ||
416331ca | 43 | pub fn print_ast_stats(krate: &ast::Crate, title: &str) { |
dfeec247 XL |
44 | let mut collector = |
45 | StatCollector { krate: None, data: FxHashMap::default(), seen: FxHashSet::default() }; | |
c30ab7b3 SL |
46 | ast_visit::walk_crate(&mut collector, krate); |
47 | collector.print(title); | |
48 | } | |
49 | ||
50 | impl<'k> StatCollector<'k> { | |
c30ab7b3 | 51 | fn record<T>(&mut self, label: &'static str, id: Id, node: &T) { |
b7449926 | 52 | if id != Id::None && !self.seen.insert(id) { |
dfeec247 | 53 | return; |
c30ab7b3 SL |
54 | } |
55 | ||
dfeec247 | 56 | let entry = self.data.entry(label).or_insert(NodeData { count: 0, size: 0 }); |
c30ab7b3 SL |
57 | |
58 | entry.count += 1; | |
9fa01778 | 59 | entry.size = std::mem::size_of_val(node); |
c30ab7b3 SL |
60 | } |
61 | ||
62 | fn print(&self, title: &str) { | |
63 | let mut stats: Vec<_> = self.data.iter().collect(); | |
64 | ||
65 | stats.sort_by_key(|&(_, ref d)| d.count * d.size); | |
66 | ||
67 | let mut total_size = 0; | |
68 | ||
69 | println!("\n{}\n", title); | |
70 | ||
dfeec247 | 71 | println!("{:<18}{:>18}{:>14}{:>14}", "Name", "Accumulated Size", "Count", "Item Size"); |
c30ab7b3 SL |
72 | println!("----------------------------------------------------------------"); |
73 | ||
74 | for (label, data) in stats { | |
dfeec247 XL |
75 | println!( |
76 | "{:<18}{:>18}{:>14}{:>14}", | |
c30ab7b3 SL |
77 | label, |
78 | to_readable_str(data.count * data.size), | |
79 | to_readable_str(data.count), | |
dfeec247 XL |
80 | to_readable_str(data.size) |
81 | ); | |
c30ab7b3 SL |
82 | |
83 | total_size += data.count * data.size; | |
84 | } | |
85 | println!("----------------------------------------------------------------"); | |
dfeec247 | 86 | println!("{:<18}{:>18}\n", "Total", to_readable_str(total_size)); |
c30ab7b3 SL |
87 | } |
88 | } | |
89 | ||
90 | impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { | |
dfeec247 | 91 | fn visit_param(&mut self, param: &'v hir::Param<'v>) { |
e1599b0c XL |
92 | self.record("Param", Id::Node(param.hir_id), param); |
93 | hir_visit::walk_param(self, param) | |
416331ca XL |
94 | } |
95 | ||
dfeec247 XL |
96 | type Map = Map<'v>; |
97 | ||
ba9703b0 | 98 | fn nested_visit_map(&mut self) -> hir_visit::NestedVisitorMap<Self::Map> { |
476ff2be SL |
99 | panic!("visit_nested_xxx must be manually implemented in this visitor") |
100 | } | |
c30ab7b3 SL |
101 | |
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) | |
105 | } | |
106 | ||
32a655c1 SL |
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) | |
110 | } | |
111 | ||
476ff2be SL |
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) | |
115 | } | |
116 | ||
3b2f2976 XL |
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) | |
120 | } | |
121 | ||
dfeec247 | 122 | fn visit_item(&mut self, i: &'v hir::Item<'v>) { |
532ac7d7 | 123 | self.record("Item", Id::Node(i.hir_id), i); |
c30ab7b3 SL |
124 | hir_visit::walk_item(self, i) |
125 | } | |
126 | ||
dfeec247 | 127 | fn visit_mod(&mut self, m: &'v hir::Mod<'v>, _s: Span, n: hir::HirId) { |
c30ab7b3 SL |
128 | self.record("Mod", Id::None, m); |
129 | hir_visit::walk_mod(self, m, n) | |
130 | } | |
b7449926 | 131 | |
dfeec247 | 132 | fn visit_foreign_item(&mut self, i: &'v hir::ForeignItem<'v>) { |
532ac7d7 | 133 | self.record("ForeignItem", Id::Node(i.hir_id), i); |
c30ab7b3 SL |
134 | hir_visit::walk_foreign_item(self, i) |
135 | } | |
b7449926 | 136 | |
dfeec247 | 137 | fn visit_local(&mut self, l: &'v hir::Local<'v>) { |
532ac7d7 | 138 | self.record("Local", Id::Node(l.hir_id), l); |
c30ab7b3 SL |
139 | hir_visit::walk_local(self, l) |
140 | } | |
b7449926 | 141 | |
dfeec247 | 142 | fn visit_block(&mut self, b: &'v hir::Block<'v>) { |
532ac7d7 | 143 | self.record("Block", Id::Node(b.hir_id), b); |
c30ab7b3 SL |
144 | hir_visit::walk_block(self, b) |
145 | } | |
b7449926 | 146 | |
dfeec247 | 147 | fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) { |
532ac7d7 | 148 | self.record("Stmt", Id::Node(s.hir_id), s); |
c30ab7b3 SL |
149 | hir_visit::walk_stmt(self, s) |
150 | } | |
b7449926 | 151 | |
dfeec247 | 152 | fn visit_arm(&mut self, a: &'v hir::Arm<'v>) { |
dc9dc135 | 153 | self.record("Arm", Id::Node(a.hir_id), a); |
c30ab7b3 SL |
154 | hir_visit::walk_arm(self, a) |
155 | } | |
b7449926 | 156 | |
dfeec247 | 157 | fn visit_pat(&mut self, p: &'v hir::Pat<'v>) { |
532ac7d7 | 158 | self.record("Pat", Id::Node(p.hir_id), p); |
c30ab7b3 SL |
159 | hir_visit::walk_pat(self, p) |
160 | } | |
b7449926 | 161 | |
dfeec247 | 162 | fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { |
532ac7d7 | 163 | self.record("Expr", Id::Node(ex.hir_id), ex); |
c30ab7b3 SL |
164 | hir_visit::walk_expr(self, ex) |
165 | } | |
166 | ||
dfeec247 | 167 | fn visit_ty(&mut self, t: &'v hir::Ty<'v>) { |
532ac7d7 | 168 | self.record("Ty", Id::Node(t.hir_id), t); |
c30ab7b3 SL |
169 | hir_visit::walk_ty(self, t) |
170 | } | |
171 | ||
dfeec247 XL |
172 | fn visit_fn( |
173 | &mut self, | |
174 | fk: hir_visit::FnKind<'v>, | |
175 | fd: &'v hir::FnDecl<'v>, | |
176 | b: hir::BodyId, | |
177 | s: Span, | |
178 | id: hir::HirId, | |
179 | ) { | |
c30ab7b3 SL |
180 | self.record("FnDecl", Id::None, fd); |
181 | hir_visit::walk_fn(self, fk, fd, b, s, id) | |
182 | } | |
183 | ||
dfeec247 | 184 | fn visit_where_predicate(&mut self, predicate: &'v hir::WherePredicate<'v>) { |
c30ab7b3 SL |
185 | self.record("WherePredicate", Id::None, predicate); |
186 | hir_visit::walk_where_predicate(self, predicate) | |
187 | } | |
188 | ||
dfeec247 | 189 | fn visit_trait_item(&mut self, ti: &'v hir::TraitItem<'v>) { |
532ac7d7 | 190 | self.record("TraitItem", Id::Node(ti.hir_id), ti); |
c30ab7b3 SL |
191 | hir_visit::walk_trait_item(self, ti) |
192 | } | |
b7449926 | 193 | |
dfeec247 | 194 | fn visit_impl_item(&mut self, ii: &'v hir::ImplItem<'v>) { |
532ac7d7 | 195 | self.record("ImplItem", Id::Node(ii.hir_id), ii); |
c30ab7b3 SL |
196 | hir_visit::walk_impl_item(self, ii) |
197 | } | |
198 | ||
dfeec247 | 199 | fn visit_param_bound(&mut self, bounds: &'v hir::GenericBound<'v>) { |
8faf50e0 XL |
200 | self.record("GenericBound", Id::None, bounds); |
201 | hir_visit::walk_param_bound(self, bounds) | |
c30ab7b3 SL |
202 | } |
203 | ||
dfeec247 | 204 | fn visit_struct_field(&mut self, s: &'v hir::StructField<'v>) { |
532ac7d7 | 205 | self.record("StructField", Id::Node(s.hir_id), s); |
c30ab7b3 SL |
206 | hir_visit::walk_struct_field(self, s) |
207 | } | |
208 | ||
dfeec247 XL |
209 | fn visit_variant( |
210 | &mut self, | |
211 | v: &'v hir::Variant<'v>, | |
212 | g: &'v hir::Generics<'v>, | |
213 | item_id: hir::HirId, | |
214 | ) { | |
c30ab7b3 SL |
215 | self.record("Variant", Id::None, v); |
216 | hir_visit::walk_variant(self, v, g, item_id) | |
217 | } | |
b7449926 | 218 | |
c30ab7b3 | 219 | fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) { |
532ac7d7 | 220 | self.record("Lifetime", Id::Node(lifetime.hir_id), lifetime); |
c30ab7b3 SL |
221 | hir_visit::walk_lifetime(self, lifetime) |
222 | } | |
b7449926 | 223 | |
dfeec247 | 224 | fn visit_qpath(&mut self, qpath: &'v hir::QPath<'v>, id: hir::HirId, span: Span) { |
476ff2be SL |
225 | self.record("QPath", Id::None, qpath); |
226 | hir_visit::walk_qpath(self, qpath, id, span) | |
227 | } | |
b7449926 | 228 | |
dfeec247 | 229 | fn visit_path(&mut self, path: &'v hir::Path<'v>, _id: hir::HirId) { |
c30ab7b3 SL |
230 | self.record("Path", Id::None, path); |
231 | hir_visit::walk_path(self, path) | |
232 | } | |
b7449926 | 233 | |
dfeec247 | 234 | fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v hir::PathSegment<'v>) { |
c30ab7b3 SL |
235 | self.record("PathSegment", Id::None, path_segment); |
236 | hir_visit::walk_path_segment(self, path_span, path_segment) | |
237 | } | |
b7449926 | 238 | |
dfeec247 | 239 | fn visit_assoc_type_binding(&mut self, type_binding: &'v hir::TypeBinding<'v>) { |
532ac7d7 | 240 | self.record("TypeBinding", Id::Node(type_binding.hir_id), type_binding); |
c30ab7b3 SL |
241 | hir_visit::walk_assoc_type_binding(self, type_binding) |
242 | } | |
b7449926 | 243 | |
c30ab7b3 | 244 | fn visit_attribute(&mut self, attr: &'v ast::Attribute) { |
476ff2be | 245 | self.record("Attribute", Id::Attr(attr.id), attr); |
c30ab7b3 | 246 | } |
b7449926 | 247 | |
dfeec247 | 248 | fn visit_macro_def(&mut self, macro_def: &'v hir::MacroDef<'v>) { |
532ac7d7 | 249 | self.record("MacroDef", Id::Node(macro_def.hir_id), macro_def); |
c30ab7b3 SL |
250 | hir_visit::walk_macro_def(self, macro_def) |
251 | } | |
252 | } | |
253 | ||
476ff2be | 254 | impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { |
7cac9316 | 255 | fn visit_mod(&mut self, m: &'v ast::Mod, _s: Span, _a: &[ast::Attribute], _n: NodeId) { |
c30ab7b3 SL |
256 | self.record("Mod", Id::None, m); |
257 | ast_visit::walk_mod(self, m) | |
258 | } | |
259 | ||
476ff2be | 260 | fn visit_foreign_item(&mut self, i: &'v ast::ForeignItem) { |
c30ab7b3 SL |
261 | self.record("ForeignItem", Id::None, i); |
262 | ast_visit::walk_foreign_item(self, i) | |
263 | } | |
264 | ||
476ff2be | 265 | fn visit_item(&mut self, i: &'v ast::Item) { |
c30ab7b3 SL |
266 | self.record("Item", Id::None, i); |
267 | ast_visit::walk_item(self, i) | |
268 | } | |
269 | ||
476ff2be | 270 | fn visit_local(&mut self, l: &'v ast::Local) { |
c30ab7b3 SL |
271 | self.record("Local", Id::None, l); |
272 | ast_visit::walk_local(self, l) | |
273 | } | |
274 | ||
476ff2be | 275 | fn visit_block(&mut self, b: &'v ast::Block) { |
c30ab7b3 SL |
276 | self.record("Block", Id::None, b); |
277 | ast_visit::walk_block(self, b) | |
278 | } | |
279 | ||
476ff2be | 280 | fn visit_stmt(&mut self, s: &'v ast::Stmt) { |
c30ab7b3 SL |
281 | self.record("Stmt", Id::None, s); |
282 | ast_visit::walk_stmt(self, s) | |
283 | } | |
284 | ||
476ff2be | 285 | fn visit_arm(&mut self, a: &'v ast::Arm) { |
c30ab7b3 SL |
286 | self.record("Arm", Id::None, a); |
287 | ast_visit::walk_arm(self, a) | |
288 | } | |
289 | ||
476ff2be | 290 | fn visit_pat(&mut self, p: &'v ast::Pat) { |
c30ab7b3 SL |
291 | self.record("Pat", Id::None, p); |
292 | ast_visit::walk_pat(self, p) | |
293 | } | |
294 | ||
476ff2be | 295 | fn visit_expr(&mut self, ex: &'v ast::Expr) { |
c30ab7b3 SL |
296 | self.record("Expr", Id::None, ex); |
297 | ast_visit::walk_expr(self, ex) | |
298 | } | |
299 | ||
476ff2be | 300 | fn visit_ty(&mut self, t: &'v ast::Ty) { |
c30ab7b3 SL |
301 | self.record("Ty", Id::None, t); |
302 | ast_visit::walk_ty(self, t) | |
303 | } | |
304 | ||
74b04a01 XL |
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) | |
c30ab7b3 SL |
308 | } |
309 | ||
74b04a01 XL |
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", | |
314 | }; | |
315 | self.record(label, Id::None, item); | |
316 | ast_visit::walk_assoc_item(self, item, ctxt); | |
c30ab7b3 SL |
317 | } |
318 | ||
8faf50e0 XL |
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) | |
c30ab7b3 SL |
322 | } |
323 | ||
476ff2be | 324 | fn visit_struct_field(&mut self, s: &'v ast::StructField) { |
c30ab7b3 SL |
325 | self.record("StructField", Id::None, s); |
326 | ast_visit::walk_struct_field(self, s) | |
327 | } | |
328 | ||
e1599b0c | 329 | fn visit_variant(&mut self, v: &'v ast::Variant) { |
c30ab7b3 | 330 | self.record("Variant", Id::None, v); |
e1599b0c | 331 | ast_visit::walk_variant(self, v) |
c30ab7b3 SL |
332 | } |
333 | ||
476ff2be | 334 | fn visit_lifetime(&mut self, lifetime: &'v ast::Lifetime) { |
c30ab7b3 SL |
335 | self.record("Lifetime", Id::None, lifetime); |
336 | ast_visit::walk_lifetime(self, lifetime) | |
337 | } | |
338 | ||
ba9703b0 XL |
339 | fn visit_mac(&mut self, mac: &'v ast::MacCall) { |
340 | self.record("MacCall", Id::None, mac); | |
c30ab7b3 SL |
341 | } |
342 | ||
dfeec247 | 343 | fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v ast::PathSegment) { |
c30ab7b3 SL |
344 | self.record("PathSegment", Id::None, path_segment); |
345 | ast_visit::walk_path_segment(self, path_span, path_segment) | |
346 | } | |
347 | ||
dc9dc135 XL |
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) | |
c30ab7b3 SL |
351 | } |
352 | ||
476ff2be | 353 | fn visit_attribute(&mut self, attr: &'v ast::Attribute) { |
c30ab7b3 SL |
354 | self.record("Attribute", Id::None, attr); |
355 | } | |
c30ab7b3 | 356 | } |