-Zprint-type-sizes: print the types of awaitees and unnamed coroutine locals.

This should assist comprehending the size of coroutines.
In particular, whenever a future is suspended while awaiting another
future, the latter is given the special name `__awaitee`, and now the
type of the awaited future will be printed, allowing identifying
caller/callee — er, I mean, poller/pollee — relationships.

It would be possible to include the type name in more cases, but I
thought that that might be overly verbose (`print-type-sizes` is already
a lot of text) and ordinary named fields or variables are easier for
readers to discover the types of.
This commit is contained in:
Kevin Reid 2024-03-22 16:45:32 -07:00
parent 85e449a323
commit 44d185b0d0
5 changed files with 34 additions and 16 deletions

View File

@ -44,6 +44,10 @@ pub struct FieldInfo {
pub offset: u64,
pub size: u64,
pub align: u64,
/// Name of the type of this field.
/// Present only if the creator thought that this would be important for identifying the field,
/// typically because the field name is uninformative.
pub type_name: Option<Symbol>,
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
@ -192,7 +196,7 @@ impl CodeStats {
fields.sort_by_key(|f| (f.offset, f.size));
for field in fields {
let FieldInfo { kind, ref name, offset, size, align } = field;
let FieldInfo { kind, ref name, offset, size, align, type_name } = field;
if offset > min_offset {
let pad = offset - min_offset;
@ -201,21 +205,27 @@ impl CodeStats {
if offset < min_offset {
// If this happens it's probably a union.
println!(
print!(
"print-type-size {indent}{kind} `.{name}`: {size} bytes, \
offset: {offset} bytes, \
alignment: {align} bytes"
);
} else if info.packed || offset == min_offset {
println!("print-type-size {indent}{kind} `.{name}`: {size} bytes");
print!("print-type-size {indent}{kind} `.{name}`: {size} bytes");
} else {
// Include field alignment in output only if it caused padding injection
println!(
print!(
"print-type-size {indent}{kind} `.{name}`: {size} bytes, \
alignment: {align} bytes"
);
}
if let Some(type_name) = type_name {
println!(", type: {type_name}");
} else {
println!();
}
min_offset = offset + size;
}
}

View File

@ -10,6 +10,7 @@ use rustc_middle::ty::layout::{
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, AdtDef, EarlyBinder, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt};
use rustc_session::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
use rustc_span::sym;
use rustc_span::symbol::Symbol;
use rustc_target::abi::*;
@ -1007,6 +1008,7 @@ fn variant_info_for_adt<'tcx>(
offset: offset.bytes(),
size: field_layout.size.bytes(),
align: field_layout.align.abi.bytes(),
type_name: None,
}
})
.collect();
@ -1090,6 +1092,7 @@ fn variant_info_for_coroutine<'tcx>(
offset: offset.bytes(),
size: field_layout.size.bytes(),
align: field_layout.align.abi.bytes(),
type_name: None,
}
})
.collect();
@ -1104,19 +1107,24 @@ fn variant_info_for_coroutine<'tcx>(
.iter()
.enumerate()
.map(|(field_idx, local)| {
let field_name = coroutine.field_names[*local];
let field_layout = variant_layout.field(cx, field_idx);
let offset = variant_layout.fields.offset(field_idx);
// The struct is as large as the last field's end
variant_size = variant_size.max(offset + field_layout.size);
FieldInfo {
kind: FieldKind::CoroutineLocal,
name: coroutine.field_names[*local].unwrap_or(Symbol::intern(&format!(
name: field_name.unwrap_or(Symbol::intern(&format!(
".coroutine_field{}",
local.as_usize()
))),
offset: offset.bytes(),
size: field_layout.size.bytes(),
align: field_layout.align.abi.bytes(),
// Include the type name if there is no field name, or if the name is the
// __awaitee placeholder symbol which means a child future being `.await`ed.
type_name: (field_name.is_none() || field_name == Some(sym::__awaitee))
.then(|| Symbol::intern(&field_layout.ty.to_string())),
}
})
.chain(upvar_fields.iter().copied())

View File

@ -2,7 +2,7 @@ print-type-size type: `{async fn body@$DIR/async-awaiting-fut.rs:21:21: 24:2}`:
print-type-size discriminant: 1 bytes
print-type-size variant `Unresumed`: 0 bytes
print-type-size variant `Suspend0`: 3077 bytes
print-type-size local `.__awaitee`: 3077 bytes
print-type-size local `.__awaitee`: 3077 bytes, type: {async fn body@$DIR/async-awaiting-fut.rs:10:64: 19:2}
print-type-size variant `Returned`: 0 bytes
print-type-size variant `Panicked`: 0 bytes
print-type-size type: `std::mem::ManuallyDrop<{async fn body@$DIR/async-awaiting-fut.rs:10:64: 19:2}>`: 3077 bytes, alignment: 1 bytes
@ -19,19 +19,19 @@ print-type-size variant `Suspend0`: 2052 bytes
print-type-size upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
print-type-size padding: 1 bytes
print-type-size local `.fut`: 1025 bytes, alignment: 1 bytes
print-type-size local `..coroutine_field4`: 1 bytes
print-type-size local `.__awaitee`: 1 bytes
print-type-size local `..coroutine_field4`: 1 bytes, type: bool
print-type-size local `.__awaitee`: 1 bytes, type: {async fn body@$DIR/async-awaiting-fut.rs:6:17: 6:19}
print-type-size variant `Suspend1`: 3076 bytes
print-type-size upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
print-type-size padding: 1026 bytes
print-type-size local `..coroutine_field4`: 1 bytes, alignment: 1 bytes
print-type-size local `.__awaitee`: 1025 bytes
print-type-size local `..coroutine_field4`: 1 bytes, alignment: 1 bytes, type: bool
print-type-size local `.__awaitee`: 1025 bytes, type: {async fn body@$DIR/async-awaiting-fut.rs:8:35: 8:37}
print-type-size variant `Suspend2`: 2052 bytes
print-type-size upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
print-type-size padding: 1 bytes
print-type-size local `.fut`: 1025 bytes, alignment: 1 bytes
print-type-size local `..coroutine_field4`: 1 bytes
print-type-size local `.__awaitee`: 1 bytes
print-type-size local `..coroutine_field4`: 1 bytes, type: bool
print-type-size local `.__awaitee`: 1 bytes, type: {async fn body@$DIR/async-awaiting-fut.rs:6:17: 6:19}
print-type-size variant `Returned`: 1025 bytes
print-type-size upvar `.fut`: 1025 bytes, offset: 0 bytes, alignment: 1 bytes
print-type-size variant `Panicked`: 1025 bytes

View File

@ -2,7 +2,7 @@ print-type-size type: `{async fn body@$DIR/large-arg.rs:6:21: 8:2}`: 3076 bytes,
print-type-size discriminant: 1 bytes
print-type-size variant `Unresumed`: 0 bytes
print-type-size variant `Suspend0`: 3075 bytes
print-type-size local `.__awaitee`: 3075 bytes
print-type-size local `.__awaitee`: 3075 bytes, type: {async fn body@$DIR/large-arg.rs:10:30: 12:2}
print-type-size variant `Returned`: 0 bytes
print-type-size variant `Panicked`: 0 bytes
print-type-size type: `std::mem::ManuallyDrop<{async fn body@$DIR/large-arg.rs:10:30: 12:2}>`: 3075 bytes, alignment: 1 bytes
@ -17,7 +17,7 @@ print-type-size variant `Unresumed`: 1024 bytes
print-type-size upvar `.t`: 1024 bytes
print-type-size variant `Suspend0`: 3074 bytes
print-type-size upvar `.t`: 1024 bytes
print-type-size local `.__awaitee`: 2050 bytes
print-type-size local `.__awaitee`: 2050 bytes, type: {async fn body@$DIR/large-arg.rs:13:26: 15:2}
print-type-size variant `Returned`: 1024 bytes
print-type-size upvar `.t`: 1024 bytes
print-type-size variant `Panicked`: 1024 bytes
@ -34,7 +34,7 @@ print-type-size variant `Unresumed`: 1024 bytes
print-type-size upvar `.t`: 1024 bytes
print-type-size variant `Suspend0`: 2049 bytes
print-type-size upvar `.t`: 1024 bytes
print-type-size local `.__awaitee`: 1025 bytes
print-type-size local `.__awaitee`: 1025 bytes, type: {async fn body@$DIR/large-arg.rs:16:26: 18:2}
print-type-size variant `Returned`: 1024 bytes
print-type-size upvar `.t`: 1024 bytes
print-type-size variant `Panicked`: 1024 bytes

View File

@ -5,7 +5,7 @@ print-type-size upvar `.arg`: 8192 bytes
print-type-size variant `Suspend0`: 16385 bytes
print-type-size upvar `.arg`: 8192 bytes
print-type-size local `.arg`: 8192 bytes
print-type-size local `.__awaitee`: 1 bytes
print-type-size local `.__awaitee`: 1 bytes, type: {async fn body@$DIR/async.rs:8:17: 8:19}
print-type-size variant `Returned`: 8192 bytes
print-type-size upvar `.arg`: 8192 bytes
print-type-size variant `Panicked`: 8192 bytes