Skip to content

perf: move ref into the Core.Context cold subobject - #15027

Draft
Kha wants to merge 2 commits into
masterfrom
core-context-cold-ref
Draft

perf: move ref into the Core.Context cold subobject#15027
Kha wants to merge 2 commits into
masterfrom
core-context-cold-ref

Conversation

@Kha

@Kha Kha commented Sep 4, 2026

Copy link
Copy Markdown
Member

No description provided.

Kha and others added 2 commits September 4, 2026 11:06
…bobject

This PR cuts the reference count traffic paid by the recursion-depth and `withRef` steps that dominate elaboration, from ten increments per reconstruction to three. Measured against master it saves between 0.35% and 1.24% of elaboration instructions across match-, simp- and grind-heavy workloads.

`withReader` can never reuse the `Context` record, so every reconstruction pays one increment per pointer field. The original split classified fields by their number of update *sites*; this classifies them by measured update *frequency* instead. On a representative module `withIncRecDepth` runs about 1.0M times and `withRef` about 31k, while `withOptions` runs once, so `options`, `maxRecDepth`, `currNamespace`, `openDecls`, `initHeartbeats`, `maxHeartbeats` and `currMacroScope` join the cold group and only `currRecDepth` and `ref` stay hot. The `Context` constructor goes from `(0, 10, 2)` to `(0, 3, 2)`.

Rebuilding the wider cold record does make the rare paths that update those fields more expensive: `withCurrHeartbeats` goes from ten increments to fourteen. At roughly 4.9k such calls against 1.05M reconstructions, the trade is strongly positive.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This PR removes the last per-recursion-step reference count increment on a thread-shared object, leaving `withIncRecDepth` copying only the cold subobject pointer. The instruction saving is small, but the increment it removes is expected to be a contended atomic one, so the effect on wall-clock should be larger than on instructions.

`ref` points into the command's parsed syntax tree, which is shared with async elaboration tasks and therefore marked multi-threaded, making each increment on it a locked read-modify-write. The cold subobject is instead rebuilt often enough (about 18k times per module, by `withFreshMacroScope` and `withCurrHeartbeats`) that its instances are usually fresh, single-threaded and cheap to increment. Moving `ref` across therefore trades roughly 1.0M contended increments on the recursion path for about 155k on the 31k `withRef` calls that now rebuild the cold record.

Measured on a representative module, `withIncRecDepth` drops from three increments to two and `withRef` rises from three to fourteen; the `Context` constructor becomes `(0, 2, 2)`. The trade rests on `withRef` staying far rarer than `withIncRecDepth` — about 31k against 1.0M there — so it should be checked on syntax-heavy workloads before being relied upon.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Kha

Kha commented Sep 4, 2026

Copy link
Copy Markdown
Member Author

!bench

@leanprover-radar

leanprover-radar commented Sep 4, 2026

Copy link
Copy Markdown

Benchmark results for 1ed4f9a against 5877442 are in. There are significant results. @Kha

  • build//instructions: -30.3G (-0.27%)

Medium changes (1✅)

  • elab/simp_local//instructions: -254.2M (-0.85%)

Small changes (92✅, 8🟥)

  • build/module/Init.Data.Array.Attach//instructions: -37.0M (-0.37%)
  • build/module/Init.Data.Array.Basic//instructions: -41.6M (-0.39%)
  • build/module/Init.Data.Array.Find//instructions: -52.2M (-0.55%)
  • build/module/Init.Data.Array.Lemmas//instructions: -211.9M (-0.41%)
  • build/module/Init.Data.Array.Lex.Lemmas//instructions: -62.2M (-0.67%)
  • build/module/Init.Data.Array.MapIdx//instructions: -39.3M (-0.46%)
  • build/module/Init.Data.BitVec.Bitblast//instructions: -170.2M (-0.35%)
  • build/module/Init.Data.Dyadic.Basic//instructions: -65.5M (-0.49%)
  • build/module/Init.Data.Int.DivMod.Bootstrap//instructions: -35.6M (-0.68%)
  • build/module/Init.Data.Iterators.Lemmas.Combinators.FilterMap//instructions: -102.0M (-0.55%)
  • build/module/Init.Data.Iterators.Lemmas.Combinators.Monadic.FilterMap//instructions: -188.0M (-0.54%)
  • build/module/Init.Data.Iterators.Lemmas.Combinators.Monadic.FlatMap//instructions: -38.4M (-0.48%)
  • build/module/Init.Data.Iterators.Lemmas.Consumers.Loop//instructions: -55.6M (-0.54%)
  • build/module/Init.Data.Iterators.Lemmas.Consumers.Monadic.Loop//instructions: -66.4M (-0.57%)
  • build/module/Init.Data.List.Basic//instructions: -61.7M (-0.48%)
  • build/module/Init.Data.List.Erase//instructions: -34.1M (-0.50%)
  • build/module/Init.Data.List.Find//instructions: -109.6M (-0.59%)
  • build/module/Init.Data.List.Lemmas//instructions: -195.0M (-0.52%)
  • build/module/Init.Data.List.Lex//instructions: -45.9M (-0.55%)
  • build/module/Init.Data.List.MapIdx//instructions: -36.8M (-0.42%)
  • and 80 more

@Kha Kha added the downstream-force Force creation of a downstream-lean4 adaptation PR. label Sep 4, 2026
@github-actions github-actions Bot added the toolchain-available A toolchain is available for this PR, at leanprover/lean4-pr-releases:pr-release-NNNN label Sep 4, 2026
@mathlib-lean-pr-testing

Copy link
Copy Markdown

Mathlib CI status (docs):

  • ❗ Mathlib CI can not be attempted yet, as the nightly-testing-2026-09-04 tag does not exist there yet. We will retry when you push more commits. If you rebase your branch onto nightly-with-mathlib, Mathlib CI should run now. You can force Mathlib CI using the force-mathlib-ci label. (2026-09-04 13:34:52)

@downstream-lean4

Copy link
Copy Markdown

The adaptation PR for this PR is leanprover/downstream-lean4#46.

@leanprover-bot leanprover-bot added the builds-manual CI has verified that the Lean Language Reference builds against this PR label Sep 4, 2026
@leanprover-bot

leanprover-bot commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Reference manual CI status:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

builds-manual CI has verified that the Lean Language Reference builds against this PR downstream-force Force creation of a downstream-lean4 adaptation PR. toolchain-available A toolchain is available for this PR, at leanprover/lean4-pr-releases:pr-release-NNNN

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants