Skip to content

add feature gate to permit measuring memory usage of dyn upcasting #112355

Closed
@nikomatsakis

Description

@nikomatsakis

@WaffleLapkin is preparing a PR to permit measuring memory usage of dyn upcasting to help gather data for concerns raised in #65991. The lang team is generally in favor of gathering data but we don't want to wait infinitely long. Opening this issue to track this work.

Instructions on how to measure trait upcasting effects on your codebase

You need a recent nightly compiler — 2023-06-14 or newer.

If you are using cargo, run cargo clean && RUSTFLAGS="-Zprint-vtable-sizes" cargo check. Note that cargo clean is required — without it caching will silence the output. If you are using rustc directly pass -Zprint-vtable-sizes to it.

The output will contain lines like these:

print-vtable-sizes { "crate_name": "num_traits", "trait_name": "RefNum", "entries": "23", "entries_ignoring_upcasting": "13", "entries_for_upcasting": "10", "upcasting_cost_percent": "76.92307692307693" }
print-vtable-sizes { "crate_name": "num_traits", "trait_name": "NumAssignOps", "entries": "12", "entries_ignoring_upcasting": "8", "entries_for_upcasting": "4", "upcasting_cost_percent": "50" }
print-vtable-sizes { "crate_name": "num_traits", "trait_name": "NumOps", "entries": "12", "entries_ignoring_upcasting": "8", "entries_for_upcasting": "4", "upcasting_cost_percent": "50" }
print-vtable-sizes { "crate_name": "num_traits", "trait_name": "cast::ToPrimitive", "entries": "17", "entries_ignoring_upcasting": "17", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" }
print-vtable-sizes { "crate_name": "num_traits", "trait_name": "ops::inv::Inv", "entries": "4", "entries_ignoring_upcasting": "4", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" }
print-vtable-sizes { "crate_name": "num_traits", "trait_name": "ops::mul_add::MulAdd", "entries": "4", "entries_ignoring_upcasting": "4", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" }
print-vtable-sizes { "crate_name": "num_traits", "trait_name": "ops::mul_add::MulAddAssign", "entries": "4", "entries_ignoring_upcasting": "4", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" }
print-vtable-sizes { "crate_name": "num_traits", "trait_name": "pow::Pow", "entries": "4", "entries_ignoring_upcasting": "4", "entries_for_upcasting": "0", "upcasting_cost_percent": "0" }

print-vtable-sizes followed by a json describing vtable sizes. Json will contain the following fields:

  • crate_name — name of the crate which defines the traits
  • trait_name — path to the trait
  • entries — number of entries in a vtable with the current algorithm (i.e. with upcasting)
  • entries_ignoring_upcasting — number of entries in a vtable, as-if we did not have trait upcasting
  • entries_for_upcasting — number of entries in a vtable needed solely for upcasting (i.e. entries - entries_ignoring_upcasting).
  • upcasting_cost_percent — cost of having upcasting in % relative to the number of entries without upcasting (i.e. entries_for_upcasting / entries_ignoring_upcasting * 100%).

Lines are sorted by upcasting_cost_percent, so that the biggest % change is first.

You can collect and analyze these stats however your want.

Some important notes:

  1. This includes private traits
  2. This includes traits that are not meant to be used as dyn and/or vtables of which are never actually instantiated
  3. For traits with generics/associated types this can produce slightly misleading stats (only making the change bigger than it actually is)
  4. This does not include traits which are not object safe

Metadata

Metadata

Assignees

Labels

F-trait_upcasting`#![feature(trait_upcasting)]`T-langRelevant to the language team

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions