Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions .github/workflows/webkit-stall-experiment.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# TEMPORARY: experiment for a draft PR, never to be merged.
# Does a WebKit page on Linux stall after rendering a million rows, or under the suite's load,
# and do the stalls line up with drops in the memory of WebKit's web processes?
name: WebKit stall experiment

on: pull_request

permissions: {}

jobs:
experiment:
runs-on: ubuntu-latest
timeout-minutes: 30

permissions:
contents: read # check out the repository

strategy:
fail-fast: false
matrix:
run: [1, 2, 3]

steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- uses: voidzero-dev/setup-vp@68f39c78aaf39be468cabd2afb09c162574c84af # v1.21.2
with:
cache: true
cache-save: false
run-install: false

- run: vp install --frozen-lockfile

- run: vp run install-browsers
timeout-minutes: 8

- name: Idle after rendering a million rows, then 100k rows
env:
WEBKIT_STALL_SAMPLER: 1
WEBKIT_STALL_IDLE: 1
DEBUG: pw:browser*
run: |
(while sleep 0.2; do echo "$(date +%s%3N) $(ps -eo pid=,rss=,comm= | grep -E 'WebProces' | tr -s ' ' | tr '\n' ';')"; done) > memory-idle.log &
poller=$!
vp test test/browser/zzStall.experiment.tsx --project "browser (webkit)" --sequence.shuffle.tests=false > idle.log 2>&1 || true
kill "$poller"
grep -E 'STALLS|Tests |Duration' idle.log | cut -c1-2000

- name: WebKit suite with the stall sampler
env:
WEBKIT_STALL_SAMPLER: 1
DEBUG: pw:browser*
run: |
(while sleep 0.2; do echo "$(date +%s%3N) $(ps -eo pid=,rss=,comm= | grep -E 'WebProces' | tr -s ' ' | tr '\n' ';')"; done) > memory-suite.log &
poller=$!
vp test --project "browser (webkit)" > suite.log 2>&1 || true
kill "$poller"
grep -E 'FAIL|Tests |Duration' suite.log | head -50

- name: Upload logs
if: always()
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: webkit-stall-${{ matrix.run }}
path: '*.log'
51 changes: 51 additions & 0 deletions test/browser/zzStall.experiment.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// TEMPORARY: WebKit stall experiment, does the page stall while idle after rendering a million rows?
import { page } from 'vite-plus/test/browser';

import { TreeDataGrid } from '../../src';

interface Row {
id: number;
country: string;
year: number;
}

const columns = [
{ key: 'country', name: 'Country' },
{ key: 'id', name: 'Id' }
];

async function renderRows(count: number) {
const rows = Array.from({ length: count }, (_, id): Row => ({ id, country: 'USA', year: 2020 }));

await page.render(
<TreeDataGrid
columns={columns}
rows={rows}
groupBy={['country']}
expandedGroupIds={new Set(['USA'])}
onExpandedGroupIdsChange={() => {}}
/>
);

await expect.element(page.getTreeGrid()).toHaveAttribute('aria-rowcount', String(count + 2));
await expect.element(page.getCell({ name: '0', exact: true })).toBeVisible();
}

// vitest-browser-react unmounts the grid before the idle test starts
async function idle(seconds: number) {
for (let i = 0; i < seconds; i++) {
await new Promise((resolve) => {
setTimeout(resolve, 1000);
});
}
}

describe.each([1_000_000, 100_000])('%i rows', (count) => {
it('render', async () => {
await renderRows(count);
});

it('idle for 65s', { timeout: 90_000 }, async () => {
await idle(65);
});
});
42 changes: 42 additions & 0 deletions test/zzStallSampler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// TEMPORARY: WebKit stall experiment, records the page's main-thread stalls and test timings
// with wall-clock times, so stalls can be compared across pages and with memory samples
import { server } from 'vite-plus/test/browser';

const INTERVAL = 5;
const THRESHOLD = 100;

let file = '';
let currentTest = '(before the first test)';
let testStart = 0;
let tests: { name: string; start: number; end: number }[] = [];
let stalls: { start: number; end: number; test: string }[] = [];
let last = performance.now();

setInterval(() => {
const now = performance.now();
if (now - last - INTERVAL > THRESHOLD) {
const end = Date.now();
stalls.push({ start: Math.round(end - (now - last)), end, test: currentTest });
}
last = now;
}, INTERVAL);

// registered before the other setup files' hooks, so it runs first
beforeEach(({ task }) => {
file = task.file.name;
currentTest = task.name;
testStart = Date.now();
});

afterEach(({ task }) => {
tests.push({ name: task.name, start: testStart, end: Date.now() });
currentTest = `(after ${task.name})`;
});

// one log per file, so the experiment doesn't flood the console
afterAll(() => {
// oxlint-disable-next-line eslint/no-console
console.info(`STALLS ${JSON.stringify({ browser: server.browser, file, tests, stalls })}`);
tests = [];
stalls = [];
});
15 changes: 13 additions & 2 deletions vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,9 +311,20 @@ export default defineConfig({
{
test: {
name: 'browser',
include: ['browser/**/*.test.*', ...(isCI ? ['visual/*.test.*'] : [])],
include: [
'browser/**/*.test.*',
...(isCI ? ['visual/*.test.*'] : []),
// TEMPORARY: WebKit stall experiment
...(process.env.WEBKIT_STALL_IDLE === '1' ? ['browser/zzStall.experiment.tsx'] : [])
],
browser: { enabled: true },
setupFiles: ['test/browser/styles.css', 'test/setupBrowser.ts', 'test/failOnConsole.ts']
setupFiles: [
// TEMPORARY: WebKit stall experiment
...(process.env.WEBKIT_STALL_SAMPLER === '1' ? ['test/zzStallSampler.ts'] : []),
'test/browser/styles.css',
'test/setupBrowser.ts',
'test/failOnConsole.ts'
]
}
},
{
Expand Down
Loading