wazero: the zero dependency WebAssembly runtime for Go developers
Hiya folks, time to celebrate the new wazero release again! The last release 1.7.0 was such a blast so this new 1.7.1 is a little bit boring compared to it, but it still has some niceties!
This patch release has basically two major things: various bug fixes and experimental memory allocation API!
Since the release of 1.7.0, several community members (@jerbob92, @anuraaga and @davidmdm) tried the new optimizing compiler and reported some bugs. @mathetake and @evacchi worked on the fix and all the reported bugs were removed. Notably, the arm64 compiler has become more robust against huge binaries like the ones produced by the Go official compiler, in addition to a corner case in the bounds check elimination optimization pass applied to both arm64 and amd64.
The experimental Memory Allocator API has been added to our experimental friends by @ncruces in collaboration with @achille-roussel. This allows you to control how to allocate the linear memory of Wasm instance. For instance, you can use a memory mapped buffer as a Wasm linear memory. This is highly advanced feature hence requires a lot of detailed knowledge on how Wasm module works. If this is something interesting to you, we highly recommend to talk to @ncruces who is an expert in here ;)
Welcome to wazero 1.7: the release that upgrades like a minor, but feels like a major!
It's finally time for the long-awaited, final release of our brand new optimizing compiler. This is such a big deal that we are celebrating it at Wasm I/O 2024 with another round of wonderful lightning talks from wazero users like we did in 2023. In fact, even this release is being tagged during the event! Stay tuned on our usual channels to see the recording:
Translating Wasm bytecode into machine code can take multiple forms. An optimizing compiler performs multiple nontrivial transformations on the input code, ultimately producing more efficient ("optimized") code.
In 1.7 we replaced our internal wasm compiler with an optimizing one. This means it is a drop-in: you don’t need to do anything to use it. If interested in compiler design, please read the docs, contributed by @evacchi.
As for performance improvements, we have come to expect a run-time boost ranging from 10% to even 60%, with 30-40% being the average. Notably:
GOOS=wasip1
) showing at least 30% improvements on the syscall
, compress/flate
(gzip) and encoding/json
packages, with peaks of 60% (especially in data throughput).While a major improvement, we decided against calling this version 2.0. If we did, we would cause library dependency lockups due to go imports needing a ‘/v2’. We take backwards compatibility seriously, so couldn’t do that to you!
As usual, @mathetake owns the lionshare of the contributions, with @evacchi helping along the way, especially on the new amd64
backend. Notably, @achille-roussel also contributed a performance improvement to the compiler (#2026) and @ncruces helped in many ways with testing and verifying the implementation, validating (among other things) against his library go-sqlite3.
Note: an optimizing compiler does more work, so it takes longer. Production use of wazero should always compile wasm during initialization to avoid slowing down function runtime.
The Wasm Threads spec introduces instructions to explicitly share memory between modules, and new operations for atomic memory access. Compilers may use this feature for concurrent threads of execution. For instance @anuraaga’s Go ports of protoc plugins needed atomic instruction support to compile to Wasm.
1.7 concludes a long journey started with @anuraaga's first PR #1899 and continued with @mathetake occasionally tag-teaming, especially to support in the new compiler; @ncruces assisted with reviewing.
You can enable Wasm Threads support by setting the corresponding flag:
// Threads support must be enabled explicitly in addition to standard V2 features.
cfg := wazero.NewRuntimeConfig().
WithCoreFeatures(api.CoreFeaturesV2 | experimental.CoreFeaturesThreads)
For a usage example see features_example_test.go
The Snapshot/Restore experimental feature saves the state of a wasm function and restores it later. This feature has been contributed by @anuraaga to implement exception handling in wasilibs/go-pgquery
You can enable snapshot/restore by setting the context flag:
// Enable experimental snapshotting functionality by setting it to context. We use this
// context when invoking functions, indicating to wazero to enable it.
ctx = context.WithValue(ctx, experimental.EnableSnapshotterKey{}, struct{}{})
For a detailed example see experimental/checkpoint_example_test.go and for further details read PR #1808.
Notably, the Thread Spec and Snapshot/Restore were originally developed as part of the wazerox friendly fork to support wasilibs. With both features making it into this release, @anuraaga could proceed with archiving wazerox: another win from wazero 1.7!
GOOS=gojs
has been dropped (@mathetake, #2027)TestErrorBuilderGoRuntimeError
, #2142)Thanks everyone for making wazero awesomer and awesomer!
This is a pre-release for wazero 1.7.0. You can watch Releases for the final 1.7.0
Hey, gophers! Do you know what time it is? It is that time of the year again! That time when we all gather together to share our time with friends and family to celebrate ANOTHER AWESOME WAZERO RELEASE!
Notably, this release includes the first public experimental release of the long-awaited, highly-requested multi-pass optimizing compiler! Keep reading for more details!
A huge thanks to all the contributors, old and new, and always remember that all the developers hang out at the Gophers Slack in the #wazero channel; and if you haven’t already you can star our repo. You know, Santa is making a list, and checking it twice.
It’s been a while since v1.5.0, but we promise v1.6.0 was worth the wait! Fun facts about v1.6.0:
Jokes aside, we have a lot to cheer about! The lion share of this release is obviously our brand new optimizing compiler (codename “wazevo”) now available as an experimental feature for arm64 (#1496)!
@mathetake led the design and implementation. Work started this summer, and it has evolved in a few iterations over the last months. Initial focus has been on general abstract infrastructure and support to the arm64 instruction set as our first compilation target. @evacchi contributed to the arm64 backend with special focus on the SIMD instructions, and @achille-roussel helped improve the initial register allocator (this was then further evolved and eventually overhauled again by @mathetake). @ncruces contributed with suggestions and testing.
We held off a few releases to polish this new compiler and gain more confidence in the implementation. In this first public release, the optimizing compiler is only available for arm64. The journey to supporting amd64 is set to begin soon with @evacchi leading the effort.
The new compiler has been, as usual, extensively tested against the Wasm spec, our own unit tests, and against the standard libraries of TinyGo, Go and Zig; and of course it has also been hardened through hours-long fuzzing.
You can enable the optimizing compiler by replacing wazero.NewRuntimeConfigCompiler()
or wazero.NewRuntimeConfig()
with the new experimental API as follows:
- c := wazero.NewRuntimeConfigCompiler()
+ c := opt.NewRuntimeConfigOptimizingCompiler()
- c := wazero.NewRuntimeConfig()
+ c := opt.NewRuntimeConfigOptimizingCompiler()
The CLI is now also exposing an experimental flag -optimizing-compiler
:
wazero run -optimizing-compiler myapp.wasm
The optimizing compiler is an experimental feature so we welcome your input. It is also a work in progress: we implemented only a few optimization passes, guiding our choices through testing and benchmarking.
It is worth noting that WebAssembly is an interesting beast: since it is a compilation target, most compilers generate pre-optimized output; therefore, some traditional optimization passes may surprisingly only add build-time overhead and produce no observable improvement. However, our work there is far from being done: more optimization passes can be added; we invite you to do your experiments and bring your own suggestions. For instance, among others, we currently implement forms of dead-code elimination, and bounds-checking eliminations.
In your experiments, you should also expect the CompileModule
phase to take a while longer than the old compiler: the difference may be noticeable with large modules; but you can still cache the result, so you can pay this cost only once. The good news is that, in our tests, the run-time should always visibly improve. Interestingly enough, there are also some cases where both compile-time and run-time have improved: this might be the case when the input module is not pre-optimized, and the dead-code elimination procedures kick in.
For instance, the Zig standard library is about 2x quicker to compile and 4x faster to run than the old compiler. However, a pre-optimized test binary (e.g. pre-processed using Binaryen’s wasm-opt
) will be much faster to build on the old compiler, but the new compiler will still produce 2x faster code. This is fully expected because the old compiler does a straightforward translation from input Wasm to native code: therefore, processing time tends to be low; but if the input is large, the generated output will be large. The new compiler is smarter, in that it is able to drop all the irrelevant code sections; in fact, processing time is about the same on both an optimized and unoptimized binary.
The bottom line is: if you control the Wasm binary, run it through wasm-opt
and compare the result for your workload!
emscripten.Instantiate
and related functions in favor of emscripten.InstantiateForModule
. Examples have been updated accordingly. This is also @Danlock’s first contribution! Cheers!Speaking of first-timers, let’s welcome them all:
emscripten
deprecation warnings mentioned above.Cheers to all of you! You are helping make wazero awesome!
Now onto the veterans!
Finally, we also welcome to the community pages:
Hey, do you know what time is it? ⏰ Yes! Time for another wazero release! 🎉
Notably, as previously announced, this release drops support to Go 1.18. But you must be here for the goodies! Don't you worry, we have you covered: there's a whole lot of updates especially for you Emscripten fanatics!
Time flies when you are having fun: WasmCon 2023 is only a few days away (5-6 September). Remember, our very own @evacchi will be there to talk about wazero, so if you are going to be there, don't be shy and say hi!
Contributor @jerbob92 together with @mathetake brought quite some improvements to our Emscripten support.
longjmp
, especially useful to exception handling (https://github.com/tetratelabs/wazero/pull/1611).What is Embind? In @jerbob92's words:
Embind allows developers to write C++ code and directly interact with that code from Javascript in the browser. It also allows to call Javascript methods directly from C++. [...] [The Wazero implementation] is trying to be a 1-on-1 implementation of the JS version in Emscripten so that the same codebase can be used for both Web and WASI WebAssembly builds.
Embind support lives in its own module and you can check it out at jerbob92/wazero-emscripten-embind!
As you may already know, we follow the Go support policy: i.e., we support each major Go release until there are two newer major releases: in v1.4.0 we added support to Go 1.21, while keeping support to Go 1.18 for a little while more. The time has come to say goodbye to Go 1.18: it's been an honor and a privilege, sir. 🫡
@evacchi (https://github.com/tetratelabs/wazero/pull/1622) and @ncruces (https://github.com/tetratelabs/wazero/pull/1620) upgraded the code paths that were relying on old workarounds or simply pointed to an older version.
While working on Emscripten support, @jerbob92 discovered that looking up and calling a non-existing function may SIGILL on some platforms (#1621). Together with @evacchi, they conducted some detective work and realized that the SIGILL was really due to a cross-compilation bug of a humble nil
dereference panic @mathetake released a workaround (https://github.com/tetratelabs/wazero/pull/1623) while the bug is fixed upstream.
@mathetake updated our CI to align our test suites to their upstream (https://github.com/tetratelabs/wazero/pull/1617, https://github.com/tetratelabs/wazero/pull/1619, https://github.com/tetratelabs/wazero/pull/1650).
Some minor issues in path handling were fixed by @evacchi in https://github.com/tetratelabs/wazero/pull/1648
We also welcome first-time contributor @philippgille who made a fix to our README! (https://github.com/tetratelabs/wazero/pull/1629)
This release is hot 🔥 like a torrid summer sun! 🏖️
Let us all rejoyce: Go 1.21 is out!! We are now promoting the existing CI tests against the Go development branch to tests against the 1.21
stable release (#1616).
As you know may already know, we follow the Go support policy: i.e., we support each major Go release until there are two newer major releases: this means starting with the next release we will drop support for 1.18
!
In case you missed it, WasmCon 2023 is taking place in Bellevue, 5-6 September so if you happen to be there, you might bump into @evacchi, who will be there to deliver a talk on your favorite zero-dependency Wasm runtime for Go (yes, that's wazero).
If you won't be there, don't forget we always hang out in the gophers slack #wazero channel. Note: You may need an invite to join gophers. Regardless, if you like what we are doing, remember to star our repo because that's what the cool kids do 😎
In the meantime, let's take a look at what is new with this release. We have the usual influx of fixes and improvements and a major feature in experimental state: enter the Virtual File System API!
Thanks to a final spike before the release @codefromthecrypt, with a lil' help from @evacchi, completed this long-awaited feature, closing issue #1013.
It is now possible to configure a virtual file system using a lower-level API under experimental/sysfs
, experimental/sys
. In order to configure a custom file system you can type:
import(
"github.com/tetratelabs/wazero/experimental/sys"
"github.com/tetratelabs/wazero/experimental/sysfs"
)
...
cfg := wazero.NewModuleConfig().
WithFSConfig(wazero.NewFSConfig().(sysfs.FSConfig).
WithSysFSMount(<experimentalsys.FS>, <guestPath>))
This lower-level API gives a higher degree of control over lower-level FS operations, as compared to fs.FS
, and ensure cross-platform portability. It handles experimentalsys.File
instances (instead fs.File
or os.File
) and returns experimentalsys.Errno
in case of error.
For instance, sysfs.DirFS
is equivalent to os.DirFS
and may be instantiated with:
fs := sysfs.DirFS("/some/path")
AdaptFS
adapts an fs.FS
:
adapted = &sysfs.AdaptFS{FS: fs}
You can also embed most of these types in your struct to provide default behavior to your own implemementation; for instance ReadFS
provides a read-only view over a file system; there is also an experimentalsys.UnimplementedFS
(returning experimentalsys.ENOSYS
for most operations) that should be always embedded in your own implementation for forward compatibility. You can find examples under experimental/sysfs
.
Notably, the Virtual File System implementation does not currently expose methods to override blocking/nonblocking behavior; during this release @evacchi and @codefromthecrypt collaborated on these internals (#1596, #1597, #1599, #1604, #1612, #1613), including the wasip1
poll_oneoff
implementation, which was improved and simplified. Related File
APIs may eventually be exposed to the VFS layer as well.
It is now possible to build wazero successfully on GOOS=plan9
(@codefromthecrypt #1603), incidentally, this also makes it possible to build on GOOS=js
(@mathetake, #1614) and GOOS=wasip1
: yes we heard you like wazero, so now you can put wazero in your wazero so YOU CAN WASM WHILE YOU WASM.
@panchen66 discovered a memory leak (#1600) happening when repeatedly re-instantiating a module. @ncruces and @achille-roussel tag-teamed (#1608, #1609) a simplified reproducer and a solution. Huge thanks!
@anuraaga contributed a fix to the amd64 compiler in case of error, and some doc corrections (#1593, #1593)
Other fixes to the documentation
sock_*
(@evacchi, #1598)Aren't you excited for the imminent release of Go 1.21 with GOOS=wasip1 GOARCH=wasm
? We are!
wazero 1.3.1 is a minor release with important changes. No public APIs have been affected in any way, but we improved portability and further moved forward support to nonblocking I/O, especially on Windows!
Remember to star wazero, and check our community for other cool wazero users like you!
@SlashScreen noticed (#1578) that builds for GOOS=plan9
were failing due to some missing constant definitions; this is somewhat related to an earlier issue reported by @supermigo (#1526) that prevents building wazero against the new GOOS=wasip1
GOARCH=wasm
target pair with Go 1.21.
@codefromthecrypt has led a spike (#1582, #1584, #1586, #1588) of refactorings to decouple our core from the direct dependency on the syscall
package, which is obviously highly platform-specific; for instance, some error codes or flags may only exist on some platforms: referring to such constants in shared code paths prevents a successful cross-platform build. #1582 introduces sys.Errno
as an abstraction over platform-specific error codes, and #1586 defines fsapi.Oflag
to abstract over file open flags.
If you are interested in that kind of oddity, support to GOOS=wasip1
will allow you to run a wasm wazero on a native wazero because self-hosting is the ultimate test for a runtime, but also because... why not? 🔥
This release is also improving support for nonblocking I/O, first by fixing a bug (#1538) that was originally addressed with #1542, but ultimately was not completely resolved. @johanbrandhorst reported that the Go CI was still producing corrupted output when writing to a redirected stdout. @evacchi uncovered the root cause of the bug rather quickly; in fact, most time was spent writing an automated test case that reproduced the conditions of the Go CI (i.e. spawning a stand-alone wazero process and hooking that stdout to a buffer). This was fixed with #1581.
Notably, @evacchi moved issue #1500 another step closer to resolving, i.e., nonblocking I/O on Windows, by emulating select
using a few different Windows APIs. Details on how this has been realized are described in #1579 and are summarized in /RATIONALE.md. Further work is still needed to close the gap in poll_oneoff
.
wazero 1.3.0 is ready for next month's release of Go 1.21.
The new GOOS=wasip1 GOARCH=wasm
will be very popular: It is the first WebAssembly platform for non-browser use. A %.wasm
file compiled with Go 1.21 runs fine in wazero. This is thanks to efforts on both sides, CI with gotip
and the latest release candidate (1.21rc2).
Go 1.21 is already bringing new developers to WebAssembly: We suggest you unconditionally upgrade in anticipation of demand. Besides this and bug fixes, you may also be interested in our new sys.Stat_t
type used for fs.FS
integration.
Don't forget to star wazero and any project relevant to you, made by our community. Let's get into the details of what's new!
wazero has two relationships to Go 1.21:
GOOS=wasip1 GOARCH=wasm
?We have made significant progress on both these points. We now run tests on every change with the latest Go 1.21 release candidate and gotip
(last commit refreshed weekly).
wazero includes logic conditional on Go versions, notably to dodge known problems on Windows with Go 1.18. This logic was made more flexible to be forwards compatible with any subsequent version. There was also a platform difference in setting file times, fixed by @evacchi. wazero now runs tests with the latest release candidate on every change, as well as everything it was testing before.
Before, there were a couple of standard library tests skipped on wazero. Notably, these were around non-blocking I/O (os.Stdout
and io.Pipe()
) and pre-opened sockets. @chriso and @evacchi collaborated to both fix these and also remove the special casing in golang/go. Edo even went beyond to improve code not tested upstream such as named pipes on Windows!
Many compilers use wasi-libc directly to implement functions such as readdir. Go doesn't rely on this, so all logic in GOOS=wasip1
is implemented directly. TinyGo's -target=wasi
is a hybrid where some features are implemented in Go and others imported from wasi-libc.
@GeorgeMac noticed some inconsistency when wrapping file systems due to this, where files without inodes were filtered out. Details such as this are not defined in wasip1
: while POSIX has something to say, there is murky water. After a long and detailed investigation between @achille-roussel and @codefromthecrypt, three things happened:
fs.FileInfo
returned from Stat
can optionally include raw info from its Sys()
method. In Unix systems, this returns *syscall.Stat_t
, allowing access to more timestamps and the file's inode.
However, *syscall.Stat_t
is not platform agnostic: its field lengths vary, and the type doesn't exist in Windows or virtual filesystems such as go:embed
.
Our first answer to this problem is to define and process a new type, *sys.Stat_t
, if returned from info.Sys()
. This allows developers to intercept *os.File
's Readdir
or any fs.File.Stat
functions to backfill inode information. For example, if a Readdir
returns file info with this, it can set a non-zero inode. This prevents a performance penalty caused by wasi-libc, which would otherwise fan out with a Stat
call for each directory entry.
It is understood this first feature is not for most integrators. However, it is an important milestone for filesystem performance and customization. wazero 1.4 will promote our internal writeable API to experimental, allowing full control over filesystem features used by wasip1
.
There were numerous small changes in 1.3, thanks to folks who brought them to our attention. Notable call out to @abraithwaite, @ncruces, @leighmcculloch who helped us understand edge cases on resource cleanup and close state concerns.
GOOS=wasip1
covering custom file systems.IsClosed()
to api.Module
for better error handling when a module exits during initialization (_start
).GOOS=js
.wazero 1.2.1 is an easy upgrade decision for everyone: There is no public API change of any kind, yet updating gives you a more portable and faster wasm runtime.
This release was helped and motivated by friendly projects in our ecosystem, please star their repos!
GOOS=wasip1
, for example, running an HTTP server with middleware, using only one thread.As usual, we have a hefty amount of background for you to enjoy, even if you aren't a wazero user, yet. Please star our repo if you like it!
WebAssembly does not yet support true parallelism; it lacks support for multiple threads, atomics, and memory barriers. This may be addressed portably in the future, when the threads proposal standardizes and common concerns like garbage collection employ it. For now, the only way to safely use wasm is sequentially, like how GOMAXPROCS=1
works in Go.
This isn't a problem in a lot of cases, but in I/O it can be. Network services often need to accept new connections while processing existing ones. Interleaving of this isn't viable with blocking I/O. The typical way to address this is using non-blocking I/O, with a loop that looks for channels which are ready and processes accordingly.
As mentioned in the 1.2.0 release, non-blocking I/O is a work in progress, and it is improved in 1.2.1. This is improved so much that @chriso was able to remove skips for HTTP and file-based non-blocking tests in the emerging GOOS=wasip1
in Go 1.21.
@evacchi focused on the problem of non-blocking I/O, both network sockets and files. He both invented some solutions and leveraged existing approaches from wasi-go to fix issues such as inability to use HTTP middleware in Go source compiled to wasm. To make sure it worked, he landed new tests, for example C code compiled with wasi-libc and go(tip) compiled with GOOS=wasip1
.
The changes are all transparent to end users, and while Edo led this effort, @achille-roussel and @chriso deserve a large thank you for support and the some prior art in wasi-go.
One final note is the battle is not over. We still have work to do in windows and surely there will be more edge cases. Please track issue 1500 and add comments if you noticed any more glitches.
While developing go-sqlite3, @ncruces noticed some opportunities both to save size in machine code and performance. This focused on "traps" which are unresolvable execution errors that happen in cases such as divide by zero or invalid bounds conditions. The basic idea was to centralize the concern, so that any instruction that could trap uses the same way out of machine code.
While developing this, Nuno found a glitch which is fast-pathing these cases can interfere with source code mapping. For example, if you were using a debugger or using a DWARF-enabled trace, the line numbers could be wrong. After discussing with others, a pragmatic way out was chosen: optimize when there is either no debug information (usually the case in release builds) or if RuntimeConfiguration.WithDebugInfoEnabled
is set to false. The latter is helpful, because it can be difficult to prevent a compiler from obfuscating function names, so some may use debug builds always. This is handy in the case of a rare bug such as a nil pointer, because you can still identify original source function by name.
While led by @ncruces, others were involved in review and design. This was made easier because Nuno kept excellent notes and comments, as well made speedtest1 to test results. @achille-roussel and @mathetake contributed feedback and @evacchi ported the implementation over to arm64 a lot easier due to the rigor involved.
The end results are really quite excellent, especially as debug info is rarely used in release builds. For example, an unrelated project kube-scheduler-wasm-extension performance improved with real data, up to 6.5%, with no other changes except upgrading to the latest patch.
We updated our TinyGo examples to v0.28.1, which supports more features (such as ReadDir and json), and more idiomatic wasm import signatures. A lot went into this release, so please thank the TinyGo team with a star!
- //go:wasm-module env
- //export log
+ //go:wasmimport env log
func _log(ptr, size uint32)
wazero 1.2.0 includes 33 days of valiant effort towards performance, interop and debug goals, shared not only in wazero, but WebAssembly in general. We appreciate folks waiting a couple more days than usual and expect you'll enjoy what you see below.
While we haven't set a formal post 1.0 release cadence, you can expect another patch or minor within a month. Meanwhile, this is our most performant and best tested release yet. As always, star all the projects that interest you, and say thanks when you can.
Performance is something we aim to always improve, release to release. This includes looking at memory usage as well as latency. While there were multiple people involved in efficiency work, @achille-roussel and @lburgazzoli deserve special call outs for leading efforts, and @ncruces deserves a big pat on the back for contributing reviews, cleanups and advice.
@achille-roussel made many changes internal to our compiler, as well linux-only specializations such as using huge pages for the memory mapped regions under wasm functions. These were all profile and benchmark guided changes and proposed in top rigor.
@lburgazzoli tracked down best practice in TinyGo, consolidating advice from various experts, such as the primary developer of TinyGo @aykevl. He worked with @ncruces to make sure our allocation example is not just a code snippet, but an exemplar of good practice, without risk of memory leaks and performance validated with benchmarks.
The combination of backend work (e.g. runtime improvements) and frontend work (e.g. changes to our TinyGo example) combined in a notable holistic gain across the board. This was true teamwork and a job well done!
$ benchstat v1.1.0.txt v1.2.0.txt
goos: darwin
goarch: arm64
pkg: github.com/tetratelabs/wazero/internal/integration_test/vs/compiler
│ v1.1.0.txt │ v1.2.0.txt │
│ sec/op │ sec/op vs base │
Allocation/Compile-12 3.365m ± 1% 3.174m ± 1% -5.66% (p=0.002 n=6)
Allocation/Instantiate-12 149.1µ ± 26% 120.4µ ± 7% -19.23% (p=0.002 n=6)
Allocation/Call-12 1.404µ ± 2% 1.297µ ± 2% -7.66% (p=0.002 n=6)
geomean 88.97µ 79.13µ -11.05%
│ v1.1.0.txt │ v1.2.0.txt │
│ B/op │ B/op vs base │
Allocation/Compile-12 2.404Mi ± 0% 1.292Mi ± 0% -46.24% (p=0.002 n=6)
Allocation/Instantiate-12 319.4Ki ± 0% 230.5Ki ± 0% -27.84% (p=0.002 n=6)
Allocation/Call-12 48.00 ± 0% 48.00 ± 0% ~ (p=1.000 n=6) ¹
geomean 33.28Ki 24.27Ki -27.07%
¹ all samples are equal
│ v1.1.0.txt │ v1.2.0.txt │
│ allocs/op │ allocs/op vs base │
Allocation/Compile-12 1.830k ± 0% 1.595k ± 0% -12.84% (p=0.002 n=6)
Allocation/Instantiate-12 803.0 ± 0% 508.0 ± 0% -36.74% (p=0.002 n=6)
Allocation/Call-12 5.000 ± 0% 5.000 ± 0% ~ (p=1.000 n=6) ¹
geomean 194.4 159.4 -18.00%
¹ all samples are equal
Compatibility is a moving target as both specifications change as well understanding of specifications. For example, the WebAssembly Core Specification 2.0 remains in a draft state, and expectations of the VM change as it changes. Also the d'facto WASI version preview1 (a.k.a. wasip1) had no tests, nor detailed documentation for the first several years of its existence. This left interop as more a quorum of implementation practice vs a spec. While new initiatives such as the wasi-testsuite and wasix aim to stabilize this, WASI compatibility remains a source of work from wazero maintainers and compiler developers. We really appreciate the efforts spent here to keep as many users unaware of these glitches as possible.
On the WebAssembly Core (VM) side, we appreciate @mathetake updating our code and spec suite to pass latest changes there. Also, we appreciate an attempt by @anuraaga with support by @ncruces on the Threads proposal, despite us ending up parking the idea until the proposal finishes.
On the WASI side, we appreciate a lot of work driven by the team working on Go. Specifically, the upcoming GOOS=wasip1
planned for 1.21 helped reveal a number of grey areas that required work to support in Go without breaking other languages. Championing these came from various team members including @Pryz, @achille-roussel and @evacchi on various file rights and non-blocking related glitches, some fixing other language runtimes such as python.
We're also excited that @evacchi began an experiment to support sockets, currently working for blocking requests. As wasm only has one thread to use, libraries often need non-blocking functionality to do anything notable. We'll report more on sockets once non-blocking glitches sort out.
Meanwhile, those using sockets know that the preview1 version of WASI is extremely limited. There are other ABI such as wasmedge_wasi_socket, wasi-sockets and most recently wasix. All of these go beyond the simple TCP sock accept, read/write in wasip1. If you'd like the bleeding edge socket support, please try wasi-go and request the features you want to experiment with. This project is a layer over wazero with an alternate syscall layer. wasi-go can move faster due to less constraints than upstream, such as Windows or virtual files. This makes it a lower risk and ideal playground to develop evolving host function (ABI) specifications. As these functions mature, what makes sense to build-in will land upstream in wazero.
We are very excited to power the only known out-of-browser CPU and memory profiler for WebAssembly, wzprof. wzprof brings the power of pprof to wasm, regardless of if the source language is Go or not.
wzprof has already served a lot of benefits in its short life so far. For example, the kube-scheduler-wasm-extension used it to isolate a garbage collection problem endemic in large protobuf decoders compiled to wasm.
Implementing this required significant work in wazero, which we are happy went upstream! @pelletier added the source offset to experimental.StackIterator
which allows source-mapping in debugging use cases. @achille-roussel polished the experimental.FunctionListener
to be more performant, including optimizing its API around errors and removing context propagation. @chriso and @mathetake helped fix some glitches along the way. Finally, @achille-roussel made it easier to develop 3rd party listeners by adding experimental.FunctionListenerFactory
to supply them and wazerotest.Module
to test them.
While we don't expect a lot of people to implement listeners, it was a great team effort to get the substrate together to the point you can build a profiler on top of it. Kudos especially to the wzprof team on finally giving wasm developers a decent profiler!
In the short term, we'll try to close the gaps on non-blocking I/O inside WASI. We still aim to have a fully pluggable filesystem soon, including an in-memory option for those needing to provide something like tmpfs from Go. Of course compatibility issues and user demands will take priority as they always do.
Longer term, @mathetake is taking on the task of an optimizing compiler affectionately named wazevo. This will likely take a year to mature, and will narrow the performance gap on certain libraries like libsodium without adding any platform dependencies whatsoever.
Meanwhile, if you want updates you can always contact the community and ask, or just wait for the next release. Until next time!