Skip to content

Commit ee6bedb

Browse files
committed
Add a bunch of cookbook-style "how do I do X?" examples to the book
This tries to cover things that we repeatedly get questions about on Zulip.
1 parent f3e5c87 commit ee6bedb

14 files changed

+711
-7
lines changed

docs/SUMMARY.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,17 @@
3737
- [Profiling WebAssembly](./examples-profiling.md)
3838
- [Profiling with Perf](./examples-profiling-perf.md)
3939
- [Profiling with VTune](./examples-profiling-vtune.md)
40-
- [Profiling with samply](./examples-profiling-samply.md)
40+
- [Profiling with `samply`](./examples-profiling-samply.md)
4141
- [Cross-platform Profiling](./examples-profiling-guest.md)
42+
- [Building a Minimal Embedding](./examples-minimal.md)
43+
- [Portable Interpretation](./examples-pulley.md)
44+
- [Pre-Compiling Wasm](./examples-pre-compiling-wasm.md)
45+
- [Fast Execution](./examples-fast-execution.md)
46+
- [Fast Instantiation](./examples-fast-instantiation.md)
47+
- [Fast Compilation](./examples-fast-compilation.md)
48+
- [Interrupting Execution](./examples-interrupting-wasm.md)
49+
- [Deterministic Execution](./examples-deterministic-wasm-execution.md)
4250
- [Checking Guests' Memory Accesses](./wmemcheck.md)
43-
- [Building a minimal embedding](./examples-minimal.md)
44-
- [Using Pulley](./examples-pulley.md)
4551
- [Stability](stability.md)
4652
- [Release Process](./stability-release.md)
4753
- [Tiers of support](./stability-tiers.md)
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Deterministic Wasm Execution
2+
3+
The WebAssembly language is *mostly* deterministic, but there are a few places
4+
where non-determinism slips in. This page documents how to use Wasmtime to
5+
execute Wasm programs fully deterministically, even when the Wasm language spec
6+
allows for non-determinism.
7+
8+
## Make Sure All Imports are Deterministic
9+
10+
Do not give Wasm programs access to non-deterministic host functions.
11+
12+
When using WASI, use
13+
[`wasi-virt`](https://github.com/bytecodealliance/WASI-Virt) to virtualize
14+
non-deterministic APIs like clocks and file systems.
15+
16+
## Enable IEEE-754 `NaN` canonicalization
17+
18+
Some Wasm opcodes can result in `NaN` (not-a-number) values. The IEEE-754 spec
19+
defines a whole range of `NaN` values and the Wasm spec does not require that
20+
Wasm always generates any particular `NaN` value, it could be any one of
21+
them. This non-determinism can then be observed by the Wasm program by storing
22+
the `NaN` value to memory or bitcasting it to an integer. Therefore, Wasmtime
23+
can be configured to canonicalize all `NaN`s into a particular, canonical `NaN`
24+
value. The downside is that this adds overhead to Wasm's floating-point
25+
instructions.
26+
27+
See
28+
[wasmtime::Config::cranelift_nan_canonicalization](https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.cranelift_nan_canonicalization)
29+
for more details.
30+
31+
## Make the Relaxed SIMD Proposal Deterministic
32+
33+
The relaxed SIMD proposal gives Wasm programs access to SIMD operations that
34+
cannot be made to execute both identically and performantly across different
35+
architecures. The proposal gave up determinism across different achitectures in
36+
order to maintain portable performance.
37+
38+
At the cost of worse runtime performance, Wasmtime can deterministically execute
39+
this proposal's instructions. See
40+
[wasmtime::Config::relaxed_simd_deterministic](https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.relaxed_simd_deterministic)
41+
for more details.
42+
43+
Alternatively, you can simply disable the proposal completely. See
44+
[`wasmtime::Config::wasm_relaxed_simd`](https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.wasm_relaxed_simd)
45+
for more details.
46+
47+
## Handling Non-Deterministic Memory and Table Growth
48+
49+
All WebAssembly memories and tables have an associated minimum, or initial, size
50+
and an optional maximum size. When the maximum size is not present, that means
51+
"unlimited". If a memory or table is already at its maximum size, then attempts
52+
to grow them will always fail. If they are below their maximum size, however,
53+
then the `memory.grow` and `table.grow` instructions are allowed to
54+
non-deterministicaly succeed or fail (for example, when the host system does not
55+
have enough memory available to satisfy that growth).
56+
57+
You can make this deterministic in a variety of ways:
58+
59+
* Disallow Wasm programs that use memories and tables via a
60+
[limiter](https://docs.rs/wasmtime/latest/wasmtime/struct.Store.html#method.limiter)
61+
that rejects non-zero-sized memories and tables.
62+
63+
* Use a [custom memory
64+
creator](https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.with_host_memory)
65+
that allocates the maximum size up front so that growth will either always
66+
succeed or fail before the program has begun execution.
67+
68+
* Use [the `wasmparser` crate](https://crates.io/crates/wasmparser) to write a
69+
little validator program that rejects Wasm modules that use
70+
`{memory,table}.grow` instructions or alternatively rejects memories and
71+
tables that do not have a maximum size equal to their minimum size (which,
72+
again, means that their allocation must happen completely up front, and if
73+
allocation fails, it will have failed before the Wasm program began
74+
executing).
75+
76+
## Use Deterministic Interruption, If Any
77+
78+
If you are making Wasm execution interruptible, use [deterministic fuel-based
79+
interruption](./examples-interrupting-wasm.html#deterministic-fuel) rather than
80+
non-deterministic epoch-based interruption.

docs/examples-fast-compilation.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Tuning Wasmtime for Fast Compilation
2+
3+
Wasmtime must compile a Wasm program before executing it. This means that, by
4+
default, Wasm compilation is on your critical path. In most scenarios, you can
5+
completely remove Wasm compilation from the critical path by [pre-compiling Wasm
6+
programs](./examples-pre-compiling-wasm.md). That option is not always
7+
available, however, and this page documents how to tune Wasmtime for fast
8+
compilation in these alternative scenarios.
9+
10+
## Enable the Compilation Cache
11+
12+
Wasmtime can be configured to use a cache, so that if you attempt to compile a
13+
Wasm program that has already been compiled previously, it just grabs the cached
14+
result rather than performing compilation all over again.
15+
16+
See these API docs for more details:
17+
18+
* [`wasmtime::Config::cache_config_load`](https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.cache_config_load)
19+
* [`wasmtime::Config::cache_config_load_default`](https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.cache_config_load_default)
20+
* [`wasmtime::Config::disable_cache`](https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.disable_cache)
21+
* [`wasmtime::CacheStore`](https://docs.rs/wasmtime/latest/wasmtime/trait.CacheStore.html)
22+
23+
## Enable Winch
24+
25+
Winch is Wasmtime's "baseline" compiler: for each Wasm opcode, it emits a canned
26+
sequence of machine instructions to implement that opcode. This makes
27+
compilation fast: it performs only a single, quick pass over the Wasm
28+
code. However, it does not perform optimizations, so the machine code it emits
29+
will run Wasm programs slower than Cranelift, Wasmtime's optimizing compiler.
30+
31+
See the API docs for
32+
[`wasmtime::Strategy`](https://docs.rs/wasmtime/latest/wasmtime/enum.Strategy.html)
33+
and
34+
[`wasmtime::Config::strategy`](https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.strategy)
35+
for more details.
36+
37+
## Enable Parallel Compilation
38+
39+
Wasmtime can compile Wasm programs in parallel, speeding up the compilation
40+
process more or less depending on how many cores your machine has and the exact
41+
shape of the Wasm program. Wasmtime will generally enable parallel compilation
42+
by default, but it does depend on the host platform and cargo features enabled
43+
when building Wasmtime itself. You can double check that parallel compilation is
44+
enabled via the setting the
45+
[`wasmtime::Config::parallel_compilation`](https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.parallel_compilation)
46+
configuration option.
47+
48+
## Putting It All Together
49+
50+
```rust,ignore
51+
{{#include ../examples/fast_compilation.rs}}
52+
```
53+
54+
## See Also
55+
56+
* [Pre-Compiling Wasm Programs](./examples-pre-compiling-wasm.md)
57+
* [Tuning Wasmtime for Fast Wasm Instantiation](./examples-fast-instantiation.md)
58+
* [Tuning Wasmtime for Fast Wasm Execution](./examples-fast-execution.md)

docs/examples-fast-execution.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Tuning Wasmtime for Fast Wasm Execution
2+
3+
To tune Wasmtime for faster Wasm execution, consider the following tips.
4+
5+
## Enable Cranelift
6+
7+
[Cranelift](https://cranelift.dev/) is an optimizing compiler. Compared to
8+
alternative strategies like [the Winch "baseline"
9+
compiler](./examples-fast-compilation.md), it translates Wasm into faster
10+
machine code, but compilation is slower. Cranelift is similar to the optimizing
11+
tier of browsers' just-in-time Wasm engines, such as SpiderMonkey's Ion tier or
12+
V8's TurboFan tier.
13+
14+
See the API docs for
15+
[`wasmtime::Strategy`](https://docs.rs/wasmtime/latest/wasmtime/enum.Strategy.html)
16+
and
17+
[`wasmtime::Config::strategy`](https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.strategy)
18+
for more details.
19+
20+
## Configure Wasmtime to Elide Explicit Bounds Checks
21+
22+
Wasm programs are sandboxed and may only access their linear memories. Attempts
23+
to access beyond the bounds of a linear memory results in a trap, and this
24+
prevents the Wasm guest from stealing data from host memory, or from another
25+
concurrently running Wasm instance. Explicitly bounds-checking every linear
26+
memory operation performed by a Wasm guest is expensive: it has been measured to
27+
create between a 1.2x to 1.8x slow down, depending on a number of
28+
factors. Luckily, Wasmtime can usually omit explicit bounds checks by relying on
29+
virtual memory guard pages. This requires enabling signals-based traps (on by
30+
default for non-bare-metal builds), running Wasm on a 64-bit host architecture,
31+
and ensuring that memory reservations and guard pages are appropriately sized
32+
(again, configured by default for 64-bit architectures).
33+
34+
To elide any explicit bounds checks, Wasm linear memories must have at least a
35+
4GiB (`1 << 32` bytes) reservation. If a memory instruction has an additional
36+
static offset immediate, then the bounds check can only be elided when there is
37+
a memory guard of at least that offset's size. Using a 4GiB guard region allows
38+
Wasmtime to elide explicit bounds checks regardless of the static memory offset
39+
immediate. While small static offset immediate values are common, very large
40+
values are exceedingly rare, so you can get almost all of the benefits while
41+
consuming less virtual memory address space by using, for example, 32MiB guards.
42+
43+
See the API docs for
44+
[`wasmtime::Config::signals_based_traps`](https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.signals_based_traps),
45+
[`wasmtime::Config::memory_reservation`](https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.memory_reservation),
46+
and
47+
[`wasmtime::Config::memory_reservation`](https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.memory_guard_size)
48+
for more details.
49+
50+
## Force-Enable ISA Extensions
51+
52+
This section can be ignored if you are compiling and running Wasm programs on
53+
the same machine. In this scenario, Wasmtime will automatically detect which ISA
54+
extensions (such as AVX on x86\_64) are available, and you do not need to
55+
configure anything yourself.
56+
57+
However, if you are compiling a Wasm program on one machine and then running
58+
that pre-compiled Wasm program on another machine, then during compilation
59+
Wasmtime cannot automatically detect which ISA extensions will be available on
60+
the machine on which you actually execute the pre-compiled Wasm
61+
program. Configuring which ISA extensions are available on the target
62+
architecture that will run the pre-compiled Wasm programs can have a large
63+
impact for certain Wasm programs, particularly those using SIMD instructions.
64+
65+
See the API docs for
66+
[`wasmtime::Config::detect_host_feature`](https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.detect_host_feature)
67+
for more details.
68+
69+
## Putting It All Together
70+
71+
```rust,ignore
72+
{{#include ../examples/fast_execution.rs}}
73+
```
74+
75+
## See Also
76+
77+
* [Tuning Wasmtime for Fast Wasm Compilation](./examples-fast-compilation.md)
78+
* [Tuning Wasmtime for Fast Wasm Instantiation](./examples-fast-instantiation.md)
79+
* [Pre-Compiling Wasm Programs](./examples-pre-compiling-wasm.md)
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Tuning Wasmtime for Fast Instantiation
2+
3+
Before a WebAssembly module can begin execution, it must first be compiled and
4+
then instantiated. Compilation can happen [ahead of
5+
time](./examples-pre-compiling-wasm.md), which removes compilation from the
6+
critical path. That leaves just instantiation on the critical path. This page
7+
documents methods for tuning Wasmtime for fast instantiation.
8+
9+
## Enable the Pooling Allocator
10+
11+
By enabling the pooling allocator, you are configuring Wasmtime to up-front and
12+
ahead-of-time allocate a large pool containing all the resources necessary to
13+
run the configured maximum number of concurrent instances. Creating a new
14+
instance doesn't require allocating new Wasm memories and tables on demand, it
15+
just takes pre-allocated memories and tables from the pool, which is generally
16+
much faster. Deallocating an instance returns its memories and tables to the
17+
pool.
18+
19+
See
20+
[`wasmtime::PoolingAllocationConfig`](https://docs.rs/wasmtime/latest/wasmtime/struct.PoolingAllocationConfig.html),
21+
[`wasmtime::InstanceAllocationStrategy`](https://docs.rs/wasmtime/latest/wasmtime/enum.InstanceAllocationStrategy.html),
22+
and
23+
[`wasmtime::Config::allocation_strategy`](https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.allocation_strategy)
24+
for more details.
25+
26+
## Enable Copy-on-Write Heap Images
27+
28+
Initializing a WebAssembly linear memory via a copy-on-write mapping can
29+
drastically improve instantiation costs because copying memory is deferred from
30+
instantiation time to when the data is first mutated. When the Wasm module only
31+
reads the initial data, and never overwrites it, then the copying is completely
32+
avoided.
33+
34+
See the API docs for
35+
[`wasmtime::Config::memory_init_cow`](https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.memory_init_cow)
36+
for more details.
37+
38+
## Use `InstancePre`
39+
40+
To instantiate a WebAssembly module or component, Wasmtime must look up each of
41+
the module's imports and check that they are of the expected types. If the
42+
imports are always the same, this work can be done ahead of time, before
43+
instantiation. A `wasmtime::InstancePre` represents an instance *just before* it
44+
is instantiated, after all type-checking and imports have been resolved. The
45+
only thing left to do for this instance is to actually allocate its memories,
46+
tables, and internal runtime context, initialize its state, and run its `start`
47+
function, if any.
48+
49+
See the API docs for
50+
[`wasmtime::InstancePre`](https://docs.rs/wasmtime/latest/wasmtime/struct.InstancePre.html),
51+
[`wasmtime::Linker::instantiate_pre`](https://docs.rs/wasmtime/latest/wasmtime/struct.Linker.html#method.instantiate_pre),
52+
[`wasmtime::component::InstancePre`](https://docs.rs/wasmtime/latest/wasmtime/component/struct.InstancePre.html),
53+
and
54+
[`wasmtime::component::Linker::instantiate_pre`](https://docs.rs/wasmtime/latest/wasmtime/component/struct.Linker.html#method.instantiate_pre)
55+
for more details.
56+
57+
## Putting It All Together
58+
59+
```rust,ignore
60+
{{#include ../examples/fast_instantiation.rs}}
61+
```
62+
63+
## See Also
64+
65+
* [Pre-Compiling Wasm Programs](./examples-pre-compiling-wasm.md)
66+
* [Tuning Wasmtime for Fast Wasm Compilation](./examples-fast-compilation.md)
67+
* [Tuning Wasmtime for Fast Wasm Execution](./examples-fast-execution.md)
68+
* [Wizer, the WebAssembly Pre-Initializer](https://github.com/bytecodealliance/wizer)

docs/examples-interrupting-wasm.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Interrupting Wasm Execution
2+
3+
If you want to interrupt Wasm execution, for example to prevent an infinite loop
4+
in the Wasm guest from indefinitely blocking the host, Wasmtime provides two
5+
mechanisms you can choose between. Wasmtime also allows you to choose what
6+
happens when Wasm execution is interrupted.
7+
8+
## What Happens When Execution is Interrupted
9+
10+
When a Wasm program's execution is interrupted, you can configure Wasmtime to do
11+
either of the following:
12+
13+
* **Raise a trap:** This terminates the current Wasm program, and it is not
14+
resumable.
15+
16+
* **Async yield:** This pauses the current Wasm program, yields control back to
17+
the host, and lets the host decide whether to resume execution sometime in the
18+
future.
19+
20+
These options are both available regardless of which interruption mechanism you
21+
employ.
22+
23+
## Interruption Mechanisms
24+
25+
### Deterministic Fuel
26+
27+
Fuel-based interruption is completely deterministic: the same program run with
28+
the same amount of fuel will always be interrupted at the same location in the
29+
program (unless it has enough fuel to complete its computation, or there is some
30+
other form of non-determinism that causes the program to behave differently).
31+
32+
The downside is that fuel-based interruption imposes more overhead on execution,
33+
slowing down Wasm programs, than epochs do.
34+
35+
```rust,ignore
36+
{{#include ../examples/fuel.rs}}
37+
```
38+
39+
See these API docs for more details:
40+
41+
* [`wasmtime::Config::consume_fuel`](https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.consume_fuel)
42+
* [`wasmtime::Config::set_fuel`](https://docs.rs/wasmtime/latest/wasmtime/struct.Store.html#method.set_fuel)
43+
* [`wasmtime::Config::fuel_async_yield_interval`](https://docs.rs/wasmtime/latest/wasmtime/struct.Store.html#method.fuel_async_yield_interval)
44+
45+
### Non-Deterministic Epochs
46+
47+
Epoch-based interruption imposes relatively low overhead on Wasm execution; it
48+
has been measured at around a 10% slowdown. It is faster than fuel-based
49+
interruption.
50+
51+
The downside is that it is non-deterministic. Running the same program with the
52+
same inputs for one epoch might result in an interrupt at one location the first
53+
time, a later location the second time, or even complete successfully another
54+
time. This is because it is based on wall-time rather than an exact count of how
55+
many Wasm instructions are executed.
56+
57+
```rust,ignore
58+
{{#include ../examples/epochs.rs}}
59+
```
60+
61+
See these API docs for more details:
62+
63+
* [`wasmtime::Config::epoch_interruption`](https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.epoch_interruption)
64+
* [`wasmtime::Config::epoch_deadline_trap`](https://docs.rs/wasmtime/latest/wasmtime/struct.Store.html#method.epoch_deadline_trap)
65+
* [`wasmtime::Config::epoch_deadline_callback`](https://docs.rs/wasmtime/latest/wasmtime/struct.Store.html#method.epoch_deadline_callback)
66+
* [`wasmtime::Config::epoch_deadline_async_yield_and_update`](https://docs.rs/wasmtime/latest/wasmtime/struct.Store.html#method.epoch_deadline_async_yield_and_update)

0 commit comments

Comments
 (0)