Skip to content

build/wasm: restore runner reliability and executable acceptance - #2660

Merged
cpunion merged 18 commits into
xgo-dev:mainfrom
cpunion:codex/wasm-r3-runner-recovery-20260924
Sep 27, 2026
Merged

cpunion merged 18 commits into
xgo-dev:mainfrom
cpunion:codex/wasm-r3-runner-recovery-20260924

Conversation

@cpunion

@cpunion cpunion commented Sep 23, 2026 •

Copy link
Copy Markdown
Collaborator

llgo run and llgo test can leave implicit Wasm entry modules and sidecars after runner execution, report an unclassified host error, or wait indefinitely when a runner hangs. This PR restores the useful runner and executable-acceptance changes from the retired R3 stack on the current J32/J64/W32 baseline.

  • Classify runner setup, startup, exit, output-drain, and timeout failures with target, profile, artifact, package, and runner details. llgo test prints the classified failure before FAIL. Native llgo run, WasmRuntime() execution, and emulator execution share the same deadline handling; raw Go-compatible Wasm tests also have host deadlines.
  • For positive deadlines, terminate the runner's process group on Unix and invoke taskkill /T /F on Windows, with direct-child termination as a fallback. Bound inherited-output draining with WaitDelay. Unix llgo run preserves interactive terminal input and restores foreground ownership; llgo test does not take the foreground terminal while its test processes run. A zero timeout keeps the existing unlimited execution behavior.
  • Own implicit execution artifacts for the full invocation and clean them after success, failure, and multi-package test execution.
  • Report actual executed profile cases, expected failures, timeouts, and unexpected failures in CI. Run complete bytes, strings, and encoding/json test packages on Emscripten Memory32, Emscripten Memory64, and WASI.

This consolidates the still-useful changes from fork PRs #223, #226, #227, #229, and #231. The prerequisite reflectlite Kind and Windows wasm-opt fixes are already on main.

Review-fix validation:

  • CI follow-up: the report failure probe uses the test-command suite so it reaches a recorded case before any runtime-only preflight, and prints the captured report on a mismatch. It passed on Linux AMD64 and ARM64 containers against the current upstream main merge. The terminal test waits for its helper to exit normally and passes its coverage directory through, so the exercised Unix process-group path is included in the host Go coverage profile; local focused coverage for that function rose from 57.9% to 100%.

  • go test ./internal/build ./cmd/internal/run ./cmd/internal/test -count=1 passed. After the review fixes, focused runner and CLI suites passed again; the pseudo-terminal test passed ten repetitions, and a real helper-process test verifies that llgo test prints the classified timeout cause.

  • Regression tests launch descendants that write heartbeats and verify termination for native, WasmRuntime(), and emulator paths. Unix tests cover both successful and failed parent exits while a descendant retains output pipes, plus interactive terminal input and foreground restoration. The failed-exit regression fails without the final cleanup fix and passes with it. Zero-timeout native execution is also covered.

  • Actual native llgo run -timeout=150ms and Emscripten/Node llgo run -timeout=1s runs returned classified timeout failures. The Emscripten run used LLGo Binaryen llgo-v132.3.

  • dev/wasm_ci_report_test.sh passed; the platform cancellation helpers compiled for Linux and Windows on the earlier head. Windows runtime behavior still needs the updated PR CI. Post-exit descendant cleanup on Windows is not guaranteed if the parent has already exited: taskkill /T only covers descendants while the parent still exists. Guaranteeing that case requires a Job Object; this PR does not claim it.

Earlier executable validation passed the runtime/test-command suites (24/24 and 10/10 checks), all nine stdlib package runs with cache disabled, shellcheck, actionlint, and dev/test_wasm_stdlib_test.sh. Those runs used LLGo Binaryen llgo-v132.2, Emscripten 6.0.8, Node 26.8.1, and Wasmtime 48.0.1.

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Review summary

Solid, well-tested change adding runner-recovery for the WebAssembly/emscripten paths: a host-side timeout for llgo run/llgo test, a structured runnerFailure error that distinguishes missing/unavailable runner, start error, timeout, and non-zero exit, generalized implicit-execution temp-dir cleanup, and CI acceptance scripts with their own self-tests. The time.Duration overflow guard in testRunnerTimeout, the DeadlineExceeded classification via runContext.Err(), and the append-only CI report design (errexit save/restore + EXIT-trap publish) are all nicely handled.

A few findings below. Nothing blocking.

Confirmed non-issue: the runNative ModeRun change (dropping mockable.Exit(s.ExitCode()) in favor of returning through build.Do) does not regress llgo run exit codes — in the previous code that call only ran on the success path (exit 0), while non-zero child exits already returned an error and were mapped to exit 1 by the cmd/run caller. Behavior is unchanged, and success now correctly runs build.Do's deferred cleanup. Security review found no issues (argv-form exec, %s-formatted awk report, mktemp-based temp handling).

Additional note (no reliable inline anchor): runInEmulator's ModeRun and ModeTest switch arms in internal/build/run.go are now identical; they could be collapsed to case ModeRun, ModeTest: for clarity.

Comment thread cmd/internal/run/run.go
Comment thread internal/build/run.go Outdated
@codecov

codecov Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.85039% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/build/run.go 97.59% 2 Missing ⚠️
internal/build/build.go 50.00% 1 Missing ⚠️
internal/build/run_process_windows.go 90.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@github-actions

github-actions Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

LLGo WebAssembly build benchmarks

f172ad19e62d | workflow run | long-term charts

WebAssembly output sizes
Example, profile and compiler Wasm module vs base Generated JS glue vs base
cprintf/j32-emscripten/LLGo 142925 B 0 B / +0.0% 73538 B 0 B / +0.0%
cprintf/j32-goos-js/LLGo 141404 B 0 B / +0.0% 71853 B 0 B / +0.0%
cprintf/j64-emscripten-memory64/LLGo 131242 B 0 B / +0.0% 77211 B 0 B / +0.0%
cprintf/w32-goos-wasip1/LLGo 138444 B 0 B / +0.0% 0 B 0 B / 0.0%
cprintf/w32-wasi/LLGo 138170 B 0 B / +0.0% 0 B 0 B / 0.0%
fmtprintf/j32-emscripten/LLGo 3184145 B 0 B / +0.0% 117962 B 0 B / +0.0%
fmtprintf/j32-goos-js/Go 2526852 B 0 B / +0.0% 0 B 0 B / 0.0%
fmtprintf/j32-goos-js/LLGo 3176231 B 0 B / +0.0% 101617 B 0 B / +0.0%
fmtprintf/j64-emscripten-memory64/LLGo 2921714 B 0 B / +0.0% 125341 B 0 B / +0.0%
fmtprintf/w32-goos-wasip1/Go 2500019 B 0 B / +0.0% 0 B 0 B / 0.0%
fmtprintf/w32-goos-wasip1/LLGo 2829062 B 0 B / +0.0% 0 B 0 B / 0.0%
fmtprintf/w32-wasi/LLGo 2695473 B 0 B / +0.0% 0 B 0 B / 0.0%
j32-emscripten/LLGo 142171 B 0 B / +0.0% 73538 B 0 B / +0.0%
j32-goos-js/Go 1895533 B 0 B / +0.0% 0 B 0 B / 0.0%
j32-goos-js/LLGo 140880 B 0 B / +0.0% 71853 B 0 B / +0.0%
j64-emscripten-memory64/LLGo 130580 B 0 B / +0.0% 77211 B 0 B / +0.0%
reflectcall/j32-emscripten/LLGo 1527329 B 0 B / +0.0% 91998 B 0 B / +0.0%
reflectcall/j32-goos-js/Go 2191221 B 0 B / +0.0% 0 B 0 B / 0.0%
reflectcall/j32-goos-js/LLGo 1530093 B 0 B / +0.0% 90313 B 0 B / +0.0%
reflectcall/j64-emscripten-memory64/LLGo 1413394 B 0 B / +0.0% 97731 B 0 B / +0.0%
reflectcall/w32-goos-wasip1/Go 2205707 B 0 B / +0.0% 0 B 0 B / 0.0%
reflectcall/w32-goos-wasip1/LLGo 1534667 B 0 B / +0.0% 0 B 0 B / 0.0%
reflectcall/w32-wasi/LLGo 1460122 B 0 B / +0.0% 0 B 0 B / 0.0%
w32-goos-wasip1/Go 1909947 B 0 B / +0.0% 0 B 0 B / 0.0%
w32-goos-wasip1/LLGo 137725 B 0 B / +0.0% 0 B 0 B / 0.0%
w32-wasi/LLGo 137518 B 0 B / +0.0% 0 B 0 B / 0.0%
LLGo WebAssembly build measurements
Example and profile Build vs base
j32-emscripten 5.521 s -73.78 ms / -1.3% (better)
j32-goos-js 5.562 s -240.9 ms / -4.2% (better)
j64-emscripten-memory64 4.809 s -71.24 ms / -1.5% (better)
reflectcall/w32-wasi 27.954 s +1.798 s / +6.9% (worse)
w32-goos-wasip1 4.661 s -162.2 ms / -3.4% (better)
w32-wasi 4.443 s -163 ms / -3.5% (better)

Compared with a34388d0a9ab measured in the same runner job.

@github-actions

github-actions Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

LLGo baseline benchmarks

f172ad19e62d | workflow run | long-term charts

Program measurements

Platform Workload File size vs base Text size vs base Build vs base Run vs base
Linux cprintf 7160 B 0 B / +0.0% 387 B 0 B / +0.0% 527.072 ms +33.77 ms / +6.8% (worse) 1.437 ms -362.4 us / -20.1% (better)
Linux cprintf-lto 6912 B 0 B / +0.0% 368 B 0 B / +0.0% 567.455 ms +78.43 ms / +16.0% (worse) 1.331 ms -1.659 us / -0.1% (better)
Linux fmtprintf 1637960 B 0 B / +0.0% 484730 B 0 B / +0.0% 4.119 s +194.8 ms / +5.0% (worse) 3.079 ms +20.57 us / +0.7% (worse)
Linux fmtprintf-lto 1478416 B 0 B / +0.0% 422446 B 0 B / +0.0% 11.417 s -757.9 ms / -6.2% (better) 3.176 ms -86.41 us / -2.6% (better)
Linux println 61344 B 0 B / +0.0% 14171 B 0 B / +0.0% 505.921 ms +7.468 ms / +1.5% (worse) 1.588 ms -52.81 us / -3.2% (better)
Linux println-lto 54152 B 0 B / +0.0% 12073 B 0 B / +0.0% 728.969 ms +16.88 ms / +2.4% (worse) 1.585 ms +19.54 us / +1.2% (worse)
macOS cprintf 68064 B 0 B / +0.0% 4429 B 0 B / +0.0% 786.444 ms -23.94 ms / -3.0% (better) 5.474 ms +933.1 us / +20.5% (worse)
macOS cprintf-lto 84288 B 0 B / +0.0% 193 B 0 B / +0.0% 976.839 ms +338.7 ms / +53.1% (worse) 3.728 ms +1.33 ms / +55.4% (worse)
macOS fmtprintf 1483856 B 0 B / +0.0% 860140 B 0 B / +0.0% 4.688 s +663.5 ms / +16.5% (worse) 9.352 ms +1.796 ms / +23.8% (worse)
macOS fmtprintf-lto 1175808 B 0 B / +0.0% 832752 B 0 B / +0.0% 10.363 s +383.4 ms / +3.8% (worse) 5.459 ms -63.17 us / -1.1% (better)
macOS println 114512 B 0 B / +0.0% 34330 B 0 B / +0.0% 779.204 ms +157.8 ms / +25.4% (worse) 4.965 ms +2.003 ms / +67.6% (worse)
macOS println-lto 118720 B 0 B / +0.0% 32308 B 0 B / +0.0% 1.239 s +474.9 ms / +62.2% (worse) 4.934 ms +2.076 ms / +72.7% (worse)
Windows MinGW cprintf 19456 B 0 B / +0.0% 4550 B 0 B / +0.0% 1.098 s +534.8 us / +0.04875% (worse) 3.493 ms -340.8 us / -8.9% (better)
Windows MinGW cprintf-lto 17920 B 0 B / +0.0% 4486 B 0 B / +0.0% 1.137 s -957.6 us / -0.1% (better) 3.499 ms +5.9 us / +0.2% (worse)
Windows MinGW fmtprintf 1910784 B 0 B / +0.0% 586502 B 0 B / +0.0% 4.051 s -3.074 ms / -0.1% (better) 7.947 ms -524.4 us / -6.2% (better)
Windows MinGW fmtprintf-lto 1934848 B 0 B / +0.0% 535206 B 0 B / +0.0% 9.855 s +125.8 ms / +1.3% (worse) 8.136 ms +367.4 us / +4.7% (worse)
Windows MinGW println 70656 B 0 B / +0.0% 23062 B 0 B / +0.0% 1.115 s -14.94 ms / -1.3% (better) 6.167 ms -771.5 us / -11.1% (better)
Windows MinGW println-lto 65024 B 0 B / +0.0% 20358 B 0 B / +0.0% 1.292 s -27.43 ms / -2.1% (better) 6.581 ms -313.7 us / -4.6% (better)
Windows MinGW 386 cprintf 43008 B 0 B / +0.0% 5326 B 0 B / +0.0% 1.131 s +24.8 ms / +2.2% (worse) 5.723 ms +69 us / +1.2% (worse)
Windows MinGW 386 cprintf-lto 20992 B 0 B / +0.0% 5094 B 0 B / +0.0% 1.135 s +5.239 ms / +0.5% (worse) 5.486 ms +152.5 us / +2.9% (worse)
Windows MinGW 386 fmtprintf 1876480 B 0 B / +0.0% 462574 B 0 B / +0.0% 4.191 s -2.761 ms / -0.1% (better) 9.991 ms -1.492 ms / -13.0% (better)
Windows MinGW 386 fmtprintf-lto 2152448 B 0 B / +0.0% 440194 B 0 B / +0.0% 9.797 s -161.3 ms / -1.6% (better) 10.332 ms -1.253 ms / -10.8% (better)
Windows MinGW 386 println 91136 B 0 B / +0.0% 19814 B 0 B / +0.0% 1.110 s -26.68 ms / -2.3% (better) 9.567 ms +973.5 us / +11.3% (worse)
Windows MinGW 386 println-lto 69120 B 0 B / +0.0% 17726 B 0 B / +0.0% 1.340 s +8.108 ms / +0.6% (worse) 9.307 ms +128.5 us / +1.4% (worse)
Windows MinGW ARM64 cprintf 18944 B 0 B / +0.0% 4408 B 0 B / +0.0% 1.400 s -51.86 ms / -3.6% (better) 6.799 ms -702.7 us / -9.4% (better)
Windows MinGW ARM64 cprintf-lto 17920 B 0 B / +0.0% 4340 B 0 B / +0.0% 1.432 s -33.67 ms / -2.3% (better) 6.846 ms -934.7 us / -12.0% (better)
Windows MinGW ARM64 fmtprintf 1798656 B 0 B / +0.0% 499196 B 0 B / +0.0% 4.286 s -147.4 ms / -3.3% (better) 13.986 ms -1.214 ms / -8.0% (better)
Windows MinGW ARM64 fmtprintf-lto 1857536 B 0 B / +0.0% 465268 B 0 B / +0.0% 9.686 s -259.9 ms / -2.6% (better) 13.588 ms -1.043 ms / -7.1% (better)
Windows MinGW ARM64 println 67072 B 0 B / +0.0% 21816 B 0 B / +0.0% 1.402 s -55.58 ms / -3.8% (better) 11.444 ms -975.8 us / -7.9% (better)
Windows MinGW ARM64 println-lto 63488 B 0 B / +0.0% 19436 B 0 B / +0.0% 1.592 s -60.21 ms / -3.6% (better) 11.298 ms -971.9 us / -7.9% (better)
Windows MSVC cprintf 120320 B 0 B / +0.0% 65782 B 0 B / +0.0% 1.111 s +187.5 ms / +20.3% (worse) 3.758 ms +156.1 us / +4.3% (worse)
Windows MSVC cprintf-lto 119808 B 0 B / +0.0% 65718 B 0 B / +0.0% 933.584 ms -16.53 ms / -1.7% (better) 3.307 ms -43 us / -1.3% (better)
Windows MSVC fmtprintf 1625088 B 0 B / +0.0% 682038 B 0 B / +0.0% 3.837 s +35.49 ms / +0.9% (worse) 9.665 ms -1.192 ms / -11.0% (better)
Windows MSVC fmtprintf-lto 1616384 B 0 B / +0.0% 635206 B 0 B / +0.0% 8.911 s -561.7 ms / -5.9% (better) 9.548 ms -368.2 us / -3.7% (better)
Windows MSVC println 192000 B 0 B / +0.0% 118486 B 0 B / +0.0% 946.807 ms -4.882 ms / -0.5% (better) 6.951 ms -635 us / -8.4% (better)
Windows MSVC println-lto 189952 B 0 B / +0.0% 116326 B 0 B / +0.0% 1.138 s +11.42 ms / +1.0% (worse) 7.377 ms +597.5 us / +8.8% (worse)
Windows MSVC 386 cprintf 9728 B 0 B / +0.0% 3931 B 0 B / +0.0% 926.403 ms +2.106 ms / +0.2% (worse) 5.981 ms -227 us / -3.7% (better)
Windows MSVC 386 cprintf-lto 9216 B 0 B / +0.0% 3853 B 0 B / +0.0% 961.518 ms -41.01 ms / -4.1% (better) 6.392 ms -408.3 us / -6.0% (better)
Windows MSVC 386 fmtprintf 1190400 B 0 B / +0.0% 445957 B 0 B / +0.0% 4.090 s +6.72 ms / +0.2% (worse) 13.441 ms +508.1 us / +3.9% (worse)
Windows MSVC 386 fmtprintf-lto 1224192 B 0 B / +0.0% 416649 B 0 B / +0.0% 8.755 s -387.2 ms / -4.2% (better) 12.943 ms -564.5 us / -4.2% (better)
Windows MSVC 386 println 34304 B 0 B / +0.0% 18641 B 0 B / +0.0% 970.401 ms -5.296 ms / -0.5% (better) 10.662 ms +838.5 us / +8.5% (worse)
Windows MSVC 386 println-lto 32256 B 0 B / +0.0% 16839 B 0 B / +0.0% 1.137 s +12.32 ms / +1.1% (worse) 10.852 ms +639 us / +6.3% (worse)
Windows MSVC ARM64 cprintf 11776 B 0 B / +0.0% 4192 B 0 B / +0.0% 1.115 s -2.369 ms / -0.2% (better) 7.469 ms +65.1 us / +0.9% (worse)
Windows MSVC ARM64 cprintf-lto 10752 B 0 B / +0.0% 4084 B 0 B / +0.0% 1.101 s -20.45 ms / -1.8% (better) 7.175 ms +193.8 us / +2.8% (worse)
Windows MSVC ARM64 fmtprintf 1370624 B 0 B / +0.0% 499068 B 0 B / +0.0% 3.854 s +4.2 ms / +0.1% (worse) 14.217 ms -422.2 us / -2.9% (better)
Windows MSVC ARM64 fmtprintf-lto 1387008 B 0 B / +0.0% 465900 B 0 B / +0.0% 8.667 s -67.24 ms / -0.8% (better) 15.000 ms +922.6 us / +6.6% (worse)
Windows MSVC ARM64 println 41984 B 0 B / +0.0% 21824 B 0 B / +0.0% 1.090 s -34.3 ms / -3.0% (better) 12.366 ms -1.181 ms / -8.7% (better)
Windows MSVC ARM64 println-lto 40448 B 0 B / +0.0% 19556 B 0 B / +0.0% 1.270 s -7.921 ms / -0.6% (better) 12.914 ms +549 us / +4.4% (worse)
Core language and compiler benchmarks
Platform Benchmark ns/op vs base
Linux BenchmarkLookupPCRandom 14.790 ns/op +0.14 ns/op / +1.0% (worse)
Linux BenchmarkMergeCompilerFlags 198.500 ns/op -8.7 ns/op / -4.2% (better)
Linux BenchmarkMergeLinkerFlags 126.800 ns/op -6.7 ns/op / -5.0% (better)
Linux BenchmarkChannelBuffered 55.590 ns/op +0.35 ns/op / +0.6% (worse)
Linux BenchmarkChannelHandoff 15392 ns/op +1565 ns/op / +11.3% (worse)
Linux BenchmarkDefer 47.180 ns/op -4.66 ns/op / -9.0% (better)
Linux BenchmarkDirectCall 1.519 ns/op 0 ns/op / +0.0%
Linux BenchmarkGlobalRead 1.553 ns/op 0 ns/op / +0.0%
Linux BenchmarkGlobalWrite 7.771 ns/op -0.012 ns/op / -0.2% (better)
Linux BenchmarkGoroutine 30916 ns/op -894 ns/op / -2.8% (better)
Linux BenchmarkInterfaceCall 5.975 ns/op +0.084 ns/op / +1.4% (worse)
Linux BenchmarkRuntimeGetG 2.443 ns/op +0.008 ns/op / +0.3% (worse)
macOS BenchmarkLookupPCRandom 22.180 ns/op +2.42 ns/op / +12.2% (worse)
macOS BenchmarkMergeCompilerFlags 161.100 ns/op +24.4 ns/op / +17.8% (worse)
macOS BenchmarkMergeLinkerFlags 135.800 ns/op +44.09 ns/op / +48.1% (worse)
macOS BenchmarkChannelBuffered 31.490 ns/op +0.22 ns/op / +0.7% (worse)
macOS BenchmarkChannelHandoff 7163 ns/op -4039 ns/op / -36.1% (better)
macOS BenchmarkDefer 35.660 ns/op -9.43 ns/op / -20.9% (better)
macOS BenchmarkDirectCall 1.349 ns/op +0.135 ns/op / +11.1% (worse)
macOS BenchmarkGlobalRead 1.352 ns/op -0.262 ns/op / -16.2% (better)
macOS BenchmarkGlobalWrite 1.424 ns/op -0.045 ns/op / -3.1% (better)
macOS BenchmarkGoroutine 40705 ns/op -22510 ns/op / -35.6% (better)
macOS BenchmarkInterfaceCall 4.797 ns/op +0.111 ns/op / +2.4% (worse)
macOS BenchmarkRuntimeGetG 2.057 ns/op -0.738 ns/op / -26.4% (better)
Windows MinGW BenchmarkLookupPCRandom 13.170 ns/op -0.05 ns/op / -0.4% (better)
Windows MinGW BenchmarkMergeCompilerFlags 617.400 ns/op -3.7 ns/op / -0.6% (better)
Windows MinGW BenchmarkMergeLinkerFlags 541.300 ns/op -5.1 ns/op / -0.9% (better)
Windows MinGW BenchmarkChannelBuffered 31.030 ns/op +0.51 ns/op / +1.7% (worse)
Windows MinGW BenchmarkChannelHandoff 1015 ns/op -43 ns/op / -4.1% (better)
Windows MinGW BenchmarkDefer 56.020 ns/op -0.08 ns/op / -0.1% (better)
Windows MinGW BenchmarkDirectCall 1.548 ns/op -0.001 ns/op / -0.1% (better)
Windows MinGW BenchmarkGlobalRead 1.858 ns/op -0.001 ns/op / -0.1% (better)
Windows MinGW BenchmarkGlobalWrite 2.455 ns/op -0.003 ns/op / -0.1% (better)
Windows MinGW BenchmarkGoroutine 86389 ns/op +4086 ns/op / +5.0% (worse)
Windows MinGW BenchmarkInterfaceCall 8.373 ns/op +0.001 ns/op / +0.01194% (worse)
Windows MinGW BenchmarkRuntimeGetG 1.862 ns/op +0.003 ns/op / +0.2% (worse)
Windows MinGW 386 BenchmarkLookupPCRandom 26.530 ns/op -0.05 ns/op / -0.2% (better)
Windows MinGW 386 BenchmarkMergeCompilerFlags 763.100 ns/op +13.8 ns/op / +1.8% (worse)
Windows MinGW 386 BenchmarkMergeLinkerFlags 698.800 ns/op +10.6 ns/op / +1.5% (worse)
Windows MinGW 386 BenchmarkChannelBuffered 38.590 ns/op -0.07 ns/op / -0.2% (better)
Windows MinGW 386 BenchmarkChannelHandoff 742.100 ns/op -96.6 ns/op / -11.5% (better)
Windows MinGW 386 BenchmarkDefer 42.920 ns/op -1.58 ns/op / -3.6% (better)
Windows MinGW 386 BenchmarkDirectCall 1.550 ns/op 0 ns/op / +0.0%
Windows MinGW 386 BenchmarkGlobalRead 1.551 ns/op +0.001 ns/op / +0.1% (worse)
Windows MinGW 386 BenchmarkGlobalWrite 7.794 ns/op +0.015 ns/op / +0.2% (worse)
Windows MinGW 386 BenchmarkGoroutine 85972 ns/op +686 ns/op / +0.8% (worse)
Windows MinGW 386 BenchmarkInterfaceCall 8.376 ns/op -0.023 ns/op / -0.3% (better)
Windows MinGW 386 BenchmarkRuntimeGetG 2.176 ns/op +0.006 ns/op / +0.3% (worse)
Windows MinGW ARM64 BenchmarkLookupPCRandom 12 ns/op -0.03 ns/op / -0.2% (better)
Windows MinGW ARM64 BenchmarkMergeCompilerFlags 566.300 ns/op -4.6 ns/op / -0.8% (better)
Windows MinGW ARM64 BenchmarkMergeLinkerFlags 536.200 ns/op -9.2 ns/op / -1.7% (better)
Windows MinGW ARM64 BenchmarkChannelBuffered 39.640 ns/op +0.56 ns/op / +1.4% (worse)
Windows MinGW ARM64 BenchmarkChannelHandoff 2683 ns/op +423 ns/op / +18.7% (worse)
Windows MinGW ARM64 BenchmarkDefer 57.330 ns/op +0.68 ns/op / +1.2% (worse)
Windows MinGW ARM64 BenchmarkDirectCall 0.590 ns/op +0.0002 ns/op / +0.03392% (worse)
Windows MinGW ARM64 BenchmarkGlobalRead 0.664 ns/op 0 ns/op / +0.0%
Windows MinGW ARM64 BenchmarkGlobalWrite 0.663 ns/op +0.0002 ns/op / +0.03016% (worse)
Windows MinGW ARM64 BenchmarkGoroutine 58084 ns/op +1274 ns/op / +2.2% (worse)
Windows MinGW ARM64 BenchmarkInterfaceCall 4.157 ns/op +0.002 ns/op / +0.04813% (worse)
Windows MinGW ARM64 BenchmarkRuntimeGetG 1.791 ns/op -0.019 ns/op / -1.0% (better)
Windows MSVC BenchmarkLookupPCRandom 13.180 ns/op -0.01 ns/op / -0.1% (better)
Windows MSVC BenchmarkMergeCompilerFlags 620.700 ns/op -8.1 ns/op / -1.3% (better)
Windows MSVC BenchmarkMergeLinkerFlags 545.800 ns/op -2.6 ns/op / -0.5% (better)
Windows MSVC BenchmarkChannelBuffered 27.970 ns/op +0.02 ns/op / +0.1% (worse)
Windows MSVC BenchmarkChannelHandoff 1102 ns/op -26 ns/op / -2.3% (better)
Windows MSVC BenchmarkDefer 54.940 ns/op +0.51 ns/op / +0.9% (worse)
Windows MSVC BenchmarkDirectCall 1.548 ns/op +0.001 ns/op / +0.1% (worse)
Windows MSVC BenchmarkGlobalRead 1.548 ns/op -0.003 ns/op / -0.2% (better)
Windows MSVC BenchmarkGlobalWrite 2.475 ns/op +0.005 ns/op / +0.2% (worse)
Windows MSVC BenchmarkGoroutine 83964 ns/op -1229 ns/op / -1.4% (better)
Windows MSVC BenchmarkInterfaceCall 8.697 ns/op -0.004 ns/op / -0.04597% (better)
Windows MSVC BenchmarkRuntimeGetG 2.175 ns/op +0.007 ns/op / +0.3% (worse)
Windows MSVC 386 BenchmarkLookupPCRandom 67.700 ns/op +0.05 ns/op / +0.1% (worse)
Windows MSVC 386 BenchmarkMergeCompilerFlags 777.500 ns/op +2.4 ns/op / +0.3% (worse)
Windows MSVC 386 BenchmarkMergeLinkerFlags 738.100 ns/op -1.2 ns/op / -0.2% (better)
Windows MSVC 386 BenchmarkChannelBuffered 52.350 ns/op +1.08 ns/op / +2.1% (worse)
Windows MSVC 386 BenchmarkChannelHandoff 1844 ns/op -857 ns/op / -31.7% (better)
Windows MSVC 386 BenchmarkDefer 52.510 ns/op +3.34 ns/op / +6.8% (worse)
Windows MSVC 386 BenchmarkDirectCall 1.017 ns/op -0.008 ns/op / -0.8% (better)
Windows MSVC 386 BenchmarkGlobalRead 1.244 ns/op -0.062 ns/op / -4.7% (better)
Windows MSVC 386 BenchmarkGlobalWrite 16.300 ns/op -0.41 ns/op / -2.5% (better)
Windows MSVC 386 BenchmarkGoroutine 78717 ns/op -2397 ns/op / -3.0% (better)
Windows MSVC 386 BenchmarkInterfaceCall 5.560 ns/op +0.178 ns/op / +3.3% (worse)
Windows MSVC 386 BenchmarkRuntimeGetG 1.307 ns/op +0.034 ns/op / +2.7% (worse)
Windows MSVC ARM64 BenchmarkLookupPCRandom 12.060 ns/op -0.02 ns/op / -0.2% (better)
Windows MSVC ARM64 BenchmarkMergeCompilerFlags 633.100 ns/op +72.6 ns/op / +13.0% (worse)
Windows MSVC ARM64 BenchmarkMergeLinkerFlags 575.500 ns/op +41.7 ns/op / +7.8% (worse)
Windows MSVC ARM64 BenchmarkChannelBuffered 37.750 ns/op -0.05 ns/op / -0.1% (better)
Windows MSVC ARM64 BenchmarkChannelHandoff 2350 ns/op +237 ns/op / +11.2% (worse)
Windows MSVC ARM64 BenchmarkDefer 62.570 ns/op -0.41 ns/op / -0.7% (better)
Windows MSVC ARM64 BenchmarkDirectCall 0.589 ns/op -0.0001 ns/op / -0.01696% (better)
Windows MSVC ARM64 BenchmarkGlobalRead 0.663 ns/op +0.0002 ns/op / +0.03016% (worse)
Windows MSVC ARM64 BenchmarkGlobalWrite 3.755 ns/op -0.002 ns/op / -0.1% (better)
Windows MSVC ARM64 BenchmarkGoroutine 54053 ns/op +381 ns/op / +0.7% (worse)
Windows MSVC ARM64 BenchmarkInterfaceCall 4.140 ns/op +0.007 ns/op / +0.2% (worse)
Windows MSVC ARM64 BenchmarkRuntimeGetG 2.250 ns/op +0.451 ns/op / +25.1% (worse)
Timer runtime benchmarks
Platform Operation and runtime ns/op vs base
Linux AfterFuncZeroDelivery/Go 909 ns/op -5 ns/op / -0.5% (better)
Linux AfterFuncZeroDelivery/LLGo 31706 ns/op -4236 ns/op / -11.8% (better)
Linux CreateStop/Go 291.900 ns/op -6.3 ns/op / -2.1% (better)
Linux CreateStop/LLGo 1695 ns/op +39 ns/op / +2.4% (worse)
Linux RearmStopped/Go 116.300 ns/op +0.3 ns/op / +0.3% (worse)
Linux RearmStopped/LLGo 1291 ns/op +199 ns/op / +18.2% (worse)
Linux ResetActive/Go 68.720 ns/op -0.12 ns/op / -0.2% (better)
Linux ResetActive/LLGo 703.800 ns/op +117 ns/op / +19.9% (worse)
Linux ResetHeap1024/Go 67.260 ns/op +0.14 ns/op / +0.2% (worse)
Linux ResetHeap1024/LLGo 181.500 ns/op -1.9 ns/op / -1.0% (better)
macOS AfterFuncZeroDelivery/Go 439.200 ns/op -123.2 ns/op / -21.9% (better)
macOS AfterFuncZeroDelivery/LLGo 91784 ns/op +6541 ns/op / +7.7% (worse)
macOS CreateStop/Go 252.100 ns/op +89.6 ns/op / +55.1% (worse)
macOS CreateStop/LLGo 646.300 ns/op +186.4 ns/op / +40.5% (worse)
macOS RearmStopped/Go 72.870 ns/op +7.95 ns/op / +12.2% (worse)
macOS RearmStopped/LLGo 329.700 ns/op -271 ns/op / -45.1% (better)
macOS ResetActive/Go 55.100 ns/op +3.78 ns/op / +7.4% (worse)
macOS ResetActive/LLGo 168.500 ns/op -55.1 ns/op / -24.6% (better)
macOS ResetHeap1024/Go 43.750 ns/op -9.18 ns/op / -17.3% (better)
macOS ResetHeap1024/LLGo 84.420 ns/op -18.18 ns/op / -17.7% (better)
Windows MinGW AfterFuncZeroDelivery/Go 571 ns/op +20.9 ns/op / +3.8% (worse)
Windows MinGW AfterFuncZeroDelivery/LLGo 164441 ns/op +2374 ns/op / +1.5% (worse)
Windows MinGW CreateStop/Go 117.100 ns/op +2.4 ns/op / +2.1% (worse)
Windows MinGW CreateStop/LLGo 432.800 ns/op +10.5 ns/op / +2.5% (worse)
Windows MinGW RearmStopped/Go 31.250 ns/op -0.3 ns/op / -1.0% (better)
Windows MinGW RearmStopped/LLGo 274.700 ns/op -1.9 ns/op / -0.7% (better)
Windows MinGW ResetActive/Go 20.060 ns/op +0.01 ns/op / +0.04988% (worse)
Windows MinGW ResetActive/LLGo 169.900 ns/op -7.8 ns/op / -4.4% (better)
Windows MinGW ResetHeap1024/Go 20.390 ns/op +0.02 ns/op / +0.1% (worse)
Windows MinGW ResetHeap1024/LLGo 123.500 ns/op -1.2 ns/op / -1.0% (better)
Windows MinGW 386 AfterFuncZeroDelivery/Go 956.500 ns/op +5.7 ns/op / +0.6% (worse)
Windows MinGW 386 AfterFuncZeroDelivery/LLGo 190286 ns/op +1319 ns/op / +0.7% (worse)
Windows MinGW 386 CreateStop/Go 191 ns/op -2.4 ns/op / -1.2% (better)
Windows MinGW 386 CreateStop/LLGo 501.200 ns/op +10.6 ns/op / +2.2% (worse)
Windows MinGW 386 RearmStopped/Go 63.440 ns/op +0.09 ns/op / +0.1% (worse)
Windows MinGW 386 RearmStopped/LLGo 349.500 ns/op +10 ns/op / +2.9% (worse)
Windows MinGW 386 ResetActive/Go 39.050 ns/op -0.08 ns/op / -0.2% (better)
Windows MinGW 386 ResetActive/LLGo 395.300 ns/op -584.7 ns/op / -59.7% (better)
Windows MinGW 386 ResetHeap1024/Go 39.470 ns/op -0.06 ns/op / -0.2% (better)
Windows MinGW 386 ResetHeap1024/LLGo 186.100 ns/op -11.9 ns/op / -6.0% (better)
Windows MinGW ARM64 AfterFuncZeroDelivery/Go 674.500 ns/op +5 ns/op / +0.7% (worse)
Windows MinGW ARM64 AfterFuncZeroDelivery/LLGo 132883 ns/op -12181 ns/op / -8.4% (better)
Windows MinGW ARM64 CreateStop/Go 195.700 ns/op -1.1 ns/op / -0.6% (better)
Windows MinGW ARM64 CreateStop/LLGo 367.200 ns/op +5.8 ns/op / +1.6% (worse)
Windows MinGW ARM64 RearmStopped/Go 70.620 ns/op -0.02 ns/op / -0.02831% (better)
Windows MinGW ARM64 RearmStopped/LLGo 256.500 ns/op +1.1 ns/op / +0.4% (worse)
Windows MinGW ARM64 ResetActive/Go 31.040 ns/op -0.06 ns/op / -0.2% (better)
Windows MinGW ARM64 ResetActive/LLGo 135.300 ns/op +13.1 ns/op / +10.7% (worse)
Windows MinGW ARM64 ResetHeap1024/Go 31.110 ns/op -0.03 ns/op / -0.1% (better)
Windows MinGW ARM64 ResetHeap1024/LLGo 128 ns/op +0.8 ns/op / +0.6% (worse)
Windows MSVC AfterFuncZeroDelivery/Go 546.900 ns/op -21.5 ns/op / -3.8% (better)
Windows MSVC AfterFuncZeroDelivery/LLGo 162074 ns/op -1763 ns/op / -1.1% (better)
Windows MSVC CreateStop/Go 115.500 ns/op -6 ns/op / -4.9% (better)
Windows MSVC CreateStop/LLGo 433.900 ns/op -7.1 ns/op / -1.6% (better)
Windows MSVC RearmStopped/Go 31.490 ns/op -1.62 ns/op / -4.9% (better)
Windows MSVC RearmStopped/LLGo 277.100 ns/op +15.6 ns/op / +6.0% (worse)
Windows MSVC ResetActive/Go 20.090 ns/op -0.43 ns/op / -2.1% (better)
Windows MSVC ResetActive/LLGo 140.800 ns/op -2.1 ns/op / -1.5% (better)
Windows MSVC ResetHeap1024/Go 20.340 ns/op -0.52 ns/op / -2.5% (better)
Windows MSVC ResetHeap1024/LLGo 125.500 ns/op +0.6 ns/op / +0.5% (worse)
Windows MSVC 386 AfterFuncZeroDelivery/Go 979 ns/op -0.7 ns/op / -0.1% (better)
Windows MSVC 386 AfterFuncZeroDelivery/LLGo 162713 ns/op +4661 ns/op / +2.9% (worse)
Windows MSVC 386 CreateStop/Go 252.300 ns/op +5.7 ns/op / +2.3% (worse)
Windows MSVC 386 CreateStop/LLGo 683.600 ns/op +49.8 ns/op / +7.9% (worse)
Windows MSVC 386 RearmStopped/Go 89.970 ns/op -0.35 ns/op / -0.4% (better)
Windows MSVC 386 RearmStopped/LLGo 395.800 ns/op +33.2 ns/op / +9.2% (worse)
Windows MSVC 386 ResetActive/Go 42.650 ns/op -0.66 ns/op / -1.5% (better)
Windows MSVC 386 ResetActive/LLGo 321.300 ns/op -25.3 ns/op / -7.3% (better)
Windows MSVC 386 ResetHeap1024/Go 43.900 ns/op +0.09 ns/op / +0.2% (worse)
Windows MSVC 386 ResetHeap1024/LLGo 161.300 ns/op -0.3 ns/op / -0.2% (better)
Windows MSVC ARM64 AfterFuncZeroDelivery/Go 661.300 ns/op +4.8 ns/op / +0.7% (worse)
Windows MSVC ARM64 AfterFuncZeroDelivery/LLGo 122344 ns/op -373 ns/op / -0.3% (better)
Windows MSVC ARM64 CreateStop/Go 197.700 ns/op -9.9 ns/op / -4.8% (better)
Windows MSVC ARM64 CreateStop/LLGo 378.300 ns/op -4.3 ns/op / -1.1% (better)
Windows MSVC ARM64 RearmStopped/Go 70.530 ns/op -0.02 ns/op / -0.02835% (better)
Windows MSVC ARM64 RearmStopped/LLGo 268.600 ns/op +0.5 ns/op / +0.2% (worse)
Windows MSVC ARM64 ResetActive/Go 31.050 ns/op -0.04 ns/op / -0.1% (better)
Windows MSVC ARM64 ResetActive/LLGo 128.900 ns/op -3.5 ns/op / -2.6% (better)
Windows MSVC ARM64 ResetHeap1024/Go 31.170 ns/op -0.02 ns/op / -0.1% (better)
Windows MSVC ARM64 ResetHeap1024/LLGo 137.200 ns/op -1.1 ns/op / -0.8% (better)

Compared with a34388d0a9ab measured in the same runner job.

@cpunion
cpunion force-pushed the codex/wasm-r3-runner-recovery-20260924 branch from 431da14 to 1f8733d Compare September 26, 2026 14:39

@visualfc visualfc left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Review

Can merge. This restores still-useful R3 runner behavior: classified host failures for llgo run/llgo test, process-group termination on a positive deadline, cleanup of implicit Wasm artifacts, and CI reporting of the profiles that actually ran. It does not change compile semantics.

The earlier fennoai notes are addressed: -timeout now flows through native, WasmRuntime(), and emulator execution via the same runRunnerCommand; Unix uses Setpgid plus group kill, Windows uses taskkill /T /F, and WaitDelay bounds pipe draining. The extra Cancel() after a failed exit is the right shape for Go preferring a nonzero exit over ErrWaitDelay.

Suggestions

1. llgo test drops the classified runner error

runRunnerCommand puts runner failed: phase=test status=timeout ... on the returned error and does not write it to the test stdout/stderr. runTestPrograms only uses err != nil to set failed and then prints FAIL\tpkg. build.go calls mockable.Exit(1) on test failure, so the classified error never reaches cmd/internal/test.

llgo run -timeout=1s shows status=timeout (that is what expect_llgo_runner_timeout asserts). A hung or timed-out host runner under llgo test mostly looks like FAIL plus truncated guest output.

Please print err.Error() for *runnerFailure from reportTestProgramResult. That is the command this diagnostics work is meant to serve.

2. Timed Unix runs steal the foreground TTY

Default llgo test -timeout=10m yields a 10m30s host deadline, so every wasm/emulator test gets Setpgid. When stdin is the developer's terminal, configureRunnerCancellation also sets Foreground=true on each child.

With default BuildParallelism (GOMAXPROCS), several node/wasmtime processes take turns owning the same controlling terminal. CI stdin is usually not a TTY, so the ioctl fails and this stays hidden. llgo run needs the terminal; llgo test usually does not.

Limit foreground takeover to phase=run, or to sequential runs whose child actually reads the terminal. signal.Ignore(SIGTTOU) is process-wide and is more brittle when combined with parallel takeover.

3. Windows cleanup after a failed exit is a post-mortem kill

The timeout path is fine: CommandContext calls Cancel() while the parent is still alive, so taskkill /T /F /PID can reach the tree.

The failed-exit path calls Cancel() after cmd.Run() returns. The parent PID is often already gone, children are reparented, taskkill /T fails, and Process.Kill() cannot reach them. Unix kill(-pgid) still works after the leader exits; Windows has no equivalent. fail-with-child lives only in run_timeout_unix_test.go.

Timeout tree-kill is the main goal, and the Windows timeout tests already passed. If exit 1 must also not leak node workers, the process needs a Job Object (or equivalent) at start, not a kill after the parent is reaped.

Nits

  • Native llgo test (program.runner == "") still uses a bare exec.Command and ignores RunnerTimeout. That is reasonable: the guest has the testing watchdog, and the host deadline is for a runner that stops forwarding exit. A one-line comment would help.
  • dev/test_wasm_stdlib.sh runs three packages on three targets with LLGO_BUILD_CACHE=off and a 60s guest timeout. Current CI fits the 20-minute step; a slower json run will kill the guest first.
  • The wasm-runtime timeout helper builds WasmRuntime() with strings.Split(..., " "). The emulator path quotes with %q. A Windows path with spaces will split (existing WasmRuntime() convention; the new timeout test follows it).
  • The PR text still mentions a local Binaryen llgo-v132.2 run; CI is pinned to llgo-v132.3.

@cpunion
cpunion merged commit f59bac1 into xgo-dev:main Sep 27, 2026
88 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