Perf harness: fixture Homes, server scenarios, budgets #49

Closed
kayg wants to merge 1 commit from issue/44-perf-harness into dev
Owner

Closes #44 once the budgets are agreed. Builds the harness every feature is measured with (ADR 0005).

What is here

  • crates/fixtures (calternal-fixtures --notes 10k --seed 1 --out DIR): realistic Homes of 1k / 10k / 100k notes in the real on-disk format, byte-identical for a seed. ~30% daily notes (YYYY-MM-DD.md, log entries like - 09:12 - 09:48 text #tag, some written loosely), regular Notes/<Title>.md with frontmatter (calternal-id, title, date, last edited at +05:30, tags), H1, lists, tasks, quotes, code, [t](<path.md>) links, #tags, attachment refs; 1 in 2,000 notes has 50,000 words; 1% in Archive/, 2% without an id. Writes fixture.json with sample notes for the runner.
  • crates/perf (calternal-perf --bin target/release/calternal --work DIR --sizes 1k,10k,100k --runs 5): runs the real server binary.
    • cold.*: first start on a never-indexed Home: startup, first list, time until every note is indexed, disk written, peak RSS.
    • warm runs (fresh server each, page cache dropped with --drop-caches): startup.healthz, home.first_list / home.list, journal.catch_up (whole journal, 1k pages), open.note (room join until synced), open.api_get, open.long_note (50k words), sync.round_trip and sync.save_ack (one keystroke at a time, two clients), the edit storm (4 clients, 10k keystrokes each with a save check, window of 8, plus an outside app rewriting the file every 500 ms; checks all copies converge, every outside line exactly once, file == note after save), mem.* (RSS / HWM from /proc), storm.disk_written (/proc/pid/io), shutdown.
    • Report: median over runs of each run's p50 / p95, noise = spread of run p50s; markdown + JSON; --budgets perf/budgets.json --gate exits 1 on a breach. "gate": false marks targets the code doesn't meet yet.
  • perf/run-vm.sh: rsync, build and run on the perf VM, refusing to run while another benchmark is running. perf/browser.sh: wraps the existing @perf keystroke-to-paint Playwright test (phase two: feed it a big Home and the same report).
  • docs/perf/budgets.md: proposed budgets per metric.

Baseline numbers from the perf VM: see the comment on #44.

🤖 Generated with Claude Code

Closes #44 once the budgets are agreed. Builds the harness every feature is measured with (ADR 0005). ## What is here - **`crates/fixtures`** (`calternal-fixtures --notes 10k --seed 1 --out DIR`): realistic Homes of 1k / 10k / 100k notes in the real on-disk format, byte-identical for a seed. ~30% daily notes (`YYYY-MM-DD.md`, log entries like `- 09:12 - 09:48 text #tag`, some written loosely), regular `Notes/<Title>.md` with frontmatter (`calternal-id`, `title`, `date`, `last edited` at +05:30, `tags`), H1, lists, tasks, quotes, code, `[t](<path.md>)` links, `#tags`, attachment refs; 1 in 2,000 notes has 50,000 words; 1% in `Archive/`, 2% without an id. Writes `fixture.json` with sample notes for the runner. - **`crates/perf`** (`calternal-perf --bin target/release/calternal --work DIR --sizes 1k,10k,100k --runs 5`): runs the real server binary. - `cold.*`: first start on a never-indexed Home: startup, first list, time until every note is indexed, disk written, peak RSS. - warm runs (fresh server each, page cache dropped with `--drop-caches`): `startup.healthz`, `home.first_list` / `home.list`, `journal.catch_up` (whole journal, 1k pages), `open.note` (room join until synced), `open.api_get`, `open.long_note` (50k words), `sync.round_trip` and `sync.save_ack` (one keystroke at a time, two clients), the **edit storm** (4 clients, 10k keystrokes each with a save check, window of 8, plus an outside app rewriting the file every 500 ms; checks all copies converge, every outside line exactly once, file == note after save), `mem.*` (RSS / HWM from `/proc`), `storm.disk_written` (`/proc/pid/io`), `shutdown`. - Report: median over runs of each run's p50 / p95, noise = spread of run p50s; markdown + JSON; `--budgets perf/budgets.json --gate` exits 1 on a breach. `"gate": false` marks targets the code doesn't meet yet. - `perf/run-vm.sh`: rsync, build and run on the perf VM, refusing to run while another benchmark is running. `perf/browser.sh`: wraps the existing `@perf` keystroke-to-paint Playwright test (phase two: feed it a big Home and the same report). - `docs/perf/budgets.md`: proposed budgets per metric. Baseline numbers from the perf VM: see the comment on #44. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Perf harness: fixture Homes, server scenarios, budgets
All checks were successful
CI / rust (pull_request) Successful in 43s
CI / web (pull_request) Successful in 44s
0cae9381d2
`calternal-fixtures` makes realistic Homes (1k/10k/100k notes) in the real
on-disk format, byte-identical for a seed: daily notes with log entries,
regular notes with frontmatter (+05:30 times), links `[t](<path.md>)`,
tags, tasks, attachment refs, 1 in 2,000 notes at 50,000 words, some in a
subfolder, some without a `calternal-id`.

`calternal-perf` runs the real server binary on them: first-start indexing
(cold), then fresh servers on the indexed Home measuring startup to
/healthz, notes.list, journal catch-up, opening notes (room join and
notes.get), sync round trip and save ack, and an edit storm (4 clients,
10k keystrokes with save checks, plus an outside app rewriting the file)
that checks nothing was lost or doubled. RSS and disk bytes written come
from /proc. Median of runs per p50/p95 with a noise figure; budgets in
perf/budgets.json, --gate exits 1 on a breach.

perf/run-vm.sh runs it on the perf machine; perf/browser.sh wraps the
existing @perf keystroke-to-paint browser test.

Part of #44

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018Yyy8fQGxPLkLa8v8NXz7T
Author
Owner

Superseded by #87 (same branch content; this PR stopped picking up pushes on the forge).

Superseded by #87 (same branch content; this PR stopped picking up pushes on the forge).
kayg closed this pull request 2026-10-13 22:22:59 +00:00
All checks were successful
CI / rust (pull_request) Successful in 43s
CI / web (pull_request) Successful in 44s

Pull request closed

Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal!49
No description provided.