]> git.proxmox.com Git - rustc.git/blob - src/librustc_passes/mir_stats.rs
New upstream version 1.19.0+dfsg1
[rustc.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.optimized_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::NullaryOp(..) => "Rvalue::NullaryOp",
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 }