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.
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.
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).
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}
;
35 struct StatCollector
<'a
, 'tcx
: 'a
> {
36 _tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
37 data
: FxHashMap
<&'
static str, NodeData
>,
40 pub fn print_mir_stats
<'tcx
, 'a
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>, title
: &str) {
41 let mut collector
= StatCollector
{
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
);
52 collector
.print(title
);
55 impl<'a
, 'tcx
> StatCollector
<'a
, 'tcx
> {
57 fn record_with_size(&mut self, label
: &'
static str, node_size
: usize) {
58 let entry
= self.data
.entry(label
).or_insert(NodeData
{
64 entry
.size
= node_size
;
67 fn record
<T
>(&mut self, label
: &'
static str, node
: &T
) {
68 self.record_with_size(label
, ::std
::mem
::size_of_val(node
));
71 fn print(&self, title
: &str) {
72 let mut stats
: Vec
<_
> = self.data
.iter().collect();
74 stats
.sort_by_key(|&(_
, ref d
)| d
.count
* d
.size
);
76 println
!("\n{}\n", title
);
78 println
!("{:<32}{:>18}{:>14}{:>14}",
79 "Name", "Accumulated Size", "Count", "Item Size");
80 println
!("------------------------------------------------------------------------------");
82 for (label
, data
) in stats
{
83 println
!("{:<32}{:>18}{:>14}{:>14}",
85 to_readable_str(data
.count
* data
.size
),
86 to_readable_str(data
.count
),
87 to_readable_str(data
.size
));
89 println
!("------------------------------------------------------------------------------");
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
);
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
);
108 fn visit_basic_block_data(&mut self,
110 data
: &BasicBlockData
<'tcx
>) {
111 self.record("BasicBlockData", data
);
112 self.super_basic_block_data(block
, data
);
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
);
121 fn visit_statement(&mut self,
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",
134 self.super_statement(block
, statement
, location
);
137 fn visit_terminator(&mut self,
139 terminator
: &Terminator
<'tcx
>,
140 location
: Location
) {
141 self.record("Terminator", terminator
);
142 self.super_terminator(block
, terminator
, location
);
145 fn visit_terminator_kind(&mut self,
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",
161 self.super_terminator_kind(block
, kind
, location
);
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",
172 self.super_assert_message(msg
, location
);
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",
203 self.record(rvalue_kind
, rvalue
);
204 self.super_rvalue(rvalue
, location
);
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",
215 self.super_operand(operand
, location
);
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",
228 self.super_lvalue(lvalue
, context
, location
);
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
);
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",
252 self.super_projection_elem(lvalue
, context
, location
);
255 fn visit_constant(&mut self,
256 constant
: &Constant
<'tcx
>,
257 location
: Location
) {
258 self.record("Constant", constant
);
259 self.super_constant(constant
, location
);
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",
271 self.super_literal(literal
, location
);
274 fn visit_source_info(&mut self,
275 source_info
: &SourceInfo
) {
276 self.record("SourceInfo", source_info
);
277 self.super_source_info(source_info
);
280 fn visit_closure_substs(&mut self,
281 substs
: &ClosureSubsts
<'tcx
>) {
282 self.record("ClosureSubsts", substs
);
283 self.super_closure_substs(substs
);
286 fn visit_const_val(&mut self,
287 const_val
: &ConstVal
,
289 self.record("ConstVal", const_val
);
290 self.super_const_val(const_val
);
293 fn visit_const_usize(&mut self,
294 const_usize
: &ConstUsize
,
296 self.record("ConstUsize", const_usize
);
297 self.super_const_usize(const_usize
);
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
);
306 fn visit_visibility_scope(&mut self,
307 scope
: &VisibilityScope
) {
308 self.record("VisiblityScope", scope
);
309 self.super_visibility_scope(scope
);