Close the plan: screenshots and a measured performance pass
- docs/screenshots: nineteen pages captured with headless Chromium from a running instance; README gains a screenshot section - tests/perf: opt-in load test (NOEMA_PERF=1) seeding 60k events, 6k memories and 1.5k beliefs across two minds, timing sixteen hot reads against a 400 ms ceiling and rejecting sequential-scan plans - migration 0016: indexes the test found missing (memories by mind and recency, beliefs by mind and confidence, events by mind and category, belief versions by mind and time) - docs/performance.md records the numbers and how to rerun
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
# Performance pass
|
||||
|
||||
`tests/perf` is an opt-in load test. It seeds a fresh schema with a realistic
|
||||
volume for one mind plus a second "noise" mind (so scoping matters), times
|
||||
the hot read paths in steady state, and rejects any plan that sequentially
|
||||
scans the three large tables.
|
||||
|
||||
```
|
||||
NOEMA_PERF=1 NOEMA_TEST_DATABASE_URL=postgres://... go test -count=1 -v -run TestHotPaths ./tests/perf/
|
||||
```
|
||||
|
||||
Seed: 60 000 events, 6 000 memories, 1 500 beliefs with evidence. Ceiling per
|
||||
read: 400 ms (a regression guard, not a target).
|
||||
|
||||
## Results (PostgreSQL 16 in Docker, laptop, 2026-09-14)
|
||||
|
||||
| Read | Before 0016 | After 0016 |
|
||||
|---|---|---|
|
||||
| events recent 50 | 3.2 ms | 1.2 ms |
|
||||
| events by type | 1.8 ms | 1.1 ms |
|
||||
| events after seq (runtime cursor) | 2.2 ms | 1.2 ms |
|
||||
| events summary search | 3.3 ms | 1.4 ms |
|
||||
| events stats (group by category) | 13.8 ms | 15.8 ms |
|
||||
| memory list 50 | 4.1 ms (seq scan) | 0.5 ms |
|
||||
| memory text search | 1.7 ms | 0.5 ms |
|
||||
| memory fused retrieve | 31 ms | 27 ms |
|
||||
| beliefs list | 3.6 ms (seq scan) | 3.6 ms |
|
||||
| beliefs search / contested / uncertain / stats / recent changes | ≤ 3 ms | ≤ 3 ms |
|
||||
| snapshot capture (all state tables) | 288 ms | 296 ms |
|
||||
|
||||
Migration `0016_hot_path_indexes` adds the indexes the planner needed for the
|
||||
two list orders that had fallen back to sequential scans, plus
|
||||
`(mind_id, category, seq)` on events for replay's stimulus scan and
|
||||
`(mind_id, created_at)` on belief versions for the recent-changes view.
|
||||
|
||||
## What was deliberately left alone
|
||||
|
||||
- **Fused retrieval (~27 ms)** is the most expensive per-cycle read; it runs a
|
||||
ranked full-text query capped at 50 candidates plus optional vector search.
|
||||
It is well inside the cycle budget; tune only if cycle latency becomes visible.
|
||||
- **Snapshot capture (~300 ms)** serialises every state table; it is an
|
||||
operator action, not a cycle path.
|
||||
- **Event stats (~16 ms)** is a group-by over all of a mind's events, used on
|
||||
the overview page. A materialised counter would be premature at this volume.
|
||||
|
||||
## Rerun before touching queries
|
||||
|
||||
The plan checks fail loudly when a future query drifts off its index, which is
|
||||
the cheapest way to catch a regression that would otherwise only show up with
|
||||
months of history.
|
||||
Reference in New Issue
Block a user