Skip to content

Commit

Permalink
feat!: filter types if -h is provided
Browse files Browse the repository at this point in the history
  • Loading branch information
loyd committed May 30, 2024
1 parent 4196631 commit c55646a
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 54 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Show `__awaitee` type name ([#2]).

### Changed
- The `-h` parameter now filters also types, not only fields.

### Fixed
- Support nightly after 2024-03-22 ([#4]).

Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Features:
* Merges variants with similar layout.
* Shows layouts in compact form.
* Sorts fields by size (`-s`).
* Hides small fields (`-h`).
* Hides small types and fields (`-h`).
* Hides wrappers like `MaybeUninit` and custom ones (`-w`).
* Filters by type names (`-f` and `-e`).
* Limits output (`-l`).
Expand Down Expand Up @@ -54,7 +54,7 @@ OPTIONS:
-e, --exclude <exclude>... Excludes types that match these patterns
-p, --expand <expand>... Shows only types that match these patterns and their children, heuristically
-f, --filter <filter>... Shows only types that match these patterns
-h, --hide-less <hide-less> Hides fields with size less than this value [default: 0]
-h, --hide-less <hide-less> Hides types and fields with size less than this value [default: 0]
-l, --limit <limit> Shows only this number of top types [default: 100]
```

Expand Down Expand Up @@ -92,7 +92,7 @@ top-type-sizes -w -s -h 33 -p body@examples/chat.rs:174:33 < chat.txt | less
1032 value
```
* `-s` sorts fields by size and hides paddings.
* `-h <size>` hides all fields with size less than the provided size.
* `-h <size>` hides all types and fields with size less than the provided size.
* `-p <pattern>` hides all types that aren't contained in `<patten>` types. Note that the compiler doesn't provide types of fields, so this parameter filters types recursively by field sizes and can leave a lot of irrelevant types for small sizes (because they are more frequent). But it's very useful anyway.

Output:
Expand Down
2 changes: 1 addition & 1 deletion src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub struct Options {
/// Removes wrappers like `MaybeUninit`.
#[structopt(short = "w", long)]
pub remove_wrappers: bool,
/// Hides fields with size less than this value.
/// Hides types and fields with size less than this value.
#[structopt(short, long, default_value = "0")]
pub hide_less: usize,
/// Sorts fields by size and removes paddings.
Expand Down
82 changes: 51 additions & 31 deletions src/transformer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,63 @@ use crate::{options::Options, schema::*};
// TODO: merge types with common prefix and similar layouts.
// TODO: support whitelist and blacklist.

/// Filters all types using whitelisted and blacklisted patterns.
fn filter_types(types: &mut Vec<Type>, filters: &[Regex], exclude: &[Regex]) {
if filters.is_empty() && exclude.is_empty() {
/// Filters all types by size, regex filters and wrappers.
fn filter_types(types: &mut Vec<Type>, options: &Options) {
// Skip filtering if no options are provided.
if !options.remove_wrappers
&& options.hide_less == 0
&& options.filter.is_empty()
&& options.exclude.is_empty()
{
return;
}

types.retain(|type_| {
exclude.iter().all(|pattern| !pattern.is_match(&type_.name))
&& (filters.is_empty() || filters.iter().any(|pattern| pattern.is_match(&type_.name)))
// Remove by size.
if type_.size < options.hide_less {
return false;
}

// Remove wrappers (`MaybeUninit` etc).
if options.remove_wrappers && is_wrapper(type_) {
return false;
}

// Remove by explicit patterns.
if options
.exclude
.iter()
.any(|pattern| pattern.is_match(&type_.name))
{
return false;
}

options.filter.is_empty()
|| options
.filter
.iter()
.any(|pattern| pattern.is_match(&type_.name))
});
}

/// Detects wrappers like `MaybeUninit` and custom ones.
fn is_wrapper(type_: &Type) -> bool {
if type_.end_padding.is_some() {
return false;
}

let pred = |type_size, items: &[FieldOrPadding]| {
items.iter().all(|f| f.size() == type_size || f.size() == 0)
};

match &type_.kind {
TypeKind::Struct(s) => pred(type_.size, &s.items),
TypeKind::Enum(e) => {
e.discriminant_size.is_none() && e.variants.iter().all(|v| pred(type_.size, &v.items))
}
}
}

/// Retains only types that match patterns and their children. Based on
/// hueristics. Types must be sorted in descending order.
fn expand(types: &mut Vec<Type>, patterns: &[Regex]) {
Expand Down Expand Up @@ -135,39 +180,14 @@ fn remove_small_fields(type_: &mut Type, threshold: usize) {
};
}

/// Removes wrappers like `MaybeUninit` and custom ones.
fn remove_wrappers(types: &mut Vec<Type>) {
let is_wrapper = |type_size, items: &[FieldOrPadding]| {
items.iter().all(|f| f.size() == type_size || f.size() == 0)
};

types.retain(|type_| {
if type_.end_padding.is_some() {
return true;
}

match &type_.kind {
TypeKind::Struct(s) => !is_wrapper(type_.size, &s.items),
TypeKind::Enum(e) => {
e.discriminant_size.is_some()
|| !e.variants.iter().all(|v| is_wrapper(type_.size, &v.items))
}
}
});
}

pub fn transform(mut types: Vec<Type>, options: &Options) -> Vec<Type> {
filter_types(&mut types, &options.filter, &options.exclude);
filter_types(&mut types, options);

// Use stable sort to preserve partial ordering.
// Also sort by name to do proper deduplication.
types.sort_by(|a, b| (b.size, &b.name).cmp(&(a.size, &a.name)));
types.dedup();

if options.remove_wrappers {
remove_wrappers(&mut types);
}

expand(&mut types, &options.expand);

types.truncate(options.limit);
Expand Down
3 changes: 1 addition & 2 deletions tests/snapshots/alignment_enum/output-ws-h16.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,4 @@
source: tests/runner.rs
description: top-type-sizes -ws -h16
---
8 std::ptr::alignment::AlignmentEnum64 align=8
0 variant _Align1Shl0, _Align1Shl1, _Align1Shl2, _Align1Shl3, _Align1Shl4, _Align1Shl5, _Align1Shl6, _Align1Shl7, _Align1Shl8, _Align1Shl9, _Align1Shl10, _Align1Shl11, _Align1Shl12, _Align1Shl13, _Align1Shl14, _Align1Shl15, _Align1Shl16, _Align1Shl17, _Align1Shl18, _Align1Shl19, _Align1Shl20, _Align1Shl21, _Align1Shl22, _Align1Shl23, _Align1Shl24, _Align1Shl25, _Align1Shl26, _Align1Shl27, _Align1Shl28, _Align1Shl29, _Align1Shl30, _Align1Shl31, _Align1Shl32, _Align1Shl33, _Align1Shl34, _Align1Shl35, _Align1Shl36, _Align1Shl37, _Align1Shl38, _Align1Shl39, _Align1Shl40, _Align1Shl41, _Align1Shl42, _Align1Shl43, _Align1Shl44, _Align1Shl45, _Align1Shl46, _Align1Shl47, _Align1Shl48, _Align1Shl49, _Align1Shl50, _Align1Shl51, _Align1Shl52, _Align1Shl53, _Align1Shl54, _Align1Shl55, _Align1Shl56, _Align1Shl57, _Align1Shl58, _Align1Shl59, _Align1Shl60, _Align1Shl61, _Align1Shl62, _Align1Shl63
no types found
11 changes: 0 additions & 11 deletions tests/snapshots/async_fn/output-h8.snap
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,3 @@ description: top-type-sizes -h8

8192 std::mem::ManuallyDrop<[u8; 8192]> align=1
8192 value

1 std::task::Poll<()> align=1
0 variant Ready, Pending

1 std::mem::MaybeUninit<[async fn body@$DIR/async.rs:6:17: 6:19]> align=1
1 variant MaybeUninit

1 std::mem::ManuallyDrop<[async fn body@$DIR/async.rs:6:17: 6:19]> align=1

1 [async fn body@$DIR/async.rs:6:17: 6:19] align=1
0 variant Unresumed, Returned, Panicked
6 changes: 0 additions & 6 deletions tests/snapshots/async_fn/output-ws-h16.snap
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,3 @@ description: top-type-sizes -ws -h16
8192 arg
8192 variant Unresumed, Returned, Panicked
8192 arg (upvar) align=1 offset=0

1 std::task::Poll<()> align=1
0 variant Ready, Pending

1 [async fn body@$DIR/async.rs:6:17: 6:19] align=1
0 variant Unresumed, Returned, Panicked

0 comments on commit c55646a

Please sign in to comment.