Files
vac-optimizer/docs/benchmark/pr-278-immutable-date-counts.md
T

62 lines
3.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# PR #278: reuse counts for immutable calendar dates
Measured on 2026-10-16 against `c7e7abc`, which already includes the
[direct date-key optimization](pr-278-date-keys.md).
A loaded-year CPU profile attributed 4.06 of 69.37 seconds to repeatedly counting
distinct non-working dates for time-off-period objectives. The existing calendar
cache already shares frozen date arrays between candidate plans, but each score
rebuilt a `Set` to count the same dates again.
The objective evaluator now keeps those counts in a `WeakMap` keyed by the frozen
array. Mutable arrays are recounted on every evaluation. The weak keys allow
unused arrays to be collected, and configuration validation and duplicate-date
handling remain intact. This change touches only that scoring operation.
## Before and after
Both protocol runs used Node 24.18.0, Bun 1.3.14 and Vitest 5.0.3 on the same local
machine. The baseline is the completed run recorded for `c7e7abc`; its saved core
bundle is byte-for-byte identical to a fresh bundle of that commit. No other
test, build or profiling workload ran alongside either protocol measurement.
```sh
NODE_OPTIONS=--max-old-space-size=2048 timeout 300s bunx vitest run src/app/benchmark/leave-planner-benchmark.spec.ts --maxWorkers=1
```
All seven warm-ups, fourteen measured calculations, the typed-obligation precheck,
fixtures, assertions and resource limits remain unchanged.
| Measurement | Before | After |
| ---------------------------------------------- | --------: | --------: |
| Entire command, external wall time | 268.573 s | 256.034 s |
| Benchmark test | 263.265 s | 250.652 s |
| Loaded year, mean of two measured calculations | 67.747 s | 64.360 s |
| Headroom before timeout | 31.427 s | 43.966 s |
The full command was 4.7% faster in this pair. Both runs completed successfully,
and every repeated scenario remained deterministic. Live CI performance still
needs confirmation.
An isolated check using the loaded-year plan's frozen date arrays took
551–554 ms before and 46–57 ms after for 100,000 scoring calls, following 5,000
warm-ups per run in before/after/after/before order. That result isolates the repeated
counting cost; the protocol above measures its effect on complete calculations.
## Correctness checks
Complete outcomes, stable explanations and final-state snapshots match `c7e7abc`
for all seven scenarios. These separate comparisons ran alongside functional
checks; their diagnostic timings are not used in the protocol comparison.
The functional coverage suite passes all 638 tests across 33 files. Three new
regression cases cover duplicate dates and changes to mutable arrays alongside
frozen arrays for sum, count and maximum scores. Application and spec type checks,
lint, formatting and `git diff --check` also pass.
No browser timing run or live CI rerun was performed for this change.
Diagnostic sources, profiles, bundles and full logs are retained in
`/tmp/vac-opt278-step2`. The original core diagnostic runner is documented in
[issue-78.md](issue-78.md#reproduction).