Skip to content

perf: stop scanning arrays where a lookup does, on large builds - #401

Merged
nGervasyuk merged 2 commits into
Visual-Regression-Tracker:masterfrom
nGervasyuk:perf/large-build-interactions
Aug 23, 2026
Merged

perf: stop scanning arrays where a lookup does, on large builds#401
nGervasyuk merged 2 commits into
Visual-Regression-Tracker:masterfrom
nGervasyuk:perf/large-build-interactions

Conversation

@nGervasyuk

@nGervasyuk nGervasyuk commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator

Problem

Reviewing a build of ~10 000 screenshots, list interactions cost hundreds of milliseconds each. CPU profiles taken in Chromium (10 000 runs, 500 screens × 20 locales) point at linear scans that run per row:

  • selection membership. Selecting every run of a build is one click. Each place that asks whether a run is selected walked the array of selected ids — the grouped selection model and the card count do it per run of every group, the bulk operations per row, and a card per run behind it. With 10 000 runs selected that is ~10⁸ comparisons per render.
  • the published run order. The list republishes the order the details dialog navigates on every grid state change. With thousands of runs that is a fresh array of that many ids landing in the context, re-rendering every consumer, even when the order is identical.
  • tag filter options. Collecting the values on offer built a throwaway array per run, thousands of allocations on every keystroke.

Change

  • index the selected ids in a Set and read membership off it; the card grid takes the set rather than the array, so it does not rebuild one per render
  • keep the previously published order when the new one is element-wise equal
  • read the tag fields straight off the run instead of collecting them into an array first

Measurements

Chromium, 10 000 runs, same harness before and after:

Interaction Before After
select all rows (table) 265 ms 90 ms
select all cards (grouped) 306 ms 120 ms
pick a Status filter 237 ms 165 ms
clear filters (Reset) 200 ms 149 ms
switch to the card view 138 ms 76 ms
open the build (table) 643 ms 521 ms

No hot frame is left in the profiles — what remains is React and MUI render work spread thin.

I also measured handing the data grid only the page it displays, since the list already filters, sorts and paginates itself: it moved opening a build from 521 ms to 486 ms and left the filter interactions unchanged, so it is not worth the change in sorting, selection and published-order semantics that it would need.

Unit (19) and Playwright (84) suites pass.


Nothing to configure. Independent of the other open frontend PRs (#397, #398, #399, #400, #401) — verified that they all merge onto master in sequence without conflicts, in any order.

@pashidlos pashidlos left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@nGervasyuk
nGervasyuk force-pushed the perf/large-build-interactions branch 2 times, most recently from 65d25c4 to 4bb14ed Compare August 23, 2026 06:36
Selecting every run of a build is one click, and each of the places that asks
whether a run is selected walked the array of selected ids: the grouped
selection model and card count do it per run of every group, the bulk
operations do it per row, and a card does it per run behind it. With ten
thousand runs selected that is a hundred million comparisons per render.

Index the selected ids in a set and read membership off it. Measured in
Chromium on a 10 000 run build:

  select all rows           265 ms -> 90 ms
  select all cards, grouped 306 ms -> 120 ms

The card grid takes the set itself rather than the array, so it does not
rebuild one per render.

The tag filter's options also stopped building an array per run while
collecting the values on offer — thousands of throwaway allocations on every
keystroke.
The list republishes the order the details dialog navigates on every grid
state change, which with thousands of runs means a fresh array of that many
ids landing in the context — and every consumer re-rendering — even when the
order is identical. Compare before storing, and keep the previous array when
nothing moved.
@nGervasyuk
nGervasyuk force-pushed the perf/large-build-interactions branch from 4bb14ed to ea41938 Compare August 23, 2026 06:42
@sonarqubecloud

Copy link
Copy Markdown

@nGervasyuk
nGervasyuk merged commit 21e3582 into Visual-Regression-Tracker:master Aug 23, 2026
3 checks passed
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.

2 participants