Files
HealthLog/scripts/bench/results/v1.45.0-read-path.md
T
Marc-André Bombeck a451a114a2 docs(bench): record the boot profile and the runtime results
The profile section in docs/contributing/benchmarks.md says how to run
scripts/bench/boot-profile.ts, what the profile of the v1.44 runtime
found (the worker graph as one 753 ms block, a live heap of about
165 MB of which the query compiler holds 50 and the catalogs 33) and what
changed. scripts/bench/results/v1.45.0-*.md hold the before and after
numbers per area, from back-to-back runs on the same machine. The size
baselines take the lowered numbers.
2026-10-22 09:10:14 +02:00

2.7 KiB

v1.45.0: read path

Request benchmark on the seeded account (1,265,561 rows), production build, web process, heap ceiling 792 MB, 20 requests per row, one at a time. v1.45.0-before is the v1.44 runtime (1915f9152), v1.45.0-final this branch; both on the same machine within the hour, load average 7 to 30 (other work on the host), so latency compares within a factor of noise and statements exactly. Cold means every request follows a one-row manual sync.

request before p50 / p95 ms after p50 / p95 ms statements before / after
dashboard snapshot, cold 1482 / 1526 545 / 593 158 / 153
dashboard summary, cold 170 / 221 87 / 101 31 / 30
series pulse 3650 d, cold 1627 / 1665 335 / 349 8 / 7
series pulse 3650 d, warm 2091 / 2435 328 / 346 8 / 7
series pulse 365 d, cold 184 / 193 41 / 56 8 / 7
series pulse 30 d, cold 24 / 31 19 / 27 8 / 8
insights health status, cold 245 / 401 156 / 190 68 / 67

What moved them:

  • JIT off for app sessions. Postgres compiled every fold whose estimated cost passed jit_above_cost; on the ten-year pulse pick that was 100 to 140 ms of a 220 ms statement (EXPLAIN ANALYZE: 395 ms with JIT, 220 ms without).
  • The canonical-source pick groups first. DISTINCT ON now sorts the distinct (type, day, source) triples instead of every raw reading (the ten-year pulse pick sorted 260,000 rows and spilled to disk); 220 ms to 175 ms on its own. Parity: tests/integration/canonical-source-pick-parity.test.ts runs the old statement beside the new one over five reader shapes and two ladders on a fixture with overlapping and off-ladder sources, tombstones, empty days and readings around midnight; identical rows.
  • The dense series reads its rows once. Buckets and strip figures come from one statement over a materialised window instead of two statements that each picked the canonical source and scanned the readings. Parity: tests/integration/dense-series-read-parity.test.ts, the two old statements as reference, pulse (two ranked sources), glucose and oxygen saturation, day and hour grains, UTC, Europe/Berlin, Asia/Kolkata and America/New_York; identical buckets and figures (relative 1e-9).
  • Closed blocks survive a sync. The slice's pre-fold remainder (every reading older than five years, the snapshot's largest statement at 357 ms) and the day view's past history blocks are cached under a key that names the instant their readings end before; a sync of newer readings no longer drops them (src/lib/cache/closed-block.ts). The values are the same statement's; only how long they are kept changed.