Skip to content

perf: viewport-scoped search highlight pre-computation#25

Open
kdkavanagh-agent wants to merge 2 commits intomasterfrom
perf/viewport-scoped-search-highlight-v2
Open

perf: viewport-scoped search highlight pre-computation#25
kdkavanagh-agent wants to merge 2 commits intomasterfrom
perf/viewport-scoped-search-highlight-v2

Conversation

@kdkavanagh-agent
Copy link
Copy Markdown
Collaborator

@kdkavanagh-agent kdkavanagh-agent commented Mar 25, 2026

Summary

Optimizes search highlight performance with two complementary techniques:

  1. Viewport-scoped is_in() — Instead of passing the entire search queue (up to 200k items) to is_in() on every render, pre-computes a __search_bg column by intersecting only the visible row indices with the search set. This reduces the is_in() input to at most ~1000 items (viewport height) instead of 200k.
  2. frozenset for O(1) membership — Converts active_search_queue to a frozenset for O(1) lookups in _get_sel_col_bg_color() instead of O(n) linear scan on a Python list.
  3. _resolve_row_bgcolor hook — Moves search highlight resolution out of the Polars expression tree and into a pre-computed column, eliminating per-row expression overhead during the hot scroll path.

Performance Results

Slowdown = (search_scroll_time - baseline_scroll_time) / baseline_scroll_time. Threshold: 15%.

Test Hits Screen Master (before) PR 25 (after) Improvement
single_match 1 120x30 0.1% -0.3% -
single_match 1 800x200 -2.3% -5.3% -
single_match 1 3000x1000 -1.0% 1.7% -
sparse_far_apart 200 120x30 0.8% 0.3% -
sparse_far_apart 200 800x200 -1.9% -3.8% -
sparse_far_apart 200 3000x1000 1.8% 1.2% -
many_adjacent 50,000 120x30 -0.9% -0.9% -
many_adjacent 50,000 800x200 4.6% 5.5% -
many_adjacent 50,000 3000x1000 6.1% 4.7% 1.4pp better
dense_most_rows 199,992 120x30 3.2% 2.0% 1.2pp better
dense_most_rows 199,992 800x200 13.7% 12.7% 1pp better, now passes
dense_most_rows 199,992 3000x1000 10.9% 8.2% 2.7pp better

All 12 tests pass (threshold: 15%). Previously dense_most_rows at 800x200 was intermittently failing at 15-16%.

Test plan

  • All 12 parametrized perf tests pass
  • All 27 existing functional tests pass
  • No changes to public API or user-visible behavior

Generated with Claude Code

Claude Code and others added 2 commits March 25, 2026 04:38
Parametrized tests measuring scroll performance with active search
highlights vs baseline across different search cardinalities (single
match, sparse, adjacent block, dense) and screen sizes (120x30,
800x200, 3000x1000). Tests fail if search scrolling is >15% slower.
Configured pytest-xdist with -n 2 for parallel execution.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the O(n) linear scan on active_search_queue list and the
per-render is_in(full_200k_list) Polars expression with a two-part
optimization:

1. Convert search queue to frozenset for O(1) membership tests
2. Pre-compute a __search_bg column in the viewport dataframe once
   per viewport rebuild, using only the visible indices intersected
   with the search set. This avoids rebuilding any Polars is_in
   expression during partial scroll updates (up/down keys).
3. Add _resolve_row_bgcolor hook in CustomTable so subclasses can
   apply row-level bgcolor adjustments in Python without modifying
   the Polars expression chain.

The search highlight is now read from the pre-computed column during
the segment iteration loop, eliminating all per-row overhead during
the hot scroll path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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