-
-
Notifications
You must be signed in to change notification settings - Fork 15k
Consteval layout_of caching is surprisingly ineffective #157010
Copy link
Copy link
Open
Labels
A-const-evalArea: Constant evaluation, covers all const contexts (static, const fn, ...)Area: Constant evaluation, covers all const contexts (static, const fn, ...)A-layoutArea: Memory layout of typesArea: Memory layout of typesC-bugCategory: This is a bug.Category: This is a bug.I-compiletimeIssue: Problems and improvements with respect to compile times.Issue: Problems and improvements with respect to compile times.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.
Metadata
Metadata
Assignees
Labels
A-const-evalArea: Constant evaluation, covers all const contexts (static, const fn, ...)Area: Constant evaluation, covers all const contexts (static, const fn, ...)A-layoutArea: Memory layout of typesArea: Memory layout of typesC-bugCategory: This is a bug.Category: This is a bug.I-compiletimeIssue: Problems and improvements with respect to compile times.Issue: Problems and improvements with respect to compile times.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.
Type
Fields
Give feedbackNo fields configured for issues without a type.
When compiling
image@0.25.10without default features we expected that to be a rather quick affair of 7 additional dependencies, the slowest beingnum-traitswith 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 intoInterpCx::layout_ofqueries. 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: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: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_localwhich 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.