Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add example for wasm_threads usage #841

Merged
merged 7 commits into from
Aug 7, 2024
Merged
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
1 change: 1 addition & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ jobs:
- webworker
- webworker-gloo
- webworker-module
- wasm_threads
- yew
- yew-tailwindcss
- yew-tls
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ target
dist
site/public/*
.vscode
!examples/wasm_threads/.vscode
.idea/
.DS_Store
/vendor
8 changes: 8 additions & 0 deletions examples/wasm_threads/.cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Translating complex cargo invocation into this config file, so that trunk will use the same setup
# https://github.com/chemicstry/wasm_thread/blob/main/build_wasm.sh

[target.wasm32-unknown-unknown]
rustflags = ["-C", "target-feature=+atomics,+bulk-memory,+mutable-globals"]

[unstable]
build-std = ["std,panic_abort"]
7 changes: 7 additions & 0 deletions examples/wasm_threads/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
// The build-std flag requires an explicit target.
// This breaks the usual rust-analyzer setup.
// But setting the target manually for the workspace fixes that.
// "rust-analyzer.cargo.target": "x86_64-unknown-linux-gnu",
"rust-analyzer.cargo.target": "wasm32-unknown-unknown",
}
300 changes: 300 additions & 0 deletions examples/wasm_threads/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions examples/wasm_threads/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "wasm_threads"
version = "0.1.0"
edition = "2021"

[dependencies]
console_error_panic_hook = "0.1.7"
console_log = { version = "1.0.0", features = ["color"] }
log = "0.4.22"
wasm_thread = "0.3.0"
48 changes: 48 additions & 0 deletions examples/wasm_threads/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Support workers with shared memory and one wasm binary

This is a port of [wasm_threads `simple.rs` example](https://github.com/chemicstry/wasm_thread/tree/main?tab=readme-ov-file#simple).

It should also work similarly with `wasm-bindgen-rayon` and other packages that use SharedArrayBuffer.

An explanation of that approach is described [here](https://rustwasm.github.io/wasm-bindgen/examples/raytrace.html)

## Limitations

It has a few considerable advantages over the `webworker*` examples, but also considerable disadvantages.

For starters, this needs Cross Site Isolation (setting 2 headers), which is [required for this approach to workers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements).
We've added them in the trunk config.

These same headers are also required during deployment. Github pages does not allow setting headers, and alternatives such as using `<meta>` did not work in my testing, so these sites can't be deployed like that. Cloudflare Pages is a free alternative that allows setting headers that worked for me.

Then it also requires nightly Rust, because [the standard library needs to be rebuild](https://github.com/RReverser/wasm-bindgen-rayon?tab=readme-ov-file#building-rust-code).

Some libraries might not work correctly like that, since they are written under the assumption of the historially single threaded wasm32 runtimes. `wgpu` has the `fragile-send-sync-non-atomic-wasm` flag, which if set will not work with this. Eg. `egui` sets this flag currently, though it can be removed with a manual, not well tested [patch](https://github.com/9SMTM6/egui/commit/11b00084e34c8b0ff40bac82274291dff64c26db).

Additional limitations are listed [here](https://rustwasm.github.io/wasm-bindgen/examples/raytrace.html#caveats) (some of them might be solved or worked around in libraries). Specifically for `wasm_thread` limitations are explained in the comments in the source code.

## Advantages

* code sharing
* improves dev experience
* also means that the WASM binary will be shared, which can in the extreme case half the size of the website.
* shared memory between threads
* can be a huge performance win

## Notes on applying this

Note that this requires the [toolchain file](./rust-toolchain.toml) and the [cargo config](.cargo/config.toml).

The `_headers` file and its copy in `index.html` is simply an example of how to set the headers using Cloudflare Pages.

If you get errors such as

> [Firefox] The WebAssembly.Memory object cannot be serialized. The Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy HTTP headers can be used to enable this.

> [Chrome] SharedArrayBuffer transfer requires self.crossOriginIsolated.

Then the headers did not set correctly. You can check the response headers on the `/` file in the network tab of the browser developer tools.

## Using rust-analyzer

Since we use the build-std flag in the toolchain file, and that requires an explicit target to be set for compilation etc., this will break rust-analyzer in many setups. This can be solved by specifying an explicit target for the workspace, such as with the provided [config file for vscode](./.vscode/settings.json).
Loading