Skip to content

Forward Wasm worker output to emrun - #27970

Open
slowriot wants to merge 5 commits into
emscripten-core:mainfrom
slowriot:fix-emrun-wasm-worker-output
Open

slowriot wants to merge 5 commits into
emscripten-core:mainfrom
slowriot:fix-emrun-wasm-worker-output

Conversation

@slowriot

Copy link
Copy Markdown
Contributor

Wasm workers have their own out/err hooks, while --emrun installs HTTP output forwarding only in the main browser context. Consequently, emscripten_out() and emscripten_err() calls in Wasm workers appear in browser developer tools but are missing from emrun's stdout/stderr capture.

When --emrun is enabled, relay browser Wasm-worker output to the parent and dispatch it through the parent's output hooks. Nested workers relay through their parents to the main thread, reusing emrun's existing sequencing and delivery. The additional code is compiled out without --emrun; Node's native worker output and AudioWorklets are unchanged.

Extend the existing emrun test to check that stdout/stderr from direct and nested Wasm workers are each captured exactly once, both with and without pthreads.

Validation:

  • The new regression test fails before the fix because worker output is absent from the captured log.
  • All four emrun test variants pass in headless Chromium (each exercises the existing five emrun argument configurations).
  • The optimized Node Wasm-worker sample passes with and without --emrun.
  • Generated code without --emrun contains no forwarding messages or handler.

@sbc100 sbc100 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.

@juj what do you think?

Is this worth the added complexity?

Comment thread test/test_emrun.py Outdated
@juj

juj commented Oct 15, 2026

Copy link
Copy Markdown
Collaborator

Hmm, I think this is good to fix in general, since being able to capture log output from workers/pthreads via emrun is very useful for multithreaded debugging/CI runs.

Though I'm thinking that hooking into the generic postMessage part is maybe a bit crude/brutish.. Would a more straightforward way to fix this be to just have each worker do an emrun log XHR on their own?

Currently I think that will not work because of that global message sequencing in emrun.. but maybe the message sequencing could there constructed per-thread, so that each thread has its own sequence number in emrun.py?

That way we wouldn't need to hook these functions in emrun mode, but instead monkeypatch console logging in pthreads/workers like is done on the main thread?

@slowriot

Copy link
Copy Markdown
Contributor Author

I'm happy to adapt this however you guys think works best. Right now the lack of emrun logging from workers is really tripping me up, both in interactive testing and automated testing / CI; IMO it makes emrun logging unusable without it, and I've had to resort to hacks such as getting chromium to dump console logs to stdout in order to get meaningful multithreaded output; hoping to get rid of that. I doubt I'm the only one struggling with the situation.

@sbc100

sbc100 commented Oct 16, 2026

Copy link
Copy Markdown
Collaborator

Is there some reason you cannot switch to pthreads? What is keeping you from switching? There are many features that Wasm Workers lack, which is kind of by design.

@slowriot

Copy link
Copy Markdown
Contributor Author

Is there some reason you cannot switch to pthreads? What is keeping you from switching? There are many features that Wasm Workers lack, which is kind of by design.

In the specific application I'm encountering this issue, there's no requirement for pthread emulation features, and a desire to maintain explicit control over dispatch and synchronisation. I can't justify the costs of switching to pthreads just to add logging glue for developer debug emrun builds; the alternative for me is a local logging workaround in the relevant application, but I'd prefer to address it here as I doubt I'm the only one who's likely to encounter this problem using emrun and workers.

@sbc100

sbc100 commented Oct 16, 2026

Copy link
Copy Markdown
Collaborator

Can you explain what you mean by the "the costs of switching to pthreads"? Are you referring to code size increases? or the cost of refactoring your code?

If its the former I wonder what you consider to be a too much overhead? i.e. how much would we have the shrink the pthread runtime to make not worth the costs (lack of features) of choosing Wasm Workers.

@slowriot

Copy link
Copy Markdown
Contributor Author

Can you explain what you mean by the "the costs of switching to pthreads"?

Most of the design decisions on the specific project I'm working on were initially made some years ago, but my understanding was that there are some runtime costs associated with pthreads emulation that don't apply when using wasm workers directly - please correct me if that's an outdated assumption. In this particular project, any compromise on runtime performance is unacceptable.

Size and complexity are not really concerns in this project, and refactoring is not very challenging with modern AI tools.

... how much would we have the shrink the pthread runtime to make not worth the costs (lack of features) of choosing Wasm Workers.

It's not really about the size - it's simply that nothing about pthreads emulation is appealing in this project (and tbh most of my other projects). Knowing that they use workers behind the scenes but create thread pools and so forth, just means I'm relinquishing control to automation where I could manage what the browser is actually doing in a much more controlled way with workers.

The specific application I'm working on currently renders with webgpu, uses multiple workers to generate (massive) graphical resources asynchronously on demand, most data passed through lockfree queues to minimise synchronisation costs; having precise control over the execution of these workers is useful, and I wouldn't find any extra utility in pthreads functionality, but even a few percent impact to performance would be unacceptable here. We're also using audio worklets. I generally find it more convenient to use these sorts of thin(ish) wrappers exposing actual browser functionality, rather than emulating functionality that would be found natively.

The logging thing is a bugbear during development, but it's not important to me for releases - fixing it would just be of use to developers, as only our debug builds are built with emrun support to begin with.

@sbc100

sbc100 commented Oct 16, 2026

Copy link
Copy Markdown
Collaborator

but my understanding was that there are some runtime costs associated with pthreads emulation that don't apply when using wasm workers directly

While this is true is may have been overstated or over-estimated, and less true today than before.

If you want very fast thread communication via shared memory all the same primitives that you have available in Wasm Workers are also available in pthreads. That is say, if you want to use the very lowest level primitives such as emscripten_futex_wait.. you can do so in both cases. The runtime cost of pthreads only applies if you choose to use the pthread APIs. pthread_mutex_lock is a very thin wrapper around emscripten_futex_wait.. but nobody is forcing you to use it in either case.

The primary cost of using pthreads today IIUC is the extra code size can comes form the thread management code in libpthread.js. But once a pthread is started there should be no intrinsic extra costs. In both cases the Web Worker is the underling primitive.

@slowriot

Copy link
Copy Markdown
Contributor Author

While this is true is may have been overstated or over-estimated, and less true today than before.

That makes sense. Thanks for explaining. Still, it doesn't seem like there'd be any benefit in switching aside from resolving this logging issue - and there will always be use cases where someone wants to use wasm workers anyway, surely? Or is there a plan to deprecate that API entirely?

@sbc100

sbc100 commented Oct 17, 2026

Copy link
Copy Markdown
Collaborator

While this is true is may have been overstated or over-estimated, and less true today than before.

That makes sense. Thanks for explaining. Still, it doesn't seem like there'd be any benefit in switching aside from resolving this logging issue - and there will always be use cases where someone wants to use wasm workers anyway, surely? Or is there a plan to deprecate that API entirely?

The problem is that there are a huge number of features that do not work in Wasm Workers. For example, any kind of file i/o.. even stdio i/o doesn't really work. Or any JS library functions that is marked as __proxy.

If we keep adding these features then eventually we will get to a place where the advantage of Wasm Workers over pthreads in terms of code and complexity is diminished.

Another way of putting it: You sign up for limited capabilities when you sign up for Wasm Workers, so maybe this is something we don't need to fix?

@sbc100

sbc100 commented Oct 17, 2026

Copy link
Copy Markdown
Collaborator

I'm not necessarily proposing to block this particular change, just expressing the philosophical objection to feature creep in Wasm Workers in general.

@slowriot

Copy link
Copy Markdown
Contributor Author

Another way of putting it: You sign up for limited capabilities when you sign up for Wasm Workers, so maybe this is something we don't need to fix?

Yeah I totally appreciate that perspective, and I'm definitely in favour of keeping wasm workers light, especially for production code. I see this as an exception for developer benefit mostly, since emrun and logging to console is almost exclusively going to be used during development rather than by end users of a deployed application; I don't see this adding any weight to non-emrun builds (and it's gated on #if emrun, after all). The main motivation is just to make emrun functionality consistent, since it's an unexpected and surprising result that stdout doesn't work in all contexts under emrun (and initially had me wasting time chasing phantom bugs not realising that my browser console output had diverged from my stdout emrun output - something I'm sure could happen to others too). But I completely agree with your philosophy about keeping wasm worker implementations light in general.

This branch has not been deployed

No deployments
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.

3 participants