Skip to content

Consteval layout_of caching is surprisingly ineffective #157010

@197g

Description

@197g

When compiling image@0.25.10 without default features we expected that to be a rather quick affair of 7 additional dependencies, the slowest being num-traits with a build dependency. Instead, it's slow enough for issues being opened in our own issue tracker.

We investigated further and, with perf, found ~12% of build time spent in consteval of which almost all samples fell into InterpCx::layout_of queries. That was curious since we use a few const tables but definitely not of extreme size nor complicated computation and really only with primitive types. Through instrumenting a custom compiler build (printf debugging the types being queried), we found this pattern at the top of the summary:

RDTSC    count  type
-------
2968652 48376   u8
2975486 75647   usize
3372234 2024    std::num::NonZero<usize>
3494159 65639   FnDef(DefId(2:705 ~ core[93c5]::f64::{impl#0}::to_bits), [])
6016422 107343  ()
7589954 145971  FnDef(DefId(21:947 ~ pxfm[d8cc]::common::fmla), [])
10072816        175205  i64
15194244        290049  i32
22053787        392617  u32
22284234        322397  bool
40392452        615785  u64
58157921        2110    std::alloc::Layout
179631693       2996946 f64

Since there are far fewer than 2 million (monomorphized) lines in the whole dependency tree, this points to layouts being evaluated highly redundantly—once per evaluation of at least some statements / expression parts rather than what we'd rather want once per unique definition in MIR.

Meta

rustc --version --verbose:

rustc 1.95.0 (59807616e 2026-04-14)
binary: rustc
commit-hash: 59807616e1fa2540724bfbac14d7976d7e4a3860
commit-date: 2026-04-14
host: x86_64-unknown-linux-gnu
release: 1.95.0
LLVM version: 22.1.2

Development History

In PR #156718 I tried the idea of making the queries themselves faster by special-casing primitive types, which have known layouts that can be pre-interned thus replacing a function call with a few moves. This did yield a 2% but ultimately a weird case to make when the problematic behavior is the repetition of queries themselves.

Further instrumentation with the source of each layout call revealed that the vast majority was coming from InterpCx::layout_of_local which is itself more curious due to locals already having a cache attached to it per local that apparently is not hit, most of the time. As pointed out (#156718 (comment)) the design would explicitly not work for small const functions called multiple times due to it being attached to the frame of a call, not more directly to a MIR body.

count   source:type
------
164879  layout_of_local:i64
227240  layout_of_local:bool
270325  layout_of_local:u32
579206  layout_of_local:u64
2860447 layout_of_local:f64

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-const-evalArea: Constant evaluation, covers all const contexts (static, const fn, ...)A-layoutArea: Memory layout of typesC-bugCategory: This is a bug.I-compiletimeIssue: Problems and improvements with respect to compile times.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions