Skip to content

perf: cache elaboration of section variables across commands - #14595

Draft
marcelolynch wants to merge 1 commit into
leanprover:masterfrom
marcelolynch:sectionvars-cache-pr
Draft

perf: cache elaboration of section variables across commands#14595
marcelolynch wants to merge 1 commit into
leanprover:masterfrom
marcelolynch:sectionvars-cache-pr

Conversation

@marcelolynch

Copy link
Copy Markdown
Contributor

This PR caches the elaboration of section variables. Before this change, runTermElabM re-elaborated the binders of every variable command in scope for each command. A binder type whose class takes instance-implicit arguments, for example [Module R M], runs type-class synthesis on each re-elaboration. In long Mathlib sections, this cost reaches 20–30% of the instructions of a module (see the analysis in the discussion of leanprover-community/mathlib4#42214, which removes dead binders for this reason; live binders pay the same cost).

The cache stores the elaborated binders of the current scope as a closed telescope in the command state. A command reuses the telescope when two checks pass: the scope is the same object (pointer identity, so any scope change invalidates), and the instance table has the same revision (a new Meta.Instances.revision counter). Reuse instantiates fresh level metavariables, so each command can still constrain the universes of the section variables independently. A block is not cached when its elaboration auto-binds implicit variables or universe names, leaves expression metavariables (variable (n : _)) or postponed universe constraints, or contains sorry. The reuse path replays the universeConstraintsCheckpoint and recursion-depth behavior of the elaboration path.

One intentional behavior change: with the cache, a global declaration between two commands of a scope does not change how the identifiers in earlier variable binders resolve for later commands. Before, a mid-section def Nat := Unit silently changed the type of a section variable (x : Nat) for subsequent declarations of the scope. The cache freezes the meaning of a binder at its first elaboration in the scope. Set the new option Elab.cacheSectionVars to false to restore the old behavior; tests/elab/sectionVarsCache.lean documents the invariants and this change.

Validation: a differential run of all 3097 files in tests/elab with the option on and off converged to no behavioral differences. The remaining diffs are environmental (timings, backtrace addresses, random bytes, pointer values, task interleavings), one metavariable index in an error message (the test driver strips these), and the documented resolution change. The differential run also found the need for three of the guards above, which shows the method works. A microbenchmark (80 trivial theorems under 20 instance binders) drops from 0.17s to 0.08s, against a 0.07s floor without binders.

This is a draft to run the Mathlib benchmarks through a lean-pr-testing toolchain and measure the real-world gain. Known limitation for review: commands that reuse the cache do not emit binder info nodes for the section variables, so go-to-definition on a section variable use inside such a command may degrade in the language server; this needs a decision on how to re-attach the info cheaply.

🤖 Generated with Claude Code

@marcelolynch
marcelolynch force-pushed the sectionvars-cache-pr branch from 03fd3bc to dc65ebd Compare July 29, 2026 15:54
@marcelolynch

Copy link
Copy Markdown
Contributor Author

!bench mathlib

@leanprover-radar

leanprover-radar commented Jul 29, 2026

Copy link
Copy Markdown

Benchmark results for leanprover-community/mathlib4-nightly-testing@1bd09a6 against leanprover-community/mathlib4-nightly-testing@51fd0ce are in. There are significant results. @marcelolynch

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

Large changes (2✅)

  • build/module/Mathlib.Algebra.Star.NonUnitalSubalgebra//instructions: -21.1G (-20.66%)
  • and 1 hidden

Medium changes (11✅, 1🟥)

  • build/module/Mathlib.Algebra.Algebra.Equiv//instructions: -3.8G (-9.72%)
  • build/module/Mathlib.Algebra.Lie.Basic//instructions: -4.7G (-9.75%)
  • build/module/Mathlib.Algebra.Lie.Submodule//instructions: -4.8G (-8.69%)
  • 🟥 build/module/Mathlib.AlgebraicTopology.SimplicialSet.NerveAdjunction//instructions: +19.6G (+20.83%)
  • build/module/Mathlib.Analysis.Calculus.ContDiff.Defs//instructions: -10.7G (-9.92%)
  • build/module/Mathlib.Analysis.Calculus.ContDiff.FTaylorSeries//instructions: -15.8G (-13.12%)
  • build/module/Mathlib.Analysis.Calculus.FormalMultilinearSeries//instructions: -7.4G (-17.84%)
  • build/module/Mathlib.Analysis.Convolution//instructions: -13.8G (-12.15%)
  • build/module/Mathlib.LinearAlgebra.TensorProduct.Tower//instructions: -22.3G (-15.83%)
  • build/module/Mathlib.RepresentationTheory.Continuous.TopRep//instructions: -4.3G (-9.78%)
  • build/module/Mathlib.SetTheory.Cardinal.Cofinality.Club//instructions: -5.4G (-18.63%)
  • build/module/Mathlib.Topology.MetricSpace.IsometricSMul//instructions: -2.5G (-9.47%)

Small changes (62✅)

  • build/module/Mathlib.Algebra.Algebra.Hom//instructions: -1.3G (-6.64%)
  • build/module/Mathlib.Algebra.Algebra.NonUnitalSubalgebra//instructions: -2.5G (-3.86%)
  • build/module/Mathlib.Algebra.Algebra.Subalgebra.Basic//instructions: -2.1G (-4.79%)
  • build/module/Mathlib.Algebra.Algebra.Tower//instructions: -2.0G (-9.90%)
  • build/module/Mathlib.Algebra.Category.ModuleCat.Differentials.Presheaf//instructions: -1.6G (-5.20%)
  • build/module/Mathlib.Algebra.Category.ModuleCat.Presheaf.Sheafify//instructions: -1.8G (-3.62%)
  • build/module/Mathlib.Algebra.Category.ModuleCat.Sheaf.Free//instructions: -1.0G (-4.80%)
  • build/module/Mathlib.Algebra.Homology.ShortComplex.Homology//instructions: -1.8G (-5.16%)
  • build/module/Mathlib.Algebra.Lie.Abelian//instructions: -1.4G (-5.14%)
  • build/module/Mathlib.Algebra.Lie.Ideal//instructions: -3.4G (-13.25%)
  • build/module/Mathlib.Algebra.Lie.IdealOperations//instructions: -1.6G (-8.48%)
  • build/module/Mathlib.Algebra.Lie.Nilpotent//instructions: -2.3G (-4.77%)
  • build/module/Mathlib.Algebra.Lie.Subalgebra//instructions: -1.7G (-4.82%)
  • build/module/Mathlib.Algebra.Module.Presentation.Basic//instructions: -1.3G (-5.66%)
  • build/module/Mathlib.Algebra.Module.Submodule.Defs//instructions: -785.6M (-5.54%)
  • build/module/Mathlib.Algebra.Polynomial.Basic//instructions: -2.0G (-5.24%)
  • build/module/Mathlib.Algebra.Polynomial.Div//instructions: -1.3G (-3.81%)
  • build/module/Mathlib.Algebra.Polynomial.Eval.Defs//instructions: -2.5G (-9.94%)
  • build/module/Mathlib.Algebra.Polynomial.Roots//instructions: -1.7G (-4.13%)
  • build/module/Mathlib.Algebra.Ring.Subring.Basic//instructions: -2.9G (-6.03%)
  • and 42 more

@github-actions github-actions Bot added toolchain-available A toolchain is available for this PR, at leanprover/lean4-pr-releases:pr-release-NNNN mathlib4-nightly-available A branch for this PR exists at leanprover-community/mathlib4-nightly-testing:lean-pr-testing-NNNN labels Jul 29, 2026
@leanprover-bot leanprover-bot added the builds-manual CI has verified that the Lean Language Reference builds against this PR label Jul 29, 2026
@leanprover-bot

leanprover-bot commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Reference manual CI status:

@mathlib-lean-pr-testing mathlib-lean-pr-testing Bot added the builds-mathlib CI has verified that Mathlib builds against this PR label Jul 29, 2026
@mathlib-lean-pr-testing

Copy link
Copy Markdown

Mathlib CI status (docs):

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@marcelolynch
marcelolynch force-pushed the sectionvars-cache-pr branch from dc65ebd to c393a43 Compare July 29, 2026 19:23
@marcelolynch

Copy link
Copy Markdown
Contributor Author

!bench mathlib

@leanprover-radar

Copy link
Copy Markdown

Benchmark results for leanprover-community/mathlib4-nightly-testing@1bd09a6 against leanprover-community/mathlib4-nightly-testing@51fd0ce are in. (These commits have already been benchmarked in a previous command.) There are significant results. @marcelolynch

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

Large changes (2✅)

  • build/module/Mathlib.Algebra.Star.NonUnitalSubalgebra//instructions: -21.1G (-20.66%)
  • and 1 hidden

Medium changes (11✅, 1🟥)

  • build/module/Mathlib.Algebra.Algebra.Equiv//instructions: -3.8G (-9.72%)
  • build/module/Mathlib.Algebra.Lie.Basic//instructions: -4.7G (-9.75%)
  • build/module/Mathlib.Algebra.Lie.Submodule//instructions: -4.8G (-8.69%)
  • 🟥 build/module/Mathlib.AlgebraicTopology.SimplicialSet.NerveAdjunction//instructions: +19.6G (+20.83%)
  • build/module/Mathlib.Analysis.Calculus.ContDiff.Defs//instructions: -10.7G (-9.92%)
  • build/module/Mathlib.Analysis.Calculus.ContDiff.FTaylorSeries//instructions: -15.8G (-13.12%)
  • build/module/Mathlib.Analysis.Calculus.FormalMultilinearSeries//instructions: -7.4G (-17.84%)
  • build/module/Mathlib.Analysis.Convolution//instructions: -13.8G (-12.15%)
  • build/module/Mathlib.LinearAlgebra.TensorProduct.Tower//instructions: -22.3G (-15.83%)
  • build/module/Mathlib.RepresentationTheory.Continuous.TopRep//instructions: -4.3G (-9.78%)
  • build/module/Mathlib.SetTheory.Cardinal.Cofinality.Club//instructions: -5.4G (-18.63%)
  • build/module/Mathlib.Topology.MetricSpace.IsometricSMul//instructions: -2.5G (-9.47%)

Small changes (62✅)

  • build/module/Mathlib.Algebra.Algebra.Hom//instructions: -1.3G (-6.64%)
  • build/module/Mathlib.Algebra.Algebra.NonUnitalSubalgebra//instructions: -2.5G (-3.86%)
  • build/module/Mathlib.Algebra.Algebra.Subalgebra.Basic//instructions: -2.1G (-4.79%)
  • build/module/Mathlib.Algebra.Algebra.Tower//instructions: -2.0G (-9.90%)
  • build/module/Mathlib.Algebra.Category.ModuleCat.Differentials.Presheaf//instructions: -1.6G (-5.20%)
  • build/module/Mathlib.Algebra.Category.ModuleCat.Presheaf.Sheafify//instructions: -1.8G (-3.62%)
  • build/module/Mathlib.Algebra.Category.ModuleCat.Sheaf.Free//instructions: -1.0G (-4.80%)
  • build/module/Mathlib.Algebra.Homology.ShortComplex.Homology//instructions: -1.8G (-5.16%)
  • build/module/Mathlib.Algebra.Lie.Abelian//instructions: -1.4G (-5.14%)
  • build/module/Mathlib.Algebra.Lie.Ideal//instructions: -3.4G (-13.25%)
  • build/module/Mathlib.Algebra.Lie.IdealOperations//instructions: -1.6G (-8.48%)
  • build/module/Mathlib.Algebra.Lie.Nilpotent//instructions: -2.3G (-4.77%)
  • build/module/Mathlib.Algebra.Lie.Subalgebra//instructions: -1.7G (-4.82%)
  • build/module/Mathlib.Algebra.Module.Presentation.Basic//instructions: -1.3G (-5.66%)
  • build/module/Mathlib.Algebra.Module.Submodule.Defs//instructions: -785.6M (-5.54%)
  • build/module/Mathlib.Algebra.Polynomial.Basic//instructions: -2.0G (-5.24%)
  • build/module/Mathlib.Algebra.Polynomial.Div//instructions: -1.3G (-3.81%)
  • build/module/Mathlib.Algebra.Polynomial.Eval.Defs//instructions: -2.5G (-9.94%)
  • build/module/Mathlib.Algebra.Polynomial.Roots//instructions: -1.7G (-4.13%)
  • build/module/Mathlib.Algebra.Ring.Subring.Basic//instructions: -2.9G (-6.03%)
  • and 42 more

@marcelolynch

Copy link
Copy Markdown
Contributor Author

!bench mathlib

@leanprover-radar

Copy link
Copy Markdown

Benchmark results for leanprover-community/mathlib4-nightly-testing@1bd09a6 against leanprover-community/mathlib4-nightly-testing@51fd0ce are in. (These commits have already been benchmarked in a previous command.) There are significant results. @marcelolynch

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

Large changes (2✅)

  • build/module/Mathlib.Algebra.Star.NonUnitalSubalgebra//instructions: -21.1G (-20.66%)
  • and 1 hidden

Medium changes (11✅, 1🟥)

  • build/module/Mathlib.Algebra.Algebra.Equiv//instructions: -3.8G (-9.72%)
  • build/module/Mathlib.Algebra.Lie.Basic//instructions: -4.7G (-9.75%)
  • build/module/Mathlib.Algebra.Lie.Submodule//instructions: -4.8G (-8.69%)
  • 🟥 build/module/Mathlib.AlgebraicTopology.SimplicialSet.NerveAdjunction//instructions: +19.6G (+20.83%)
  • build/module/Mathlib.Analysis.Calculus.ContDiff.Defs//instructions: -10.7G (-9.92%)
  • build/module/Mathlib.Analysis.Calculus.ContDiff.FTaylorSeries//instructions: -15.8G (-13.12%)
  • build/module/Mathlib.Analysis.Calculus.FormalMultilinearSeries//instructions: -7.4G (-17.84%)
  • build/module/Mathlib.Analysis.Convolution//instructions: -13.8G (-12.15%)
  • build/module/Mathlib.LinearAlgebra.TensorProduct.Tower//instructions: -22.3G (-15.83%)
  • build/module/Mathlib.RepresentationTheory.Continuous.TopRep//instructions: -4.3G (-9.78%)
  • build/module/Mathlib.SetTheory.Cardinal.Cofinality.Club//instructions: -5.4G (-18.63%)
  • build/module/Mathlib.Topology.MetricSpace.IsometricSMul//instructions: -2.5G (-9.47%)

Small changes (62✅)

  • build/module/Mathlib.Algebra.Algebra.Hom//instructions: -1.3G (-6.64%)
  • build/module/Mathlib.Algebra.Algebra.NonUnitalSubalgebra//instructions: -2.5G (-3.86%)
  • build/module/Mathlib.Algebra.Algebra.Subalgebra.Basic//instructions: -2.1G (-4.79%)
  • build/module/Mathlib.Algebra.Algebra.Tower//instructions: -2.0G (-9.90%)
  • build/module/Mathlib.Algebra.Category.ModuleCat.Differentials.Presheaf//instructions: -1.6G (-5.20%)
  • build/module/Mathlib.Algebra.Category.ModuleCat.Presheaf.Sheafify//instructions: -1.8G (-3.62%)
  • build/module/Mathlib.Algebra.Category.ModuleCat.Sheaf.Free//instructions: -1.0G (-4.80%)
  • build/module/Mathlib.Algebra.Homology.ShortComplex.Homology//instructions: -1.8G (-5.16%)
  • build/module/Mathlib.Algebra.Lie.Abelian//instructions: -1.4G (-5.14%)
  • build/module/Mathlib.Algebra.Lie.Ideal//instructions: -3.4G (-13.25%)
  • build/module/Mathlib.Algebra.Lie.IdealOperations//instructions: -1.6G (-8.48%)
  • build/module/Mathlib.Algebra.Lie.Nilpotent//instructions: -2.3G (-4.77%)
  • build/module/Mathlib.Algebra.Lie.Subalgebra//instructions: -1.7G (-4.82%)
  • build/module/Mathlib.Algebra.Module.Presentation.Basic//instructions: -1.3G (-5.66%)
  • build/module/Mathlib.Algebra.Module.Submodule.Defs//instructions: -785.6M (-5.54%)
  • build/module/Mathlib.Algebra.Polynomial.Basic//instructions: -2.0G (-5.24%)
  • build/module/Mathlib.Algebra.Polynomial.Div//instructions: -1.3G (-3.81%)
  • build/module/Mathlib.Algebra.Polynomial.Eval.Defs//instructions: -2.5G (-9.94%)
  • build/module/Mathlib.Algebra.Polynomial.Roots//instructions: -1.7G (-4.13%)
  • build/module/Mathlib.Algebra.Ring.Subring.Basic//instructions: -2.9G (-6.03%)
  • and 42 more

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 builds-mathlib CI has verified that Mathlib builds against this PR mathlib4-nightly-available A branch for this PR exists at leanprover-community/mathlib4-nightly-testing:lean-pr-testing-NNNN 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