WasmEdge
wasmedge.org
wasmedge.org
> The wasmedge CLI tool will execute the WebAssembly in ahead-of-time(AOT) mode if available in the input WASM file.
> The wasmedgec can compile WebAssembly into native machine code (i.e., the AOT compiler). For the pure WebAssembly, the wasmedge tool will execute the WASM in interpreter mode. After compiling with the wasmedgec AOT compiler, the wasmedge tool can execute the WASM in AOT mode which is much faster.
They added an option (--force-interpreter) to disable running untrusted native code [2]:
> Thanks for reporting this. I think we can have a flag to disable the automatically loaded AOT sections from an unknown given universal wasm format. One possible situation is that users want to execute a wasm file with interpreter mode, however, they use a universal wasm format received from a malicious developer, and then the bad thing happens.
[0]: https://wasmedge.org/book/en/cli/wasmedge.html
For server side deployment, you should always do the AOT compilation on the server. But I agree this could be more clear. We are adding a new CLI option to disable AOT code segment in the WASM file for people who do not wish to perform the separate AOT compilation step.
One of the challenges is that Wasm supports multiple languages. So, we will have to decide to start from a Rust app or a JS app or something else. Would love your suggestions.
> In the end, running v8 in a cloud-native environment often requires a full stack of software tools consisting of "Linux container + guest OS + node or deno + v8", which makes it much heavier and slower than a simple WasmEdge + QuickJS container runtime.
https://wasmedge.org/book/en/write_wasm/js.html#a-note-on-v8
Whether it's faster or not really depends on the complexity of what's being run. After reading about wasmtime 1.0's super fast 5 microsecond snapshot restore time (https://bytecodealliance.org/articles/wasmtime-1-0-fast-safe...) I did some experiments with QuickJS and Javy which runs QuickJS in wasmtime. Rendering a moderately complex web page with React renderToString production 30kB of html on my MacBook Air M1 took:
- Deno first iteration: 12-20ms
- Deno subsequent iterations: 2-4ms
- qjs native: 18-24ms
- javy (qjs wasmtime): 40-60ms
I've not tried WasmEdge but it's JS performance would presumably fall somewhere between that of qjs native and under wasmtime.
Firecracker claims a ~3ms snapshot restore time on ARM so might be the best way to go currently for such workloads but there is certainly a large subset of problems for which the current performance is adequate.
There has been talk of AOT compilation for SpiderMonkey.wasm (https://bytecodealliance.org/articles/making-javascript-run-...) which I hope this will some day happen since it should close the gap substantially. I recently asked on the ByteCode Alliance Zulip but there hasn't yet been any progress and it requires a substantial amount of work.
Why should QuickJS use less runtime memory?
Genuine question, I just recently learned of QuickJS and what I understand, it is way smaller in itself, meaning you do not need so much memory for the engine itself, but that does not say anything how efficient it is with executing js code. Or are there benchmarks that say, it is also more memory efficient with executing js?
Either way, yes, I also think meassuring memory is important.
A simple interpreter can avoid all those. It can build a very simple and compact bytecode and just execute that.
(But, of course, the speedups in optimizing JITs are usually worth it! 10x or more.)
There are already multiple runtimes that can run both WebAssembly and Javascript/TypeScript. The JS runtimes themselves. V8 does a great job of running both wasm and JS. And a custom V8 (or JavaScriptCore or whatever) embedding with appropriate sandboxing can be put together without a huge amount of work.
Seems like the better peg for the hole in question if people want support for JS and WASM in a hosted environment.
One of the benefits of running JS in Wasm (specifically the QuickJS approach) is that you can create JS APIs in Rust. That allows you to move a lot of compute intensive operations into Rust while still giving your developers a clean and nice JS API. WasmEdge does this with its JS Tensorflow API:
https://wasmedge.org/book/en/write_wasm/js/tensorflow.html
In fact, we are using Rust to support the entire Node.JS API in WasmEdge. :)
After working on a couple codebases that used wasmtime and wasmer heavily, I think if I were to start from scratch I'd just use V8 as my WASM runtime.
(And the model I would follow would be to containerize the V8 runtime piece inside its own cgroup, with resource budgets and permission constraints. cgroups accounting beats the limited and inefficient accounting one gets from the various WASM runtime opcode based accounting systems.)
Today, there are a large set of Rust apps that can run in WasmEdge, wasmtime, Fermyon spin, wasmCloud etc, but would not run on v8’s embedded Wasm engine …
However, I do agree that v8 excels in JavaScript.
In fact, Node.js and Deno have both done exactly that, a V8 core with layered APIs on top including WASI.
Isolates are one option but I believe startup time for isolates with a snapshot is actually slower than Firecracker's snapshot restore.
Developing with Firecracker is somewhat annoying since it requires support for nested virtualization (doesn't work on Mac M1 or AWS, though does on GCP and GitHub Codespaces. The M2 has hardware support so development on Mac should work eventually.)
The various WebAssembly runtimes have really put a lot of work into getting fast snapshot restore with Wasmtime 1.0 doing so in microseconds. I'd love to be able to run server rendering in such an environment.
I've been looking at quickjs issues and forks and see a lot of random fixes from various people and most of them don't seem to be accepted or responded to:
* https://github.com/bellard/quickjs/issues/131
* https://github.com/bellard/quickjs/issues/130
* https://github.com/bellard/quickjs/issues/129
* https://github.com/bellard/quickjs/issues/123
* https://github.com/bellard/quickjs/issues/111
* https://github.com/bellard/quickjs/issues/103
* https://github.com/bellard/quickjs/issues/96
The mailing list doesn't seem to have a lot of responses either. So, it's actually hard to say. The first instinct is it's great to base a product on such a talented programmer's work, but it seems you should be proficient enough to debug and fix issues yourself to do that.
No blame or slight to Fabrice, of course, I am always impressed by his work, and he certainly doesn't owe anyone any of his time.
If you refer towards Wasm module loading times (once a module is already been precompiled), Wasmer is already one of the fastest ones.
- v1: desktop software (1980-2000)
- v2: web software, single tenant, single datacenter
- v3: web software, multi-tenant, single data center
- v4: web software, multi-tenant, hosted in “cloud”
- v5: web software, multi-tenant, hosted on cloud “edge”
- v6: electron apps installed “hosted” on desktop (the ultimate cloud edge)
Full circle.
We could actually get a nice performance boost out of running WASM with VM enforced security instead of Rings and the MMU.[0]
[0]: https://www.destroyallsoftware.com/talks/the-birth-and-death...
For example, the wasmedge website claims it is the fastest runtime but I notice that your comparison page doesnt mention runtime performance at all. It would be nice to know how much slower is wasmer in that respect.
I feel that if wasmer covered things like this in the comparisons, and was highlighting that its only X% slower (even though thats a negative) I could balance the positives accordingly when making a decision about which runtime to choose.
There doesnt seem to be anywhere that provides an unbiased comparison. Maybe wasmer could lead the charge in that respect?
The places where there are no differences between runtimes are not showcased in the shared page intentionally.
Runtime performance it's not hidden because Wasmer is slower, it's hidden because there should be little difference on runtime performance between both runtimes. But just to be clear, Wasmer (when used with LLVM) should be as fast (if not faster) than WasmEdge on runtime performance.
As a random fact: Wasmer 3.0 uses zero-copy deserialization mechanisms that are not yet implemented by any other runtime. So I bet my horses that Wasmer running a pre-compiled Wasm module is not just at-level with WasmEdge but probably faster :)
> There doesnt seem to be anywhere that provides an unbiased comparison. Maybe wasmer could lead the charge in that respect?
This is a great suggestion, actually.
Performance benchmarking is complicated. We have published peer reviewed studies that show WasmEdge is the fastest in some cases. Would love to see how it performs on your workloads.
Paper: A Lightweight Design for High-performance Serverless Computing, published on IEEE Software, Jan 2021. https://arxiv.org/abs/2010.07115
Article: Performance Analysis for Arm vs. x86 CPUs in the Cloud, published on infoQ.com, Jan 2021. https://www.infoq.com/articles/arm-vs-x86-cloud-performance/
Source code of test cases: https://github.com/second-state/wasm32-wasi-benchmark
* Lightweight (no GC, under 2MB) * Designed to be a secure sandbox (not just a language runtime) * Modular (add host functions as needed — eg support for Tensorflow) * Multiple languages (esp compiled languages like Rust) * Works with container tools (Docker, k8s etc)
Designed to be a secure sandbox (not just a language runtime) => JVM and CLR also were designed as such. It didn't work out as well as planned, when black hat hackers started researching how to game the sandbox. Still open for WASM.
Modular (add host functions as needed — eg support for Tensorflow) => JVM and CLR have dynamic code loading capabilities. WASM still hasn't standardized dynamic linking
=> Multiple languages (esp compiled languages like Rust) => Just like CLR, hence why it is Common Language Runtime, C and C++ were part of version 1.0 release.
Works with container tools (Docker, k8s etc) => Just like JVM and CLR do.
Besides that, WASM allows for an open universal standard for VMs. This means that we can easily develop with many different languages for WASM.
WASI development has indeed been quite slow. Most of our efforts for the past 2 years have been developing and implementing the Component Model proposal. Right now we are working on porting WASI to the component model, which has been pushing all of the new wit tooling more than it has WASI itself.
I can’t really say that adding more people would have sped up the last few years. The vision of the component model is very ambitious - it’s the first credible open (as in, not owned by Oracle or MS) standard for a real cross language VM, and the security posture supports mutually distrustful components by default. If we had just iterated on the witx version of wasi without coming up with the component model first, I believe both the component model and wasi would be worse off for it.
A lot of the foundational spec work and tooling is now (hopefully!) pretty stable. We used to rewrite everything related to the component model (fka interface types or module linking) every 6-9 months because the spec changed really radically, now I genuinely believe you’ll be able to take todays wit-bindgen to production in 6-9 months of polishing. We are approaching the point where we can get those tools in the hands of way more contributors and the ecosystem can grow.
So yes, the contributors to it today are small, but they are growing (I’ve spent a big chunk of the last few weeks bringing on more contributors from other bca companies) and soon will be able to grow even more.
Still confused why the need for wit file instead of wat directly which is already human-friendly. Now wasm has two versions of text mode?
Appreciated, specification is a hard work.
* the component model wat can represent interfaces, but it can’t represent the composition of interfaces, e.g. if we were writing a new interface which opened something file-like and wanted to reuse the oflags type from wasi-filesystem, there would be no way to express that indirectly because we insist wasm binaries are self contained (don’t require you to load other resources), so the oflags type definition would need to be copied in literally.
* when we add resource types back to wit syntax (you can rewind history in wit-bindgen 2 months to find examples, we got rid of them because they were a strawman and now something quite similar is getting speced) it’s nice to have wit syntax appear just like constructors and methods, even if we all know a method desugars to a functions that take a resource as it’s first parameter in the canonical abi. It’s nice to have a distinction in wit that can be used by code generators for creating idiomatic C++, Rust, JS etc methods. Even if we give methods a faithful wat/binary repr (like, e.g. flag types, which are a shorthand for a struct full of bools), the wat/binary form will necessarily have much worse syntax than the wit will, and we think having a syntax that doesn’t send you rubbing your temples reading the component model spec will help adoption.
Speaking as someone who has had to read and write a nontrivial amount of wat over the last 5 years, it’s lovely for small examples and it’s pretty challenging for large, “real world” programs.
Thanks again for the effort of the elaboration.
It's great that you're developing WASI but I don't see how it's any more open than the JVM or .NET CLR. Obviously from a licensing perspective it's not any different, anyone can go implement the JVM or CLR specs. In the past the JVM and Java even had a rather complicated community process designed to disempower Sun, some aspects of which remain today.
It sounds like WASM/WASI is something similar but with Fastly being the dominant company instead of Oracle/MS. I went to the bytecodealliance github repo and picked a random repository with "wasi" in the name and looked at the last commit. It was by someone who works at Fastly. Technical specs always have some firm or another pushing more than others at any given point, that's not what determines if they're open or not.
Also, both the JVM and CLR have had support for mutually distrusting components from the start, so that's not really new either. That support didn't get widespread use because sandboxing even at the process level for individual apps is still rather rare, and sandboxing at the sub-component level proved too hard to get right with the CLR/JVM approach. It's probably better to argue that what you're doing with WASI is better in some concrete technical sense rather than arguing it's new.
After that is done, I'd expect to see a lot of focus shift to fleshing out various WASI APIs, which can then also IINM start to be released individually at their own pace.
I keep seeing this kind of statement, but is it actually true? Are there any good benchmarks around this?
Paper: A Lightweight Design for High-performance Serverless Computing, published on IEEE Software, Jan 2021. https://arxiv.org/abs/2010.07115
Article: Performance Analysis for Arm vs. x86 CPUs in the Cloud, published on infoQ.com, Jan 2021. https://www.infoq.com/articles/arm-vs-x86-cloud-performance/
Source code of test cases: https://github.com/second-state/wasm32-wasi-benchmark
See if these helps. (Kinda old so will be needing more updated ones)
The benefit of using Wasm as a wrapper is its high performance (Use Rust to prepare data) and multi language support (inference in JS!)
WasmEdge supports Tensorflow, PyTorch, and OpenVINO as wasi-NN backends.
We would love to see more containerization on the edge:
https://www.cncf.io/blog/2021/11/11/containerization-on-the-...
"Spin is an open source framework for building and running fast, secure, and composable cloud microservices with WebAssembly"
https://github.com/fermyon/spin/discussions/861
With WasmEdge there is no vendor lock-in
Both Spin and the Fermyon Platform are open-source projects. Fermyon Cloud is a managed service built on top of the Fermyon Platform.
In comparison with WasmEdge, the WebAssembly runtime used in Spin is Wasmtime, which is also open sourced and built by the Bytecode Alliance.
Hope this expands upon the existing response.
That sounds... Untrue.
Impressive and very cool!
By that argument there is no difference between 80% and 85% or 1% and 2%. One should absolutely reduce their attack surface. If the goal is to be "lightweight" as compared to containers, then WasmEdge would be running as a regular OS process and not in a jail or cgroups container. By construction, WasmEdge has a greater threat model vs rootless containers. I am huge fan of Wasm, but my appreciation for a technology doesn't outweigh the risk posed by the runtime. Its security properties are intractable.
Are you saying that end users should overlook this?
Yes — this argument makes a lot more sense to me compared to “kloc of C/C++”.
1 C++ apps can run a lot of edge hardware devices and OSes. We are running on RTOS like seL4 and CPUs like RISC-V.
2 There are already two leading Wasm runtimes written in Rust when we started. We thought runtime diversity is important from security and reliability point of view.
It is indeed more challenging to run C++ programs securely. We are participating Google’s OSS-fuzz program.
Of course, for application developers, WasmEdge provides “Rust first” SDKs and APIs. Almost all of our new features are available in the Rust SDK first. :)
Also, there are so many things that need to be done right for a VM specifically to actually be safe that merely being written in a safer language is lightyears away from being adequate. You _still_ need very careful design, dynamic analysers, and a whole lot of fuzzing if you want to end up with something you can reasonably trust. So if it were written in Rust as Wasmtime is, that alone wouldn't actually give me much more confidence that it's safe to use it on untrusted inputs.
I say all this as a huge advocate for Rust in general. Sometimes the less attractive tool is actually a better choice.
One can do lots of things. Yes all of those things are still issues, but in enumerating all the things as you have, you make a compelling argument not to use C++. If one picks something else like SML, Go or even Rust, it allows them to focus on those common areas of correctness and not also, all that other stuff.
I don't think you are apologizing for C++, but I hear this a lot, whatabout all the other parts that are fixed by a more sound system? My response is that we only have so many decisions we can make in the day, using a system that removes whole classes of problems allows me to focus on the non-accidental (forced) complexity.
> Rust as Wasmtime is, that alone wouldn't actually give me much more confidence that it's safe
I never made that argument. But let's say I did. Given two systems, one made in Rust and one made in C++. How do I audit the C++ code to ensure that it has the same level of safety as basically _anything_ else?
WasmEdge is using code coverage, good! https://app.codecov.io/gh/WasmEdge/WasmEdge
Only 80% coverage, not great.
I see mention of fuzzing being used, but I only get 69 hits in the codebase for "fuzz" and no documentation about how it actually works.
Wasmtime includes documentation on how to use their fuzzer, https://github.com/bytecodealliance/wasmtime/tree/main/fuzz
In my cursory look at the WasmEdge codebase I see
No application UBSan [1]
No application of control flow guard [2], either in the build or in the generated LLVM output.
Infact the only sanitization flags they are passing are -fsanitize=fuzzer,address
0 mentions of 'control flow' in the WasmEdge codebase, 65 mentions in Wasmtime. Although it doesn't appear that Wasmtime is itself being compiled with cfguard.
309 mention of spectre mitigations in Wasmtime, 1 link to a cloudflare blogpost in WasmEdge.
In my cursor look at Wasmtime, I see
Much better fuzzing support, 85 uses of unsafe in cranelift itself, 1400+ uses of unsafe in crates/*
The changelog and git messages for WasmEdge talk about type errors (those type errors look impossible in Rust), bus errors, out of bounds, etc.
It does not inspire confidence. C++ is already starting from behind. This software is targeted to be run on bare metal, embedded and widely distributed. It just doesn't have the level of detail around testing and correctness that I would expect for such a critical piece of infrastructure.
I am not saying that Wasmtime does not also have issues, that would be preposterous. But on the face of it, WasmEdge has a lot of work to do to catch up to where Wasmtime already is.
Wasmtime appears to care about the security properties of their dependencies with https://mozilla.github.io/cargo-vet/
It does not look like the WasmEdge project applies this basic list of practices as outlined by Jason Turner [n]
[1] https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html
[2] https://www.zdnet.com/article/microsofts-control-flow-guard-... https://clang.llvm.org/docs/ControlFlowIntegrity.html
[n] https://www.youtube.com/watch?v=q7Gv4J3FyYE https://github.com/lefticus/cpp_weekly/issues/175
I'm left with one difficult question, though. What should we do when trying to target environments that aren't well-served by languages like Rust? The demand is clearly there, so people will keep building new things using C and C++. What do you see as the most realistic path forward for these use cases? Push harder on platform support in Rust?
Change my mind.
The application use cases include containerization on edge devices, serverless functions on edge cloud, embedded functions for databases or SaaS, stream functions for data pipelines, or even smart contracts for blockchains.
All of the above are “edge” use cases in the sense that they are typically outside of mega data centers. :)
The term doesn't have a lot to do with how efficient or non-efficient the software that is run in those places is.