]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_session/src/code_stats.rs
New upstream version 1.64.0+dfsg1
[rustc.git] / compiler / rustc_session / src / code_stats.rs
CommitLineData
dfeec247
XL
1use rustc_data_structures::fx::FxHashSet;
2use rustc_data_structures::sync::Lock;
064997fb 3use rustc_span::Symbol;
b7449926 4use rustc_target::abi::{Align, Size};
476ff2be
SL
5use std::cmp::{self, Ordering};
6
7#[derive(Clone, PartialEq, Eq, Hash, Debug)]
8pub struct VariantInfo {
064997fb 9 pub name: Option<Symbol>,
476ff2be
SL
10 pub kind: SizeKind,
11 pub size: u64,
12 pub align: u64,
13 pub fields: Vec<FieldInfo>,
14}
15
16#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
cc61c64b
XL
17pub enum SizeKind {
18 Exact,
19 Min,
20}
476ff2be
SL
21
22#[derive(Clone, PartialEq, Eq, Hash, Debug)]
23pub struct FieldInfo {
064997fb 24 pub name: Symbol,
476ff2be
SL
25 pub offset: u64,
26 pub size: u64,
27 pub align: u64,
28}
29
476ff2be
SL
30#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
31pub enum DataTypeKind {
32 Struct,
33 Union,
34 Enum,
35 Closure,
36}
37
38#[derive(PartialEq, Eq, Hash, Debug)]
39pub struct TypeSizeInfo {
40 pub kind: DataTypeKind,
41 pub type_description: String,
42 pub align: u64,
43 pub overall_size: u64,
83c7162d 44 pub packed: bool,
476ff2be
SL
45 pub opt_discr_size: Option<u64>,
46 pub variants: Vec<VariantInfo>,
47}
48
60c5eb7d 49#[derive(Default)]
476ff2be 50pub struct CodeStats {
60c5eb7d 51 type_sizes: Lock<FxHashSet<TypeSizeInfo>>,
476ff2be
SL
52}
53
54impl CodeStats {
dfeec247
XL
55 pub fn record_type_size<S: ToString>(
56 &self,
57 kind: DataTypeKind,
58 type_desc: S,
59 align: Align,
60 overall_size: Size,
61 packed: bool,
62 opt_discr_size: Option<Size>,
63 mut variants: Vec<VariantInfo>,
64 ) {
48663c56
XL
65 // Sort variants so the largest ones are shown first. A stable sort is
66 // used here so that source code order is preserved for all variants
67 // that have the same size.
dfeec247 68 variants.sort_by(|info1, info2| info2.size.cmp(&info1.size));
476ff2be 69 let info = TypeSizeInfo {
041b39d2 70 kind,
476ff2be 71 type_description: type_desc.to_string(),
a1dfa0c6 72 align: align.bytes(),
476ff2be 73 overall_size: overall_size.bytes(),
74b04a01 74 packed,
476ff2be 75 opt_discr_size: opt_discr_size.map(|s| s.bytes()),
041b39d2 76 variants,
476ff2be 77 };
60c5eb7d 78 self.type_sizes.borrow_mut().insert(info);
476ff2be
SL
79 }
80
81 pub fn print_type_sizes(&self) {
60c5eb7d
XL
82 let type_sizes = self.type_sizes.borrow();
83 let mut sorted: Vec<_> = type_sizes.iter().collect();
476ff2be
SL
84
85 // Primary sort: large-to-small.
86 // Secondary sort: description (dictionary order)
87 sorted.sort_by(|info1, info2| {
88 // (reversing cmp order to get large-to-small ordering)
89 match info2.overall_size.cmp(&info1.overall_size) {
90 Ordering::Equal => info1.type_description.cmp(&info2.type_description),
91 other => other,
92 }
93 });
94
5e7ed085
FG
95 for info in sorted {
96 let TypeSizeInfo { type_description, overall_size, align, kind, variants, .. } = info;
dfeec247 97 println!(
5e7ed085 98 "print-type-size type: `{type_description}`: {overall_size} bytes, alignment: {align} bytes"
dfeec247 99 );
476ff2be
SL
100 let indent = " ";
101
102 let discr_size = if let Some(discr_size) = info.opt_discr_size {
5e7ed085 103 println!("print-type-size {indent}discriminant: {discr_size} bytes");
476ff2be
SL
104 discr_size
105 } else {
106 0
107 };
108
109 // We start this at discr_size (rather than 0) because
110 // things like C-enums do not have variants but we still
111 // want the max_variant_size at the end of the loop below
112 // to reflect the presence of the discriminant.
113 let mut max_variant_size = discr_size;
114
5e7ed085 115 let struct_like = match kind {
476ff2be
SL
116 DataTypeKind::Struct | DataTypeKind::Closure => true,
117 DataTypeKind::Enum | DataTypeKind::Union => false,
118 };
5e7ed085 119 for (i, variant_info) in variants.into_iter().enumerate() {
476ff2be
SL
120 let VariantInfo { ref name, kind: _, align: _, size, ref fields } = *variant_info;
121 let indent = if !struct_like {
122 let name = match name.as_ref() {
064997fb 123 Some(name) => name.to_string(),
8faf50e0 124 None => i.to_string(),
476ff2be 125 };
dfeec247 126 println!(
5e7ed085
FG
127 "print-type-size {indent}variant `{name}`: {diff} bytes",
128 diff = size - discr_size
dfeec247 129 );
476ff2be
SL
130 " "
131 } else {
132 assert!(i < 1);
133 " "
134 };
135 max_variant_size = cmp::max(max_variant_size, size);
136
137 let mut min_offset = discr_size;
138
60c5eb7d
XL
139 // We want to print fields by increasing offset. We also want
140 // zero-sized fields before non-zero-sized fields, otherwise
141 // the loop below goes wrong; hence the `f.size` in the sort
142 // key.
476ff2be 143 let mut fields = fields.clone();
60c5eb7d 144 fields.sort_by_key(|f| (f.offset, f.size));
476ff2be 145
5e7ed085
FG
146 for field in fields {
147 let FieldInfo { ref name, offset, size, align } = field;
476ff2be 148
83c7162d
XL
149 if offset > min_offset {
150 let pad = offset - min_offset;
5e7ed085 151 println!("print-type-size {indent}padding: {pad} bytes");
83c7162d
XL
152 }
153
154 if offset < min_offset {
60c5eb7d 155 // If this happens it's probably a union.
dfeec247 156 println!(
5e7ed085
FG
157 "print-type-size {indent}field `.{name}`: {size} bytes, \
158 offset: {offset} bytes, \
159 alignment: {align} bytes"
dfeec247 160 );
83c7162d 161 } else if info.packed || offset == min_offset {
5e7ed085 162 println!("print-type-size {indent}field `.{name}`: {size} bytes");
83c7162d
XL
163 } else {
164 // Include field alignment in output only if it caused padding injection
dfeec247 165 println!(
5e7ed085
FG
166 "print-type-size {indent}field `.{name}`: {size} bytes, \
167 alignment: {align} bytes"
dfeec247 168 );
476ff2be
SL
169 }
170
171 min_offset = offset + size;
172 }
173 }
174
5e7ed085
FG
175 match overall_size.checked_sub(max_variant_size) {
176 None => panic!("max_variant_size {max_variant_size} > {overall_size} overall_size"),
177 Some(diff @ 1..) => println!("print-type-size {indent}end padding: {diff} bytes"),
178 Some(0) => {}
476ff2be
SL
179 }
180 }
181 }
182}