Skip to content

perf: stop the freeze on huge conversations and speed up filtering#19

Merged
brtkwr merged 1 commit into
fix/mouse-report-leakfrom
perf/cache-preview-lines
Jun 30, 2026
Merged

perf: stop the freeze on huge conversations and speed up filtering#19
brtkwr merged 1 commit into
fix/mouse-report-leakfrom
perf/cache-preview-lines

Conversation

@brtkwr

@brtkwr brtkwr commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

Three hot-path optimisations, all measured on the real corpus (314 conversations). Stacked on #18 (mouse-leak) - merge #18 first.

1. The freeze: memoise HITS per query

Scrolling to the very top/bottom of a result set froze the UI for seconds when a huge conversation (a 6,000-message session) sat at that boundary. Measured: the dominant per-frame cost is formatListItem recomputing the HITS count by scanning every message of every visible row (with a strings.ToLower allocation per message) every frame. Holding a clamped nav key queued those slow frames into a long freeze.

hitCounter memoises hit counts per query, keyed by SessionID. View: 65ms → 4.7ms/frame (8 big rows visible).

2. Memoise preview lines

previewCache memoises the selected conversation's preview lines (keyed by SessionID+query) so renderPreview/maxPreviewScroll don't rebuild every frame. (buildPreviewLines was ~8ms - not the freeze, but still wasteful every frame.)

3. Incremental filtering

updateFilter scanned all 314 conversations' searchLower every keystroke (~10ms for a long, rare query). When the new query contains the previous one, every new match already matched the old query, so it now filters the previous (smaller) result set. Steady-state narrowing: ~10ms → ~1-2ms/keystroke.

Caches

Both caches are pointer-held so they survive the value-receiver copies View makes, and invalidate when the query (or selection) changes.

Tests

  • TestHitCountCachedPerQuery, TestPreviewLinesCachedUntilSelectionOrQueryChanges - cached values returned without rescan; invalidate on change.
  • TestUpdateFilterIncrementalNarrowing - narrowing/broadening/clear all produce correct results.
  • go test, go vet green; coverage 63.4%.

@brtkwr brtkwr force-pushed the perf/cache-preview-lines branch from 3b5f044 to 1084a1f Compare June 30, 2026 07:51
@brtkwr brtkwr changed the base branch from main to fix/mouse-report-leak June 30, 2026 07:51
Navigating to a huge conversation (the top/bottom of a result set can be
a 6k-message session) froze the UI - holding a nav key at a list
boundary queued frames that each took ~65ms, dominated by formatListItem
recomputing the HITS count by scanning every message of every visible
row (with a strings.ToLower allocation per message) on every frame.

Measured on a 6016-message conversation with 8 big rows visible:
View was 65ms/frame; with these caches it's 4.7ms/frame.

- Memoise hit counts per query, keyed by SessionID (hitCounter), so
  formatListItem reads a cached count instead of rescanning each frame.
- Memoise the selected conversation's preview lines, keyed by
  SessionID+query (previewCache), so renderPreview / maxPreviewScroll
  don't rebuild every frame.

Both caches are pointer-held so they survive the value-receiver copies
View makes, and both invalidate when the query (or selection) changes.
@brtkwr brtkwr force-pushed the perf/cache-preview-lines branch from 1084a1f to 069f031 Compare June 30, 2026 08:01
@brtkwr brtkwr changed the title perf: memoise preview lines to stop freezing on huge conversations perf: memoise hit counts and preview lines to stop the freeze on huge conversations Jun 30, 2026
@brtkwr brtkwr merged commit 40d82b9 into fix/mouse-report-leak Jun 30, 2026
@brtkwr brtkwr changed the title perf: memoise hit counts and preview lines to stop the freeze on huge conversations perf: stop the freeze on huge conversations and speed up filtering Jun 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant