Repository navigation
Conversation
A formula that reads a single cell went through `reference_areas`, a Vec of areas and `area_value` before it reached `Host::cell_value`, and `cell_value` checked `pending` before the results it already had. On a sheet where most formulas read a few neighbouring cells, that overhead was a large share of recalculation time. - `Evaluator::value` reads a single-cell reference straight through `area_value`, with the same nesting checks as `eval` (now in `enter`). - `resolve_sheet` returns the sheet range instead of a Vec. - `PassHost::cell_value` looks in the results first (`known`), so a value calculated earlier in the pass costs one hash lookup. - `binary` only allocates for a chain of operators, not for `a+b`. Results are unchanged: tests cover single-cell reads (including 3-D references and errors), left-to-right operator chains, and the nesting limit reached by a recursive LAMBDA whose deepest call reads a cell. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
Evaluation depth checks crates/calc/src/eval.rs, crates/calc/src/tests.rs |
Evaluation entry checks stack budget and maximum depth before incrementing depth. Recursive-lambda tests now include a formula that reads a cell. |
Direct cell-reference values crates/calc/src/eval.rs, crates/calc/src/tests.rs |
Direct cell references resolve the sheet selection and read the cell for a single-sheet result. Tests cover on-demand evaluation, cross-sheet references, 3-D references, and error results. |
Binary operator chains crates/calc/src/eval.rs, crates/calc/src/tests.rs |
The evaluator applies the outer operator after folding the left-associated chain and evaluating the original right operand. Tests cover arithmetic, concatenation, and error propagation. |
Recalculation result lookup crates/calc/src/recalc/pass_host.rs |
PassHost retrieves known results and propagates iterative-calculation taint. cell_value returns known results before checking whether a cell is pending. |
Contributor metadata
| Layer / File(s) | Summary |
|---|---|
GitHub name synchronization contributors/people.toml |
The contributor metadata adds Clemens with GitHub name synchronization enabled. |
Priority:
Estimated code review effort: 3 (Moderate) | ~20 minutes
Change: Refactor
Possibly related issues
storytold/gridcraftissue 2161: The changes update evaluation depth and stack-budget checks, but do not add the issue’s proposed combined budget across evaluators.
Suggested reviewers: echelon, aiongg, dotcoocoo
Merge Risk: 
Minimal · up to 66a52
-
No merge-blocking issue was identified.
Pre-merge checks: 
4 · 
1
-
Failed checks: 1 warning Passed checks: 4 passedFull details: Docstring Coverage
-
Explanation
Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 10 functions across 3 files. (1 skipped: 1 unsupported.)
Resolution
Write docstrings for the functions missing them to satisfy the coverage threshold.
-
Finishing Touches
-
🧪 Generate unit tests (beta)
-
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Comment @coderabbitai help to get the list of available commands.
On a sheet where most formulas read a few neighbouring cells, recalculation spends much of its time on bookkeeping around each cell read rather than on the formulas. This PR removes some of that bookkeeping. Results stay the same, bit for bit, with one exception for
RANDdescribed below.Changes
Evaluator::valuereads a single-cell reference straight througharea_value. Before, it built aVecof areas througheval,reference_areasandderef. The nesting checks are the same:enter, now shared witheval.resolve_sheetreturns the sheet range instead of aVec.PassHost::cell_valuelooks in the pass's results first (known), so reading a cell calculated earlier in the pass takes one hash lookup instead of three.binaryallocates only for a chain of operators, not for a plaina+b.contributors/people.toml, as the file asks contributors to do in their own PR.Results stay the same
New tests cover:
#VALUE!), a missing sheet (#REF!), and a formula calculated on demand;MAX_DEPTHlimit, reached by a recursive LAMBDA whose deepest call reads a cell.The tests pass on
maintoo, so they pin the existing behaviour.One exception, which the tests don't reach: a single-cell read now takes fewer stack frames, so on a chain deep enough to run past
STACK_BUDGET, evaluation can suspend at a different formula than onmain. That changes the order formulas are calculated in, and with it whatRANDdraws. Results that don't depend on that order stay the same.A private production workbook (6 sheets, about 214,000 formulas) gives bit-identical values for 20 input cases on
mainand with this PR.Benchmarks
Median time of
formulas.calculateNowthroughgridcraft-cli: release build, manual calculation mode, 30 runs each, Apple M3 Pro.mainand this PR were measured alternately in the same session.mainsmall_formulaswindowsrunning_totalsstays at about 21 s with this PR (3 runs per build, which vary by about ±10%, too much to show a difference).On the private workbook, one input case (set the inputs,
calculateNow, read the results) takes 0.94 s onmainand 0.85 s with this PR. Each is the median of 3 runs of 20 cases, with the builds taking turns.Synthetic workbooks (openpyxl)
Related
This is one of three independent performance PRs that came out of profiling recalculation of one large workbook. The other two are #2953 (running
SUM/COUNT/AVERAGEover formula cells, building on #2691) and #2954 (column blocks of formula results, building on #2814). All three changecrates/calc/src/recalc/pass_host.rsnear each other. Whichever lands second may need a small rebase.🤖 Generated with Claude Code
Summary by CodeRabbit