4 ms·
WASM is way way way faster if you need explicit memory management. It's only 100% a wash if you're doing DOM stuff.
by CuriouslyC 10mo ago
WASM is way way way faster if you need explicit memory management. It's only 100% a wash if you're doing DOM stuff.
- torginus 10mo agoNot necessarily. I found a benchmark that you can run yourself, that's doing pretty much just raw compute (JS vs C/C++ in Wasm): https://takahirox.github.io/WebAssembly-benchmark/ https://takahirox.github.io/WebAssembly-benchmark/ Js is not always faster, but in a good chunk of cases it is.
- CuriouslyC 10mo agoThings might be getting better for JS, but just looking over those briefly, they don't look memory constrained, which is the main place where I've seen significant speedups. Also, simpler code makes JIT optimizations look better, but that level of performance won't be consistent in real world code.
- torginus 10mo agoYou might be right in your use case, but still, JS is not the benchmark to beat. Native Client was already almost as fast as native code, started up almost instantly, and didn't get a decade of engineering with who knows how much money behind it invested into it. Webassembly that was supposed to replace it needs to be at least as good, that was the promise. We're a decade in, and still Wasm is nowhere near while it has accumulated an insane amount of engineering complexity in its compiler, and its ability to run native apps without tons of constraints and modifications is still meh as is the performance.
- azakai 10mo agoTo be fair, Native Client achieved much of its speed by reusing LLVM and the decades of work put into that excellent codebase. Also, Native Client started up so fast because it shipped native binaries, which was not portable. To fix that, Portable Native Client shipped a bytecode, like wasm, which meant slower startup times - in fact, the last version of PNaCl had a fast baseline compiler to help there, just like wasm engines do today, so they are very similar. And, a key issue with Native Client is that it was designed for out-of-process sandboxing. That is fine for some things, but not when you need synchronous access to Web APIs, which many applications do (NaCl avoided this problem by adding an entirely new set of APIs to the web, PPAPI, which most vendors were unhappy about). Avoiding this problem was a major principle behind wasm's design, by making it able to coexist with JS code (even interleaving stack frames) on the main thread.
- torginus 10mo agoI think youre referring to PNaCl(as opposed to Native Client), which did away with the arch-specific assembly, and I think they shipped the code as LLVM IR. These are 2 completely separate things, I am referring to the former. I don't see an issue with shipping uArch specific assembly, nowadays you only have 2 really in heavy use today, and I think managing that level of complexity is tenable, considering the monster the current Wasm implementation became, which is still lacking in key ways. As for out of process sandboxing, I think for a lot of things it's fine - if you want to run a full-fat desktop-app or game, you can cram it into an iframe, and the tab(renderer) process is isolated, so Chrome's approach was quite tenable from an IRL perspective. But if seamless interaction with Web APIs is needed, that could be achieved as well, and I think quite similarly to how Wasm does it - you designate a 'slab' of native memory and make sure no pointer access goes outside by using base-relative addressing and masking the addresses. For access to outside APIs, you permit jumps to validated entry points which can point to browser APIs. I also don't see why you couldn't interleave stack frames, by making a few safety and sanity checks, like making sure the asm code never accesses anything outside the current stack frame. Personally I thought that WebAssembly was what it's name suggested - an architecture independent assembly language, that was heavily optimized, and only the register allocation passes and the machine instruction translation was missing - which is at the end of the compiler pipeline, and can be done fairly fast, compared to a whole compile. But it seems to me Wasm engines are more like LLVM, an entire compiler consuming IR, and doing fancy optimization for it - if we view it in this context, I think sticking to raw assembly would've been preferable.
- azakai 10mo agoSorry, yes, I meant PNaCl. > I don't see an issue with shipping uArch specific assembly, nowadays you only have 2 really in heavy use today, That is true today, but it would prevent other architectures from getting a fair shot. Or, if another architecture exploded in popularity despite this, it would mean fragmentation. This is why the Portable version of NaCl was the final iteration, and the only one even Google considered shippable, back then. I agree the other stuff is fixable - APIs etc. It's really portability that was the sticking point. No browser vendor was willing to give that up.
- deleted 10mo ago[deleted]
- azakai 10mo agoIt is easy to make benchmarks where JS is faster. JS inlines at runtime, while wasm typically does not, so if you have code where the wasm toolchain makes a poor inlining decision at compile time, then JS can easily win. But that is really only common in small computational kernels. If you take a large, complex application like Adobe Photoshop or a Unity game, wasm will be far closer to native speed, because its compilation and optimization approach is much closer to native builds (types known ahead of time, no heavy dependency on tiering and recompilation, etc.).
- AlienRobot 10mo agoI would take these benchmarks with a pinch of salt. Within a single function, it's very easy to optimize JS because you know every way a single variable will be defined. When you have to call a function, the data type of the argument can be anything the caller passes to the function, which makes optimization far more complex. In practice, WASM codebases won't be simply running a single pure function in WASM from JS but instead will have several data structures being passed around from one WASM function to another, and that's going to be faster than doing the same in JS. By the way, if I remember correctly V8 can optimize function calls heuristically if every call always passes the same argument types, but because this is an implementation detail it's difficult to know what scenarios are actually optimized and which are not.