Hacker News new | ask | show | jobs
by maga 1596 days ago
> “Near-Native Performance”: Wasm is often described as having “near-native performance”. What this actually means is that WebAssembly is almost always faster than JavaScript, especially for compute-intensive workloads, and averages between 1.45 and 1.55 times slower than native code, but results do vary by runtime.

Yeah, nah: https://github.com/zandaqo/iswasmfast

JS is about 10x faster than wasm in simple linear regression, and 30% faster in levenstein distance calculation.

6 comments

At a glance, the bindings for wasm copy the data,

https://github.com/zandaqo/iswasmfast/blob/54bbb7b539c127185...

If the running code is short enough then that copy might easily make the wasm version much slower. That is indeed a known downside of wasm (calls to JS are somewhat slow, and copying of data even more so - wasm shines when you can avoid those things, which certainly limits where it makes sense!).

If it's not that, then a 10x difference suggests you are running into some kind of a VM bug or limitation.

Yep, that's it. And the data marshalling overhead is even more pronounced with the native addon example (N-API Addon). But that's the thing, it's not "WASM always faster than JavaScript" as the author presents it. And on top of that, JS engines are no slouches either, you can optimize JS code to be pretty competitive in terms of performance even for computationally heavy tasks.

WASM is _predictively_ performant, being less subject to the vicissitudes of JIT, and offers better startup performance, allows for code reusability for existing C++/Rust code, but it's not a cure-all performance solution.

It is pretty much always faster though. The same code completely written in JavaScript replaced by the same code written in Rust and compiled to WASM will nearly always be a speed up if you haven't screwed up and made the comparison apples to oranges by introducing copying or something like that. What's not always faster is mixing because of conversions. But this is just a reason to use more WASM :)
The author isn’t saying it’s a “cure all performance solution.” The quote you copied uses cautious language like “almost always” and “results do vary.”

The author also cites real world apps that have switched to WASM and seen big performance gains (Figma and 1Password), which is much more compelling than the benchmarks you shared.

You do realize that I didn't put up those benchmarks and wrote the article way back in 2017 just so that I can pick on a passage in this article? I was (and still am to a degree) excited about WASM, actually ported a significant chunk of my business logic from JS to C++ only to discover that the whole thing offered only ~20% performance boost, which didn't merit maintaining a whole separate toolchain. I'm not questioning the exciting results that Figma and such achieve, I'm saying that it's not "almost always" a case, and it's disingenuous to present it as such.
I’m just noticing that my comment went from 5 points to 0 after your reply. I’m sorry if it was upsetting. Of course I know you are not the author of the benchmarks repo.

I made that comment in good faith pointing out that the author was not saying WASM is a catch all performance booster.

But I could get on board with your claim here that “almost always” is disingenuous (which wasn’t what you were saying in the previous comment).

Yeah, that repository is measuring performance of a WASM/Node.js hybrid, and not straight WASM. Interoperability costs can certainly dominate in such cases, where straight WASM can bypass much of the cost. Such a hybrid is what you want to measure often, but certainly not always, and a large part of what this article is talking about is the potential of pure WASM unshackled by Node.js.
And how is the data going to reach the "unshackled" WASM in the browser, for example? I'm not aware of any way for the web page to interact with WASM other than through the JS land with the said overhead. The article explicitly mentions usage inside the web page and presents WASM as a performant alternative.
If you look at the success examples of 1Password or Skia they do a lot of compute based on little interaction (not no interaction). "Shackled" wasm occurs when doing things like running a string validation function as a user inputs keys into an input box, when you're constantly going between JS and WASM just to do a little work each time. It's not "I passed the data from JS and therefore it will always be slow now". In short it's not "replace any JS with WASM" it's "replace JS that isn't going to complete quickly with WASM" which is exactly the JS you should want to replace, not the stuff already running too fast to notice.

PSPDFKit is another example that added WASM to great success regarding rendering and searching. And uBlock Origin as well with its massive rule lists.

You’re still missing much the point of the article: WASM isn’t for the browser only. WASI, for example, is a full environment you can run stuff in without any such interoperability cost.

But even inside something like Node.js or the browser, most of these sorts of benchmark attempts are of converting only small parts of a system, so that message passing or format shifting ends up a comparatively large fraction of the work being done. If you migrate as much as possible into WASM and treat JS as the foreign side rather than WASM, you will tend to find that there’s much less serialisation/deserialisation overhead in the performance-sensitive parts, because the data they needed was on the WASM side from the start, rather than having to be copied in from the JS side. (This is, of course, a simplifying generalisation.) A somewhat more conservative strategy is to still treat JS as the native side as WASM as foreign, but expand the WASM as far as necessary to reach a point where very little data interchange will be needed. What that is may vary enormously, and such a boundary doesn’t always exist.

> You’re still missing much the point of the article: WASM isn’t for the browser only. WASI, for example, is a full environment you can run stuff in without any such interoperability cost.

Of course, but we are not arguing about the point of the article, I'm contesting the exact claim that "WebAssembly is almost always faster than JavaScript". Admittedly, not because it's such a big mistake on the author's part, but because I'm a bit irate with the usual flow of discussions about WebAssembly here on HN that take this claim for granted and regurgitate it incessantly. This is not the case for the mentioned reasons: data copying overhead and JS itself being compiled by JIT resulting in pretty performant code if well-optimized. Also, the comparison to JS only makes sense when we are talking about running both in the JS engine, not against a dedicated WASM runtime, otherwise it would be tantamount to arguing that Java is not faster than JS.

By the way, if someone really wants to dig into the issue I recommend an article from one of the V8 authors where he dissects one such WASN success story: https://mrale.ph/blog/2018/02/03/maybe-you-dont-need-rust-to...

I think part of the pushback you're getting here is that you're contesting "WebAssembly is almost always faster than JavaScript" (which IMO is correct and appropriately couched) with "WASM + JS can be slower than just JS" (which is also correct), but the way you're communicating it comes across as "WASM is just slower than JS" (that's obviously not literally what you're saying, but that's how it's coming across).

If we're going to be pedantic and nit-picky about claims, please use more precise counterclaims. It only takes a few extra words to clearly state you're talking about WASM + JS, which is an important distinction since many† people here are interested in WASM-only, without the JS (with the alternative in their mind being JS-only, without the WASM).

†In the spirit of pedantry, I mean many. Not all. Maybe not even a majority. But reasonably many.

> I'm a bit irate with the usual flow of discussions about WebAssembly here on HN that take this claim for granted and regurgitate it incessantly.

It is still more honest to regurgitate the claim that Wasm is faster than JS than to try and argue that "JS is about 10x faster than wasm in simple linear regression."

It's quite obvious and simple: by reducing 'context switches' between JS and WASM. E.g. don't call from JS into WASM for a simple computation, but instead batch thousands of computations into a single call. Also works the other way around. When calling from WASM into web APIs, think of those calls as expensive 'syscalls' which need to be minimized.
Consider a browser where the DOM is implemented in Rust and exposed to Javascript via some form of FFI.

The same DOM API could be exposed directly to WASM via WASI-like calls, without going through Javascript.

This is already being addressed in thread but I’d like to share some “it depends” thoughts based on experience from recent experiments with WASM and N-API. As others here and elsewhere have said, it depends on:

- how compute-heavy your workload is

- how long it runs

- how much you need to pass data back and forth

That last point is hard to overstate. It’s such an overhead that “notoriously slow” (however outdated the notoriety) JS operations like structured clone run circles around highly optimized native-bridge/WASM data transport solutions.

It’s such an overhead that—for short bursty interop around values that can’t meaningfully benefit from being passed through—you have to write JS that might as well be native integer wrangling but has to be written in JS to reduce the cross-talk. That covers pretty much any workload that involves passing around JS functions as values, or preserving inheritance chains, or dynamic usage of functions generally.

I’m excited about WASM and other JS<->compiled interop, it has a bright future. But unless and until JS as a standard and JS VMs at runtime specifically provide ways to optimize crossing that boundary, the vast majority of already hard to optimize JS use cases are either better solved natively in general with minimal interop (where WASM et al will shine) or better solved by optimizing the JS implementation where the use case necessarily deals with JS functions.

I actually tried wasm a couple of months ago with Golang in the browser, and was very disappointed.

It is indeed way slower that JS (and yes, I tried to care about performance and understand what was going on, removed any data exchange with the browser and even ran the tests without any dev tools opened - just in case).

Not even mentioning the fact that to use it, you need to include and hardcode a dubious JS file that does not even integrate properly with npm or any build system. And that the standard wasm way to exchange variables and events is not supported (instead you are forced to use some automagic and slow DOM bindings).

The performance with alternative compilers (tinygo) was a bit better on the performance side, but the integration was still disappointing and unsatisfying.

Levenstein distance with WASM is 40% faster in the benchmarks on the linked medium article.

WASM (145,086 ops/sec)

JavaScript (102,775 ops/sec)

https://medium.com/netscape/javascript-c-modern-ways-to-use-...

And that's another thing about JavaScript engines--they evolve and usually result in better performance. The article is written in 2017 and the results are from Node.js of the time, meanwhile the results in the repository are from the last year.
Can confirm, I ran the benchmark in that repo and rather than JS being 30% faster in Levenstein distance it was ~10% slower but both had improved relative to the native score.
Is it a naive recursive implementation or the matrix formulation?
Only because this is a bad demo. Do the whole thing in WASM without marshalling and it'll smoke JS.
I did some tests on my side (Rust WASM, quantum computing numerics) and was surprised that the WASM code is only 1-2x slower than native, depending on the browser. Since this code is at least NumPy-fast (a lot of optimizations purely for quantum operations), I don't believe that JS can do it 10x faster.

Your Benchmarks May Vary.