Skip to content

WebKit stall experiment (not to be merged) - #4234

Closed
nstepien wants to merge 1 commit into
mainfrom
webkit-stall-experiment
Closed

nstepien wants to merge 1 commit into
mainfrom
webkit-stall-experiment

Conversation

@nstepien

@nstepien nstepien commented Oct 25, 2026 •

Copy link
Copy Markdown
Collaborator

Experiment, not to be merged. Follows up on #4232: why does a WebKit page stop responding for seconds on Linux CI?

In run 40029118938, the focus click in test/setupBrowser.ts timed out while Playwright waited for the page itself, right after the million-row TreeDataGrid test, and after that grid had unmounted. That test bloats WebKit's web process by ~1.1 GB, and ~0.6 GB stays committed afterwards. One hypothesis is Linux WebKit's memory-pressure handling, which would release memory on the page's main thread every so often. Locally, Windows WebKit pages also stalled for over 2 s twice, in tests that didn't follow the million-row test.

The WebKit stall experiment workflow runs three times, each with:

  1. zzStall.experiment.tsx: renders a million rows, then idles for 65 s, then does the same with 100k rows as a control.
  2. The whole WebKit suite.

Both steps load test/zzStallSampler.ts, which records every main-thread stall over 100 ms in each page, with wall-clock times and the test that was running, and prints them once per file as STALLS {…}. A background loop samples the RSS of WebKit's web processes every 200 ms, with millisecond timestamps. The logs are uploaded as artifacts.

Reading it:

  • Memory pressure is likely if stalls of a second or more line up with RSS drops of a web process, at regular intervals while it stays above ~1 GB, after the million rows but not after 100k.
  • A cross-page effect is likely if stalls in the suite line up with the million-row test running in another page.

The regular CI workflow doesn't set the experiment's environment variables, so it runs as usual.

Results

Run 1 Run 2 Run 3
Stall while rendering a million rows 1.57 s 1.46 s 1.44 s
Stalls while idle for 65 s afterwards none none none
Web process memory, peak → after the render 1.50 → 0.97 GB 1.59 → 0.97 GB 1.59 → 0.96 GB
Longest stall in the suite, in the million-row test 3.11 s 3.59 s 2.87 s
Next longest stall in the suite 0.64 s 0.59 s 1.56 s
  • Memory pressure: not supported. The page didn't stall at all while idle after the million rows, and the web process's memory stayed flat. The release from ~1.5 GB to ~1 GB happens right after the render.
  • Cross-page effect: none. No long stall in another page overlapped the million-row test.
  • The million-row test blocks its page's main thread for ~3 s, by far the longest stall in WebKit's suite. The next longest come from virtualization.test.ts's tests with virtualization disabled.
  • All 205 WebKit tests passed in each run, so the original stall, after the million-row test had ended, didn't reproduce.

🤖 Generated with Claude Code

Samples the main-thread stalls of WebKit pages on Linux CI, while idle after
rendering a million rows and during the WebKit suite, alongside the memory of
WebKit's web processes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@nstepien nstepien closed this Oct 25, 2026
@nstepien
nstepien deleted the webkit-stall-experiment branch October 25, 2026 01:43
nstepien added a commit that referenced this pull request Oct 25, 2026
The "should expand a group with more rows than a function call can take
as arguments" test renders a million rows, which is far more work for
WebKit than for other browsers. DataGrid declares one grid row track per
row (`repeat(${rows.length}, …px)` in `useViewportRows`), and WebKit
lays out each track, while Chromium handles the `repeat()` as a whole.
Measured locally:

|                               |    WebKit | Chromium |
| ----------------------------- | --------: | -------: |
| One layout, 100k rows         |  18–19 ms |    ~1 ms |
| One layout, 1M rows           |   ~250 ms |    ~1 ms |
| Mounting the grid, 1M rows    |    913 ms |    61 ms |
| Memory of the page's process  |   +1.1 GB |    small |

About 0.6 GB of that memory stays committed after the grid unmounts, for
the rest of the page's life, and pages run several test files. In CI,
the test takes 2.5–5.4 s in WebKit.

The only WebKit flake in CI since October 19, the focus click in
`test/setupBrowser.ts` timing out in [run
40029118938](https://github.com/Comcast/react-data-grid/actions/runs/40029118938/attempts/1),
came from the test that ran right after this one: replaying the run's
seed shows the order. The page didn't respond for over 2 s, after the
grid had already unmounted. A Linux CI experiment in #4234 didn't
reproduce that stall, but showed that this test blocks its page's main
thread for 2.9–3.6 s, by far WebKit's longest stall in the suite (the
next longest take 0.5–1.6 s), and that pages don't stall while idle
afterwards. Locally, two other pages stalled for over 2 s in tests that
didn't follow this one, so this change may not remove every stall. It
does remove WebKit's longest main-thread block, and the memory that test
leaves behind.

The test still runs in Chromium and Firefox. It guards against spreading
the rows into a function call, which doesn't depend on the browser, and
their argument limits (123,758 and 500,000) are well below a million.

Separately, the same layout cost slows scrolling in WebKit with many
rows: 186–230 ms per scroll step at 1M rows and 30–44 ms at 100k,
against 8–15 ms in Chromium. That's worth its own issue.

`vp run ci` passes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5.5 <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