Skip to content

wazero v1.0.0-pre.3

Pre-release
Pre-release
Compare
Choose a tag to compare
@codefromthecrypt codefromthecrypt released this 31 Oct 11:25
· 1231 commits to main since this release
d108ce4

wazero 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 allocations
  • fd_write in WASI special cases io.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.