]> git.lizzy.rs Git - rust.git/blob - src/librustc/session/code_stats.rs
add inline attributes to stage 0 methods
[rust.git] / src / librustc / session / code_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 use ty::AdtKind;
12 use ty::layout::{Align, Size};
13
14 use rustc_data_structures::fx::{FxHashSet};
15
16 use std::cmp::{self, Ordering};
17
18 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
19 pub struct VariantInfo {
20     pub name: Option<String>,
21     pub kind: SizeKind,
22     pub size: u64,
23     pub align: u64,
24     pub fields: Vec<FieldInfo>,
25 }
26
27 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
28 pub enum SizeKind { Exact, Min }
29
30 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
31 pub struct FieldInfo {
32     pub name: String,
33     pub offset: u64,
34     pub size: u64,
35     pub align: u64,
36 }
37
38 impl From<AdtKind> for DataTypeKind {
39     fn from(kind: AdtKind) -> Self {
40         match kind {
41             AdtKind::Struct => DataTypeKind::Struct,
42             AdtKind::Enum => DataTypeKind::Enum,
43             AdtKind::Union => DataTypeKind::Union,
44         }
45     }
46 }
47
48 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
49 pub enum DataTypeKind {
50     Struct,
51     Union,
52     Enum,
53     Closure,
54 }
55
56 #[derive(PartialEq, Eq, Hash, Debug)]
57 pub struct TypeSizeInfo {
58     pub kind: DataTypeKind,
59     pub type_description: String,
60     pub align: u64,
61     pub overall_size: u64,
62     pub opt_discr_size: Option<u64>,
63     pub variants: Vec<VariantInfo>,
64 }
65
66 #[derive(PartialEq, Eq, Debug)]
67 pub struct CodeStats {
68     type_sizes: FxHashSet<TypeSizeInfo>,
69 }
70
71 impl CodeStats {
72     pub fn new() -> Self { CodeStats { type_sizes: FxHashSet() } }
73
74     pub fn record_type_size<S: ToString>(&mut self,
75                                          kind: DataTypeKind,
76                                          type_desc: S,
77                                          align: Align,
78                                          overall_size: Size,
79                                          opt_discr_size: Option<Size>,
80                                          variants: Vec<VariantInfo>) {
81         let info = TypeSizeInfo {
82             kind: kind,
83             type_description: type_desc.to_string(),
84             align: align.abi(),
85             overall_size: overall_size.bytes(),
86             opt_discr_size: opt_discr_size.map(|s| s.bytes()),
87             variants: variants,
88         };
89         self.type_sizes.insert(info);
90     }
91
92     pub fn print_type_sizes(&self) {
93         let mut sorted: Vec<_> = self.type_sizes.iter().collect();
94
95         // Primary sort: large-to-small.
96         // Secondary sort: description (dictionary order)
97         sorted.sort_by(|info1, info2| {
98             // (reversing cmp order to get large-to-small ordering)
99             match info2.overall_size.cmp(&info1.overall_size) {
100                 Ordering::Equal => info1.type_description.cmp(&info2.type_description),
101                 other => other,
102             }
103         });
104
105         for info in &sorted {
106             println!("print-type-size type: `{}`: {} bytes, alignment: {} bytes",
107                      info.type_description, info.overall_size, info.align);
108             let indent = "    ";
109
110             let discr_size = if let Some(discr_size) = info.opt_discr_size {
111                 println!("print-type-size {}discriminant: {} bytes",
112                          indent, discr_size);
113                 discr_size
114             } else {
115                 0
116             };
117
118             // We start this at discr_size (rather than 0) because
119             // things like C-enums do not have variants but we still
120             // want the max_variant_size at the end of the loop below
121             // to reflect the presence of the discriminant.
122             let mut max_variant_size = discr_size;
123
124             let struct_like = match info.kind {
125                 DataTypeKind::Struct | DataTypeKind::Closure => true,
126                 DataTypeKind::Enum | DataTypeKind::Union => false,
127             };
128             for (i, variant_info) in info.variants.iter().enumerate() {
129                 let VariantInfo { ref name, kind: _, align: _, size, ref fields } = *variant_info;
130                 let indent = if !struct_like {
131                     let name = match name.as_ref() {
132                         Some(name) => format!("{}", name),
133                         None => format!("{}", i),
134                     };
135                     println!("print-type-size {}variant `{}`: {} bytes",
136                              indent, name, size - discr_size);
137                     "        "
138                 } else {
139                     assert!(i < 1);
140                     "    "
141                 };
142                 max_variant_size = cmp::max(max_variant_size, size);
143
144                 let mut min_offset = discr_size;
145
146                 // We want to print fields by increasing offset.
147                 let mut fields = fields.clone();
148                 fields.sort_by_key(|f| f.offset);
149
150                 for field in fields.iter() {
151                     let FieldInfo { ref name, offset, size, align } = *field;
152
153                     // Include field alignment in output only if it caused padding injection
154                     if min_offset != offset {
155                         let pad = offset - min_offset;
156                         println!("print-type-size {}padding: {} bytes",
157                                  indent, pad);
158                         println!("print-type-size {}field `.{}`: {} bytes, alignment: {} bytes",
159                                  indent, name, size, align);
160                     } else {
161                         println!("print-type-size {}field `.{}`: {} bytes",
162                                  indent, name, size);
163                     }
164
165                     min_offset = offset + size;
166                 }
167             }
168
169             assert!(max_variant_size <= info.overall_size,
170                     "max_variant_size {} !<= {} overall_size",
171                     max_variant_size, info.overall_size);
172             if max_variant_size < info.overall_size {
173                 println!("print-type-size {}end padding: {} bytes",
174                          indent, info.overall_size - max_variant_size);
175             }
176         }
177     }
178 }