Skip to content

v1.0.0

Compare
Choose a tag to compare
@github-actions github-actions released this 24 Mar 19:24
· 765 commits to main since this release
22f8d9d

wazero v1.0.0 completes our six month pre-release period and begins our compatibility promise. We will use semantic versions to label releases, and not break APIs we've exposed as non-experimental.

Those not familiar with wazero can check out this blog which overviews the zero dependency runtime. You can also check out our website especially the community and users pages.

Many of you have been following along with our pre-releases over the last 6 months. We did introduce change since v1.0.0-rc.2 with a particularly notable feature we call "anonymous modules". So, let's talk about that first.

Anonymous modules

There are two main ways wazero is used for high-volume request handling. One way is pooling modules and the other is instantiating per-request.

The pool approach is used for functions designed to be invoked many times, such as http-wasm's handler functions. A host, such a dapr keeps a pool of modules, and checks one out per request.

The re-instantiate approach is where you know you can't re-use a module, because the code is not safe to invoke more than once. For example, WASI commands are not safe to re-invoke. So, you have to instantiate a fresh module per request. You can also re-instantiate for higher security on otherwise safe functions.

The latter case was expensive before, because we had to make sure each request had not just a new module, but also a unique name in the runtime. You would see things like this to do that.

// Currently, concurrent modules can conflict on name. Make sure we have
// a unique one.
instanceNum := out.instanceCounter.Add(1)
instanceName := out.binaryName + "-" + strconv.FormatUint(instanceNum, 10)
moduleConfig := out.moduleConfig.WithName(instanceName)

Both allocating a unique name and also name-based locks have a cost to them, and very high throughput use cases, such as event handling would show some contention around this.

Through a lot of brainstorming and work, @achille-roussel @ckaznocha and @mathetake found a clever way to improve performance. When a module has no name, it has nothing to export to other modules. Most of the lock tension was around things to export, and an unnamed module is basically a leaf node with no consumer except the host. We could avoid a lot of the more expensive locking by special-casing modules instantiated without a name.

In the end, to improve re-instantiation performance (when you can't pool modules), clear your module name!

-       // Currently, concurrent modules can conflict on name. Make sure we have
-       // a unique one.
-       instanceNum := out.instanceCounter.Add(1)
-       instanceName := out.binaryName + "-" + strconv.FormatUint(instanceNum, 10)
-       moduleConfig := out.moduleConfig.WithName(instanceName)
+       // Clear the module name so that instantiations won't conflict.
+       moduleConfig := out.moduleConfig.WithName("")

Other changes

There were a myriad of change from wazero regulars, all of them in the bucket of stabilization, bug fixes or efficiency in general. @achille-roussel @codefromthecrypt and @jerbob92 put a lot of work into triage on WASI edge cases, both discussion and code. @ncruces fixed platform support for solaris/illumos @mathetake optimized wazero performance even more than before. @evacchi fixed a really important poll issue.

These were driven by and thanks to community work. For example, @Pryz led feedback and problem resolution for go compiler tests. Both @ncruces on go-sqlite and @jerbob92 on pdfium shared wins and opportunities for next steps.

In short, there were a lot of exciting relevant work in the short period between rc2 and 1.0.0, and we are lucky for it!