-
Notifications
You must be signed in to change notification settings - Fork 12.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Revisions from review comments, squashed.
Biggest change: Revised print-type-sizes output to include breakdown of layout. Includes info about field sizes (and alignment + padding when padding is injected; the injected padding is derived from the offsets computed by layout module). Output format is illustrated in commit that has the ui tests. Note: there exists (at least) one case of variant w/o name: empty enums. Namely, empty enums use anonymous univariant repr. So for such cases, print the number of the variant instead of the name. ---- Also, eddyb suggested of reading from `layout_cache` post-trans. (For casual readers: the compiler source often uses the word "cache" for tables that are in fact not periodically purged, and thus are useful as the basis for data like this.) Some types that were previously not printed are now included in the output. (See e.g. the tests `print_type_sizes/generics.rs` and `print_type_sizes/variants.rs`) ---- Other review feedback: switch to an exhaustive match when filtering in just structural types. switch to hashset for layout info and move sort into print method. ---- Driveby change: Factored session::code_stats into its own module ---- incorporate njn feedback re output formatting.
- Loading branch information
Showing
8 changed files
with
377 additions
and
228 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
use ty::AdtKind; | ||
use ty::layout::{Align, Size}; | ||
|
||
use rustc_data_structures::fx::{FxHashSet}; | ||
|
||
use std::cmp::{self, Ordering}; | ||
|
||
#[derive(Clone, PartialEq, Eq, Hash, Debug)] | ||
pub struct VariantInfo { | ||
pub name: Option<String>, | ||
pub kind: SizeKind, | ||
pub size: u64, | ||
pub align: u64, | ||
pub fields: Vec<FieldInfo>, | ||
} | ||
|
||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] | ||
pub enum SizeKind { Exact, Min } | ||
|
||
#[derive(Clone, PartialEq, Eq, Hash, Debug)] | ||
pub struct FieldInfo { | ||
pub name: String, | ||
pub offset: u64, | ||
pub size: u64, | ||
pub align: u64, | ||
} | ||
|
||
impl From<AdtKind> for DataTypeKind { | ||
fn from(kind: AdtKind) -> Self { | ||
match kind { | ||
AdtKind::Struct => DataTypeKind::Struct, | ||
AdtKind::Enum => DataTypeKind::Enum, | ||
AdtKind::Union => DataTypeKind::Union, | ||
} | ||
} | ||
} | ||
|
||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] | ||
pub enum DataTypeKind { | ||
Struct, | ||
Union, | ||
Enum, | ||
Closure, | ||
} | ||
|
||
#[derive(PartialEq, Eq, Hash, Debug)] | ||
pub struct TypeSizeInfo { | ||
pub kind: DataTypeKind, | ||
pub type_description: String, | ||
pub align: u64, | ||
pub overall_size: u64, | ||
pub opt_discr_size: Option<u64>, | ||
pub variants: Vec<VariantInfo>, | ||
} | ||
|
||
#[derive(PartialEq, Eq, Debug)] | ||
pub struct CodeStats { | ||
type_sizes: FxHashSet<TypeSizeInfo>, | ||
} | ||
|
||
impl CodeStats { | ||
pub fn new() -> Self { CodeStats { type_sizes: FxHashSet() } } | ||
|
||
pub fn record_type_size<S: ToString>(&mut self, | ||
kind: DataTypeKind, | ||
type_desc: S, | ||
align: Align, | ||
overall_size: Size, | ||
opt_discr_size: Option<Size>, | ||
variants: Vec<VariantInfo>) { | ||
let info = TypeSizeInfo { | ||
kind: kind, | ||
type_description: type_desc.to_string(), | ||
align: align.abi(), | ||
overall_size: overall_size.bytes(), | ||
opt_discr_size: opt_discr_size.map(|s| s.bytes()), | ||
variants: variants, | ||
}; | ||
self.type_sizes.insert(info); | ||
} | ||
|
||
pub fn print_type_sizes(&self) { | ||
let mut sorted: Vec<_> = self.type_sizes.iter().collect(); | ||
|
||
// Primary sort: large-to-small. | ||
// Secondary sort: description (dictionary order) | ||
sorted.sort_by(|info1, info2| { | ||
// (reversing cmp order to get large-to-small ordering) | ||
match info2.overall_size.cmp(&info1.overall_size) { | ||
Ordering::Equal => info1.type_description.cmp(&info2.type_description), | ||
other => other, | ||
} | ||
}); | ||
|
||
for info in &sorted { | ||
println!("print-type-size type: `{}`: {} bytes, alignment: {} bytes", | ||
info.type_description, info.overall_size, info.align); | ||
let indent = " "; | ||
|
||
let discr_size = if let Some(discr_size) = info.opt_discr_size { | ||
println!("print-type-size {}discriminant: {} bytes", | ||
indent, discr_size); | ||
discr_size | ||
} else { | ||
0 | ||
}; | ||
|
||
// We start this at discr_size (rather than 0) because | ||
// things like C-enums do not have variants but we still | ||
// want the max_variant_size at the end of the loop below | ||
// to reflect the presence of the discriminant. | ||
let mut max_variant_size = discr_size; | ||
|
||
let struct_like = match info.kind { | ||
DataTypeKind::Struct | DataTypeKind::Closure => true, | ||
DataTypeKind::Enum | DataTypeKind::Union => false, | ||
}; | ||
for (i, variant_info) in info.variants.iter().enumerate() { | ||
let VariantInfo { ref name, kind: _, align: _, size, ref fields } = *variant_info; | ||
let indent = if !struct_like { | ||
let name = match name.as_ref() { | ||
Some(name) => format!("{}", name), | ||
None => format!("{}", i), | ||
}; | ||
println!("print-type-size {}variant `{}`: {} bytes", | ||
indent, name, size - discr_size); | ||
" " | ||
} else { | ||
assert!(i < 1); | ||
" " | ||
}; | ||
max_variant_size = cmp::max(max_variant_size, size); | ||
|
||
let mut min_offset = discr_size; | ||
for field in fields { | ||
let FieldInfo { ref name, offset, size, align } = *field; | ||
|
||
// Include field alignment in output only if it caused padding injection | ||
if min_offset != offset { | ||
let pad = offset - min_offset; | ||
println!("print-type-size {}padding bytes: {}", | ||
indent, pad); | ||
println!("print-type-size {}field `.{}`: {} bytes, alignment: {} bytes", | ||
indent, name, size, align); | ||
} else { | ||
println!("print-type-size {}field `.{}`: {} bytes", | ||
indent, name, size); | ||
} | ||
|
||
min_offset = offset + size; | ||
} | ||
} | ||
|
||
assert!(max_variant_size <= info.overall_size, | ||
"max_variant_size {} !<= {} overall_size", | ||
max_variant_size, info.overall_size); | ||
if max_variant_size < info.overall_size { | ||
println!("print-type-size {}end padding bytes: {}", | ||
indent, info.overall_size - max_variant_size); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.