3 ms·
It's hard to beat JavaScript because the VMs are amazing. If you know a few tricks, like how to let the VM know you want integer math [1], you can get performan
by modeless 4y ago
It's hard to beat JavaScript because the VMs are amazing. If you know a few tricks, like how to let the VM know you want integer math [1], you can get performance that's not too far off from native C in many cases. If you have a JavaScript application with a few hot functions that are slow, optimizing the JavaScript usually makes more sense than reaching for WASM.
[1] https://james.darpinian.com/blog/integer-math-in-javascript https://james.darpinian.com/blog/integer-math-in-javascript
- solardev 4y ago> If you know a few tricks, like how to let the VM know you want integer math [1] > [1] Add | 0 after every math operation to get a 32-bit signed integer result, and >>> 0 for a 32-bit unsigned integer result. That's definitely gonna cause a few "wtf?" moments for everyone else on your team, lol
- modeless 4y agoYeah, you shouldn't do it all over the place prophylactically. It's a technique for optimizing functions that are performance critical. Although I find `| 0` surprisingly well known these days. I sometimes use it in places where I want a cast to integer.
- zinekeller 4y agoMost of those optimizations stems from Mozilla's asm.js (http://asmjs.org/ http://asmjs.org/), which specified those as an explicit signal. Note that if you're still supporting IE (commiserations and I wish you that you could decommission it ASAP) this will slow down you code (only in IE of course) instead of speeding it up.
- josephg 4y agoIn my experience the place wasm really shines is in implementing custom data structures. A wasm b-tree, skip list, rope, etc seems to outperform the equivalent javascript code by many times. Edit: I just whipped up a real benchmark to test this, replaying some text editing traces[1]. Replaying the automerge-perf editing trace in javascript naively takes 610ms. Using a javascript based skip list it takes 77ms[2]. In native rust, with a rust port of the same skip list code I can process the same editing trace in 6ms[3]. Or 20ms when that rust code is compiled to wasm. So in this case, we're seeing about a 4x performance improvement using wasm, or 13x performance improvement using native code. [1] https://github.com/josephg/crdt-benchmarks https://github.com/josephg/crdt-benchmarks [2] This code https://gist.github.com/josephg/bcb2e74e52dc9c4651249fdffc48d1cf https://gist.github.com/josephg/bcb2e74e52dc9c4651249fdffc48... using this library: https://www.npmjs.com/package/jumprope https://www.npmjs.com/package/jumprope [3] https://crates.io/crates/jumprope https://crates.io/crates/jumprope
- modeless 4y agoThis makes sense to me; graphs made of JavaScript objects are not going to be as fast as C, although I think knowledge of how the JIT works can still help you get a lot closer than 10x (e.g. ensuring everything is monomorphic). Now if you implemented a b-tree completely inside of a typed array, instead of using JavaScript objects as the nodes, that would be how you would approach C speeds. But if you need a lot of custom data structures, WASM is probably a better choice at that point.
- josephg 4y agoAbout a decade ago I hand-ported the chipmunk2d physics engine to javascript. After porting it, I tried about 30 different things trying to make the code run faster. Some things I tried made it faster. Some made it slower. The most performance-critical section is the "arbiter applyImpulse" physics code[2], which is all math. I tried putting everything in as big TypedArray to avoid all the object lookups, but performance got slightly worse, not better. I still have no idea why. I think the reason is that the optimizer couldn't optimize the typedarray lookups at the time. Not in the same way it can optimize math on normal objects. Maybe v8 is more clever now? I dunno! The biggest performance win I got was from inlining vector fields. Chipmunk heavily uses {x,y} 2d vectors. Lots of objects looked like this: {pos: {x, y}, velocity: {x, y}, ...}. Flattening everything to this {posx, posy, velocityx, velocityy, ...} made the code uglier. But it caused a massive performance improvement because it reduced the number of objects allocated on the heap. (This one change reduced the number of heap allocations by about 70% from memory, and it caused a double-digit performance improvement overall.) As I see it, Javascript will always be much slower than other languages for complex data structures because everything is stored on the heap. [1] https://github.com/josephg/chipmunk-js https://github.com/josephg/chipmunk-js [2] https://github.com/josephg/Chipmunk-js/blob/ec447072458f40093c62c5cbfb71f8ca4f58975e/lib/cpArbiter.js#L361-L419 https://github.com/josephg/Chipmunk-js/blob/ec447072458f4009...
- modeless 4y ago10 years ago was around the time asm.js was just getting started, and that's what drove a lot of these optimizations. I think V8 is a lot more clever now. And the other browsers have largely caught up as well (or even surpassed V8 in some cases). And you can now safely ignore IE :)
- dahfizz 4y ago> you can get performance that's not too far off from native C in many cases. Source? Every benchmark I've seen that has JS comparable / faster than C uses an extremely suboptimal C implementation.