]> git.lizzy.rs Git - rust.git/blob - src/librustc_passes/mir_stats.rs
introduce `mir_keys()`
[rust.git] / src / librustc_passes / mir_stats.rs
1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 // The visitors in this module collect sizes and counts of the most important
12 // pieces of MIR. The resulting numbers are good approximations but not
13 // completely accurate (some things might be counted twice, others missed).
14
15 use rustc_const_math::{ConstUsize};
16 use rustc::hir::def_id::LOCAL_CRATE;
17 use rustc::middle::const_val::{ConstVal};
18 use rustc::mir::{AggregateKind, AssertMessage, BasicBlock, BasicBlockData};
19 use rustc::mir::{Constant, Literal, Location, LocalDecl};
20 use rustc::mir::{Lvalue, LvalueElem, LvalueProjection};
21 use rustc::mir::{Mir, Operand, ProjectionElem};
22 use rustc::mir::{Rvalue, SourceInfo, Statement, StatementKind};
23 use rustc::mir::{Terminator, TerminatorKind, VisibilityScope, VisibilityScopeData};
24 use rustc::mir::visit as mir_visit;
25 use rustc::mir::visit::Visitor;
26 use rustc::ty::{ClosureSubsts, TyCtxt};
27 use rustc::util::common::to_readable_str;
28 use rustc::util::nodemap::{FxHashMap};
29
30 struct NodeData {
31     count: usize,
32     size: usize,
33 }
34
35 struct StatCollector<'a, 'tcx: 'a> {
36     _tcx: TyCtxt<'a, 'tcx, 'tcx>,
37     data: FxHashMap<&'static str, NodeData>,
38 }
39
40 pub fn print_mir_stats<'tcx, 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, title: &str) {
41     let mut collector = StatCollector {
42         _tcx: tcx,
43         data: FxHashMap(),
44     };
45     // For debugging instrumentation like this, we don't need to worry
46     // about maintaining the dep graph.
47     let _ignore = tcx.dep_graph.in_ignore();
48     for &def_id in tcx.mir_keys(LOCAL_CRATE).iter() {
49         let mir = tcx.item_mir(def_id);
50         collector.visit_mir(&mir);
51     }
52     collector.print(title);
53 }
54
55 impl<'a, 'tcx> StatCollector<'a, 'tcx> {
56
57     fn record_with_size(&mut self, label: &'static str, node_size: usize) {
58         let entry = self.data.entry(label).or_insert(NodeData {
59             count: 0,
60             size: 0,
61         });
62
63         entry.count += 1;
64         entry.size = node_size;
65     }
66
67     fn record<T>(&mut self, label: &'static str, node: &T) {
68         self.record_with_size(label, ::std::mem::size_of_val(node));
69     }
70
71     fn print(&self, title: &str) {
72         let mut stats: Vec<_> = self.data.iter().collect();
73
74         stats.sort_by_key(|&(_, ref d)| d.count * d.size);
75
76         println!("\n{}\n", title);
77
78         println!("{:<32}{:>18}{:>14}{:>14}",
79             "Name", "Accumulated Size", "Count", "Item Size");
80         println!("------------------------------------------------------------------------------");
81
82         for (label, data) in stats {
83             println!("{:<32}{:>18}{:>14}{:>14}",
84                 label,
85                 to_readable_str(data.count * data.size),
86                 to_readable_str(data.count),
87                 to_readable_str(data.size));
88         }
89         println!("------------------------------------------------------------------------------");
90     }
91 }
92
93 impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> {
94     fn visit_mir(&mut self, mir: &Mir<'tcx>) {
95         self.record("Mir", mir);
96
97         // since the `super_mir` method does not traverse the MIR of
98         // promoted rvalues, (but we still want to gather statistics
99         // on the structures represented there) we manually traverse
100         // the promoted rvalues here.
101         for promoted_mir in &mir.promoted {
102             self.visit_mir(promoted_mir);
103         }
104
105         self.super_mir(mir);
106     }
107
108     fn visit_basic_block_data(&mut self,
109                               block: BasicBlock,
110                               data: &BasicBlockData<'tcx>) {
111         self.record("BasicBlockData", data);
112         self.super_basic_block_data(block, data);
113     }
114
115     fn visit_visibility_scope_data(&mut self,
116                                    scope_data: &VisibilityScopeData) {
117         self.record("VisibilityScopeData", scope_data);
118         self.super_visibility_scope_data(scope_data);
119     }
120
121     fn visit_statement(&mut self,
122                        block: BasicBlock,
123                        statement: &Statement<'tcx>,
124                        location: Location) {
125         self.record("Statement", statement);
126         self.record(match statement.kind {
127             StatementKind::Assign(..) => "StatementKind::Assign",
128             StatementKind::SetDiscriminant { .. } => "StatementKind::SetDiscriminant",
129             StatementKind::StorageLive(..) => "StatementKind::StorageLive",
130             StatementKind::StorageDead(..) => "StatementKind::StorageDead",
131             StatementKind::InlineAsm { .. } => "StatementKind::InlineAsm",
132             StatementKind::Nop => "StatementKind::Nop",
133         }, &statement.kind);
134         self.super_statement(block, statement, location);
135     }
136
137     fn visit_terminator(&mut self,
138                         block: BasicBlock,
139                         terminator: &Terminator<'tcx>,
140                         location: Location) {
141         self.record("Terminator", terminator);
142         self.super_terminator(block, terminator, location);
143     }
144
145     fn visit_terminator_kind(&mut self,
146                              block: BasicBlock,
147                              kind: &TerminatorKind<'tcx>,
148                              location: Location) {
149         self.record("TerminatorKind", kind);
150         self.record(match *kind {
151             TerminatorKind::Goto { .. } => "TerminatorKind::Goto",
152             TerminatorKind::SwitchInt { .. } => "TerminatorKind::SwitchInt",
153             TerminatorKind::Resume => "TerminatorKind::Resume",
154             TerminatorKind::Return => "TerminatorKind::Return",
155             TerminatorKind::Unreachable => "TerminatorKind::Unreachable",
156             TerminatorKind::Drop { .. } => "TerminatorKind::Drop",
157             TerminatorKind::DropAndReplace { .. } => "TerminatorKind::DropAndReplace",
158             TerminatorKind::Call { .. } => "TerminatorKind::Call",
159             TerminatorKind::Assert { .. } => "TerminatorKind::Assert",
160         }, kind);
161         self.super_terminator_kind(block, kind, location);
162     }
163
164     fn visit_assert_message(&mut self,
165                             msg: &AssertMessage<'tcx>,
166                             location: Location) {
167         self.record("AssertMessage", msg);
168         self.record(match *msg {
169             AssertMessage::BoundsCheck { .. } => "AssertMessage::BoundsCheck",
170             AssertMessage::Math(..) => "AssertMessage::Math",
171         }, msg);
172         self.super_assert_message(msg, location);
173     }
174
175     fn visit_rvalue(&mut self,
176                     rvalue: &Rvalue<'tcx>,
177                     location: Location) {
178         self.record("Rvalue", rvalue);
179         let rvalue_kind = match *rvalue {
180             Rvalue::Use(..) => "Rvalue::Use",
181             Rvalue::Repeat(..) => "Rvalue::Repeat",
182             Rvalue::Ref(..) => "Rvalue::Ref",
183             Rvalue::Len(..) => "Rvalue::Len",
184             Rvalue::Cast(..) => "Rvalue::Cast",
185             Rvalue::BinaryOp(..) => "Rvalue::BinaryOp",
186             Rvalue::CheckedBinaryOp(..) => "Rvalue::CheckedBinaryOp",
187             Rvalue::UnaryOp(..) => "Rvalue::UnaryOp",
188             Rvalue::Discriminant(..) => "Rvalue::Discriminant",
189             Rvalue::Box(..) => "Rvalue::Box",
190             Rvalue::Aggregate(ref kind, ref _operands) => {
191                 // AggregateKind is not distinguished by visit API, so
192                 // record it. (`super_rvalue` handles `_operands`.)
193                 self.record(match *kind {
194                     AggregateKind::Array(_) => "AggregateKind::Array",
195                     AggregateKind::Tuple => "AggregateKind::Tuple",
196                     AggregateKind::Adt(..) => "AggregateKind::Adt",
197                     AggregateKind::Closure(..) => "AggregateKind::Closure",
198                 }, kind);
199
200                 "Rvalue::Aggregate"
201             }
202         };
203         self.record(rvalue_kind, rvalue);
204         self.super_rvalue(rvalue, location);
205     }
206
207     fn visit_operand(&mut self,
208                      operand: &Operand<'tcx>,
209                      location: Location) {
210         self.record("Operand", operand);
211         self.record(match *operand {
212             Operand::Consume(..) => "Operand::Consume",
213             Operand::Constant(..) => "Operand::Constant",
214         }, operand);
215         self.super_operand(operand, location);
216     }
217
218     fn visit_lvalue(&mut self,
219                     lvalue: &Lvalue<'tcx>,
220                     context: mir_visit::LvalueContext<'tcx>,
221                     location: Location) {
222         self.record("Lvalue", lvalue);
223         self.record(match *lvalue {
224             Lvalue::Local(..) => "Lvalue::Local",
225             Lvalue::Static(..) => "Lvalue::Static",
226             Lvalue::Projection(..) => "Lvalue::Projection",
227         }, lvalue);
228         self.super_lvalue(lvalue, context, location);
229     }
230
231     fn visit_projection(&mut self,
232                         lvalue: &LvalueProjection<'tcx>,
233                         context: mir_visit::LvalueContext<'tcx>,
234                         location: Location) {
235         self.record("LvalueProjection", lvalue);
236         self.super_projection(lvalue, context, location);
237     }
238
239     fn visit_projection_elem(&mut self,
240                              lvalue: &LvalueElem<'tcx>,
241                              context: mir_visit::LvalueContext<'tcx>,
242                              location: Location) {
243         self.record("LvalueElem", lvalue);
244         self.record(match *lvalue {
245             ProjectionElem::Deref => "LvalueElem::Deref",
246             ProjectionElem::Subslice { .. } => "LvalueElem::Subslice",
247             ProjectionElem::Field(..) => "LvalueElem::Field",
248             ProjectionElem::Index(..) => "LvalueElem::Index",
249             ProjectionElem::ConstantIndex { .. } => "LvalueElem::ConstantIndex",
250             ProjectionElem::Downcast(..) => "LvalueElem::Downcast",
251         }, lvalue);
252         self.super_projection_elem(lvalue, context, location);
253     }
254
255     fn visit_constant(&mut self,
256                       constant: &Constant<'tcx>,
257                       location: Location) {
258         self.record("Constant", constant);
259         self.super_constant(constant, location);
260     }
261
262     fn visit_literal(&mut self,
263                      literal: &Literal<'tcx>,
264                      location: Location) {
265         self.record("Literal", literal);
266         self.record(match *literal {
267             Literal::Item { .. } => "Literal::Item",
268             Literal::Value { .. } => "Literal::Value",
269             Literal::Promoted { .. } => "Literal::Promoted",
270         }, literal);
271         self.super_literal(literal, location);
272     }
273
274     fn visit_source_info(&mut self,
275                          source_info: &SourceInfo) {
276         self.record("SourceInfo", source_info);
277         self.super_source_info(source_info);
278     }
279
280     fn visit_closure_substs(&mut self,
281                             substs: &ClosureSubsts<'tcx>) {
282         self.record("ClosureSubsts", substs);
283         self.super_closure_substs(substs);
284     }
285
286     fn visit_const_val(&mut self,
287                        const_val: &ConstVal,
288                        _: Location) {
289         self.record("ConstVal", const_val);
290         self.super_const_val(const_val);
291     }
292
293     fn visit_const_usize(&mut self,
294                          const_usize: &ConstUsize,
295                          _: Location) {
296         self.record("ConstUsize", const_usize);
297         self.super_const_usize(const_usize);
298     }
299
300     fn visit_local_decl(&mut self,
301                         local_decl: &LocalDecl<'tcx>) {
302         self.record("LocalDecl", local_decl);
303         self.super_local_decl(local_decl);
304     }
305
306     fn visit_visibility_scope(&mut self,
307                               scope: &VisibilityScope) {
308         self.record("VisiblityScope", scope);
309         self.super_visibility_scope(scope);
310     }
311 }