wazero v1.0.0-pre.3
Pre-releasewazero v1.0.0-pre.3 focuses on Application Binary Interface (ABI) developers and performance.
Note: wazero will require minimally Go 1.18 when 1.0 is released early next year.
To recap, an Application Binary Interface (ABI) is a contract between the WebAssembly host and the guest, primarily defining functions each side can import. Your application that embeds wazero is the host, and the guest is %.wasm
which wazero instantiates. There are often performance concerns across this boundary. The latest release of wazero cuts some of this by 1us per call, which can add up for frequently called functions. Thanks very much to @anuraaga @codefromthecrypt and @hafeidejiangyou for the help on the main changes of v1.0.0-pre.3 described below!
A few of us have been working on a new ABI http-handler, and in the process renovated how wazero does host functions, particularly to be much more efficient. Many users will have no impact, because they don't define any custom ABI or host functions. Those who do, minimally need to make a change like this:
ctx := context.Background()
-hello := func() {
+hello := func(context.Context) {
fmt.Fprintln(stdout, "hello!")
}
-_, err := r.NewHostModuleBuilder("env").ExportFunction("hello", hello).Instantiate(ctx, r)
+_, err := r.NewHostModuleBuilder("env").
+ NewFunctionBuilder().WithFunc(hello).Export("hello").
+ Instantiate(ctx, r)
Power users can now use HostFunctionBuilder
to define functions that won't use reflection. There are two choices of interfaces to use depending on if that function needs access to the calling module or not: api.GoFunction
and api.GoModuleFunction
. Here's an example defining one.
builder.WithGoFunction(api.GoFunc(func(ctx context.Context, params []uint64) []uint64 {
x, y := uint32(params[0]), uint32(params[1])
sum := x + y
return []uint64{sum}
}, []api.ValueType{api.ValueTypeI32, api.ValueTypeI32}, []api.ValueType{api.ValueTypeI32})
While verbose, functions defined like this work a lot faster. If you are working on a low-level ABI, consider using it. wazero ported all of our internal functions to this approach and are happy with the results. For example, the below have no logic change except how parameters and results are passed.
Before
BenchmarkHostCall/Call
BenchmarkHostCall/Call-16 1000000 1050 ns/op
Benchmark_EnvironGet/environGet
Benchmark_EnvironGet/environGet-16 525492 2224 ns/op
Now
BenchmarkHostCall/Call
BenchmarkHostCall/Call-16 14807203 83.22 ns/op
Benchmark_EnvironGet/environGet
Benchmark_EnvironGet/environGet-16 951690 1054 ns/op
Besides the new function definition syntax, v1.0.0-pre.3 has a few more goodies for ABI developers:
Memory.WriteString
to avoid allocationsfd_write
in WASI special casesio.Discard
for more efficient discarding of stdout or stderr.CompiledModule.ExportedMemories()
is available to see if the guest exported "memory" or not, prior to instantiation.