Skip to content

Commit 6b037bb

Browse files
committed
repro: add clean browser-worker UVM wasm assert harness
1 parent fc8633a commit 6b037bb

3 files changed

Lines changed: 57 additions & 19 deletions

File tree

docs/circt-uvm-browser-worker-repro.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,16 @@ npm run sync:circt
1919
node scripts/repro-uvm-browser-worker-assert.mjs
2020
```
2121

22+
Optional:
23+
24+
```bash
25+
# Use an already-running dev server instead of spawning one.
26+
REPRO_BASE_URL=http://127.0.0.1:4174 node scripts/repro-uvm-browser-worker-assert.mjs
27+
```
28+
2229
## What it does
2330

24-
- starts Vite dev server on `http://127.0.0.1:4173` (`--strictPort`)
31+
- starts Vite dev server on `http://127.0.0.1:43173` (`--strictPort`)
2532
- opens Chromium headless via Playwright
2633
- imports `createCirctWasmAdapter` from `/src/runtime/circt-adapter.js`
2734
- runs compile-only (`simulate: false`) on minimal UVM files:

docs/circt-uvm-wasm-bug-report.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,16 @@ circt-verilog --resource-guard=false --ir-llhd --timescale 1ns/1ns \
2424
--top tb_top -o /workspace/out/design.llhd.mlir /workspace/src/tb_top.sv
2525
```
2626

27+
Standalone browser-worker repro in this repo:
28+
29+
```sh
30+
node scripts/repro-uvm-browser-worker-assert.mjs
31+
```
32+
33+
This launches a headless Chromium page, imports `createCirctWasmAdapter` from
34+
`/src/runtime/circt-adapter.js`, runs compile-only (`simulate: false`) on a
35+
minimal `tb_top + my_test` UVM input, and reproduces the same assert.
36+
2737
`tb_top.sv`:
2838

2939
```systemverilog

scripts/repro-uvm-browser-worker-assert.mjs

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import { constants as fsConstants } from 'node:fs';
55
import { chromium } from '@playwright/test';
66

77
const HOST = process.env.REPRO_HOST || '127.0.0.1';
8-
const PORT = Number(process.env.REPRO_PORT || '4173');
9-
const BASE_URL = `http://${HOST}:${PORT}`;
8+
const DEFAULT_PORT = Number(process.env.REPRO_PORT || '43173');
9+
const BASE_URL_OVERRIDE = (process.env.REPRO_BASE_URL || '').trim();
1010
const SERVER_READY_TIMEOUT_MS = 45_000;
1111
const COMPILE_TIMEOUT_MS = 180_000;
1212

@@ -65,12 +65,15 @@ async function requireArtifacts() {
6565
}
6666
}
6767

68-
function startViteDevServer() {
68+
function startViteDevServer(baseUrl, port) {
69+
// Start Vite directly to avoid npm wrapper processes that are harder to
70+
// terminate from this script.
6971
const child = spawn(
70-
'npm',
71-
['run', 'dev', '--', '--host', HOST, '--port', String(PORT), '--strictPort'],
72+
process.execPath,
73+
['./node_modules/vite/bin/vite.js', '--host', HOST, '--port', String(port), '--strictPort'],
7274
{
73-
stdio: ['ignore', 'pipe', 'pipe']
75+
stdio: ['ignore', 'pipe', 'pipe'],
76+
detached: true
7477
}
7578
);
7679

@@ -85,7 +88,7 @@ function startViteDevServer() {
8588
const onData = (buf) => {
8689
const text = String(buf);
8790
output += text;
88-
if (!ready && text.includes('Local:') && text.includes(BASE_URL)) {
91+
if (!ready && text.includes('Local:') && text.includes(baseUrl)) {
8992
ready = true;
9093
clearTimeout(timer);
9194
resolve();
@@ -107,16 +110,21 @@ function startViteDevServer() {
107110
}
108111

109112
async function stopProcess(child) {
110-
if (!child || child.killed) return;
111-
child.kill('SIGTERM');
113+
if (!child || child.exitCode !== null) return;
114+
try {
115+
// Kill the whole process group (Vite + any children).
116+
process.kill(-child.pid, 'SIGTERM');
117+
} catch {}
112118
for (let i = 0; i < 30; i += 1) {
113119
if (child.exitCode !== null) return;
114120
await sleep(100);
115121
}
116-
child.kill('SIGKILL');
122+
try {
123+
process.kill(-child.pid, 'SIGKILL');
124+
} catch {}
117125
}
118126

119-
async function runBrowserWorkerCompile() {
127+
async function runBrowserWorkerCompile(baseUrl) {
120128
const browser = await chromium.launch({
121129
headless: true,
122130
channel: 'chromium',
@@ -129,7 +137,7 @@ async function runBrowserWorkerCompile() {
129137
});
130138

131139
try {
132-
const page = await browser.newPage({ baseURL: BASE_URL });
140+
const page = await browser.newPage({ baseURL: baseUrl });
133141
await page.goto('/');
134142

135143
const evaluatePromise = page.evaluate(async ({ files }) => {
@@ -152,11 +160,19 @@ async function runBrowserWorkerCompile() {
152160
};
153161
}, { files: UVM_FILES });
154162

163+
let timer = null;
155164
const timeoutPromise = new Promise((_, reject) => {
156-
setTimeout(() => reject(new Error(`compile timed out after ${COMPILE_TIMEOUT_MS}ms`)), COMPILE_TIMEOUT_MS);
165+
timer = setTimeout(
166+
() => reject(new Error(`compile timed out after ${COMPILE_TIMEOUT_MS}ms`)),
167+
COMPILE_TIMEOUT_MS
168+
);
157169
});
158170

159-
return await Promise.race([evaluatePromise, timeoutPromise]);
171+
try {
172+
return await Promise.race([evaluatePromise, timeoutPromise]);
173+
} finally {
174+
if (timer) clearTimeout(timer);
175+
}
160176
} finally {
161177
await browser.close();
162178
}
@@ -182,12 +198,17 @@ function analyzeLogs(payload) {
182198
try {
183199
await requireArtifacts();
184200

185-
console.log(`# Starting Vite dev server at ${BASE_URL}`);
186-
server = startViteDevServer();
187-
await server.readyPromise;
201+
const baseUrl = BASE_URL_OVERRIDE || `http://${HOST}:${DEFAULT_PORT}`;
202+
if (!BASE_URL_OVERRIDE) {
203+
console.log(`# Starting Vite dev server at ${baseUrl}`);
204+
server = startViteDevServer(baseUrl, DEFAULT_PORT);
205+
await server.readyPromise;
206+
} else {
207+
console.log(`# Using existing dev server at ${baseUrl}`);
208+
}
188209

189210
console.log('# Running minimal browser-worker UVM compile via createCirctWasmAdapter');
190-
const payload = await runBrowserWorkerCompile();
211+
const payload = await runBrowserWorkerCompile(baseUrl);
191212
const analysis = analyzeLogs(payload);
192213

193214
console.log('--- Repro Summary ---');

0 commit comments

Comments
 (0)