Asm.js: The JavaScript Compile Target
ejohn.org
ejohn.org
Modern CPUs tend to be able to adjust their clock speed in response to load, and I think there are even some shipping processors that can switch off entire cores. GPUs are the same way. In practice, running an asm.js version of some normal JS might load your CPU more evenly and use more of its resources, but it's going to run so much faster that you should come out ahead.
The power draw (measured at the wall by my UPS) from my current desktop PC can bounce from 100W to 400W at the drop of a hat (from the GPU and CPU both clocking up, respectively). So, in that case, code that 'runs faster' (by using the GPU) could potentially actually use more power. But I bet in practice most GPGPU applications end up using less power in total too since they run so much faster.
I think ASM is a great idea for "hacking", but the thing that doesn't make a lot of sense to me, is that you're usually only going to bother compiling to ASM for things which need the performance. The idea that they'll "still work" in non-optimized browsers doesn't seem too convincing -- games would probably be unplayable, and you'd see messages saying "This game only supports Firefox" etc.
And I don't see there being that many things written in C, etc., that one would want to port to the web, that aren't particularly processor-intensive.
Presumably PNaCl would be close to native code speed, a big improvement over ASM. And it seems like what's needed is cross-platform fast execution -- not backwards compatibility with JavaScript that will still run, but run much more slowly.
But nevertheless, it's super-interesting watching what's going on with ASM.
The BananaBread demo ran very smoothly at fullscreen, 1920x1200, on Firefox 19. I was very impressed. I'm running on old hardware: a 3GHz Core2 Duo and NVidia Quadro 1700. I know it's not a full game, but it's awesome anyway.
It runs OK without asm.js, but it's liquid smooth with it.
What else do you need?
They probably couldn't have done more even if they wanted to, though, since asm.js or not, browsers can see only use the OpenGL ES 2.0-based WebGL API's. That's why I'm hoping the OpenGL ES 3.0-based (or better) WebGL will arrive very soon, although I haven't even heard if the Khronos group is working on it, so it's possibly they haven't even started yet.
The art assets of the Citadel demo are I believe the same as in the Flash demo, which were optimized for a more mobile-friendly and touch-friendly environment.
However we also showed a full Unreal Tournament demo running, as I mentioned in another comment, both at our GDC presentation and in the booth where people could play it. That's a full desktop level.
I disagree. Granted, I'm an unusual case as I'm a compiler developer for a living, but my use of Asm.js would primarily be to write compilers for interesting or research programming languages to JS (granted, so I don't have to write JS). In this case the primary benefit isn't performance, it's having a reliable compile target that I can do profiling on. You wouldn't believe how important it is to have a stable (and well-specified) target language when you're writing a compiler.
Care to explain?
What stops language X from targeting asm.js and still having higher-level parts in plain JS to deal with the DOM?
The issue is that asm.js doesn't provide the full JavaScript & DOM API. Calls to native JavaScript functions go through a foreign function interface. The natural design in this case is just as you describe: a self-contained core for high-performance calculations called by a shell of plain JavaScript that can interface with the rest of the world. Similar two-layer patterns are used for NaCl Chrome apps, or games using Lua to script a C++ engine.
My original comment was written in the hope that existing language-to-JavaScript compilers could be modified to target asm.js, automatically gaining its performance boost for all future and current projects using, say, GWT. But existing projects aren't written with the two-layer pattern needed to target asm.js effectively. Perhaps the best you could do would be to run every function call that isn't in the module or asm.js stdlib through the FFI. That may not be worthwhile.
(Anyone can feel free to correct me if I'm totally off on something. This isn't exactly my specialty.)
People are only recently starting to talk about PNaCl because it's the only alternative to asm.js, and for some reason some people have such strong negative reactions to the idea of a highly performant language that isn't a bytecode that they'll support a defunct Google experiment before a low-level JavaScript subset.
That's a big if.
With NaCl one has to provide multiple EXEs for each platform that one wants to support be it ARM, x86 or x64.
PNaCl was designed to solve the multiple EXEs problem by just providing one in LLVM bytecode to be jitted runtime.
So websites written today wont be viewable/runnable on architectures created tomorrow unless someone goes back, updates the NaCl tooling, gets the updated NaCl tooling to the original author and convinces the original author to fix his broken, platform-dependent website.
Excuse me if I say that sounds like a bunch of horseshit. If this had been invented (and embraced) before the advent of mobile-devices, half the internet would be unusable on smart-phones and tablets now.
Why on earth would we ant to create that sort of problems for the future? Websites tend to stick around, maintained or not, and new things will always emerge.
NaCl is a bad idea for any cross-platform medium and the internet in particular. End of story. The only people rallying NaCl are Google-fanboys who can't even see past their Google Chrome browser when testing regular websites.
I can't wait for this non-standard monstrosity to die.
Asm.js's support should make sense for Chrome OS no?
And here's the latest Unreal Engine 4 demo. http://www.youtube.com/watch?v=dO2rM-l-vdQ
I know there are improvements on the web platform each year but I wish people would be very very cautious to say "we've achieved nearly native performance!".
To begin with, I think it's difficult to run 3D games (including Flash and Unity) on browsers because of the asset loading (and AOT compilation) time. If people must wait for seconds and even minutes to start a game, we can't do business with it. As many web developers says, immediate page loading is must. I'm personally running Flash and HTML5 games and I observe 80% people leave just in a few seconds loading.
To solve this issue, game stores (PS3, Xbox 360, App Store, Google Play, Steam and many others) are using the "reserve download and play it later" model. After all, traditional install apps are not that bad architecture...
This is actually incorrect. While ActionScript is actually far slower than Javascript, the VM is actually really good at running C code compiled to it. Providing about a 30x speed up over Actionscript.
The bit comparing Asm.js to Google's Native Client is interesting.
http://badassjs.com/post/17218459521/webm-and-webp-hand-port...
Presumably either Node would have to switch to Mozilla's Spidermonkey or V8 would have to implement full performance support for Asm.js.
And that may just be worth getting excited for.
Right now, I have a few workers managed in node, that run compiled code. It works pretty well, but having more of that as modules directly available in Node, with nearly the same performance would be really compelling.
Not needing to compile certain NodeJS modules is what I'd find really compelling.
Javascript is dynamically typed, and comes with eval, so that you can never really be sure what type x is (and therefore what binary code the processor should run), so you have to check and make allowances, which cost performance.
In C you always know the type of a variable so you can match + to either a float, double or integer addition at compiler time, in Javascript you have to (dynamically) check the type of both, possibly convert one or more and then either perform a float or integer addition or string concatenation.
I C you always know the size of all structs, and they can't change so allocating them is cheap and fast, whereas you have to create a hash table in Javascript and access the objects that way (which is a lot more expensive, and potentially you have to walk the chain of several objects due to usage of the prototype property).
The same thing goes for Arrays, in C they are a pointer, in Javascript they are far more complicated.
That's not entirely true. A lot of 8-bit microcontrollers, for example, do not have hardware support for arithmetic on 32-bit integers; nevertheless, C code using int32_t or uint32_t will compile just fine for those processors. This goes double for floats, if you'll pardon the completely unintentional pun.
It's a matter of degree, of course. C is still a lot closer to the metal than JS.
"So much slower"?
Perhaps you haven't been around this web scene for more than 5-6 years. JS is so much faster now it's not even funny. JS used to be in the "slow as molasses" category pre-2005.
Now it's like 10 times faster than Python for pure algorithmic code.
If Javascript were fast enough, we wouldn't be looking for "4-10x" improvements with ASM.js and NaCL. Are we close to the limit of what can be done to improve Javascript performance? Perhaps another 2x?
Sure, but "understanding" is different than appreciating.
After all, a JIT is not some magic wand. If a language is very dynamic, memory hungry, less prone to optimizations, etc, JIT code will still be slower than C/C++. Plus, not everything in a JS program is getting JITed.
>Are we close to the limit of what can be done to improve Javascript performance?
With Javascript as it is, yes. Maybe some 2x at best. If we add type hints, contiguous storage, and frozen object guarantees though (some of which ES6 has, IIRC) that can be improved further.
http://en.wikipedia.org/wiki/Escape_analysis
[Update] Adding this great read about Java vs C++ performance:
http://www.azulsystems.com/blog/cliff/2009-09-06-java-vs-c-p...
I've never seen any actual JIT being faster than compiled C/C++/Ada/Fortran, except for isolated contrived benchmarks.
ASM.js code is a subset of javascript. The point is that they have defined a subset of javascript and a set of rules that, while it will run in a normal javascript engine, clearly indicates to the engine that if it supports it, it can do additional optimizations that could break things for "normal" javascript.
E.g. javascript doesn't have proper integers. Doing everything with floats is a performance killer, and for the JS engines to figure out when they can safely substitute integers is extremely hard without hints, so ASM.js specifies how to "fake" integers in a way that ensures the code will still work in standard JS engines (by using bitwise operators to coerce the value to integer values all over the place) while allowing an engine that knows about the ASM.js conventions to optimize the code further.
Nothing stops you from writing javascript code manually this way in the first place (apart from tedium), though it is admittedly a "workaround" to features in javascript that are incredibly hard to optimize well that would've been handled cleaner by language modifications.
The advantage of ASM.js is that the code still works in other JS engines, while if they'd started adding actual extensions to the language we'd be in portability hell for years.
- I would have expected him to have tried it. There's no evidence in the post that he even fired up firefox nightly and ran even a simple test. The performance graph is straight out of asm.js marketing material
- In discussing chrome's performance, he just writes "A 4-10x performance difference is substantial" without explaining why chrome's performance suffers so much relative to firefox without asm.js (take the skinning demo. Why is chrome significantly worse than firefox?) This is a point that many have discussed, including some here in various posts about asm.js
- Certain sentences seem artificial. If you've read other posts by him, does "It is interesting to see such a large performance chasm appearing between Asm.js and the current engines in Firefox and Chrome. A 4-10x performance difference is substantial (this is in the realm of comparing these browsers to the performance of IE 6). Interestingly even with this performance difference many of these Asm.js demos are still usable on Chrome and Firefox, which is a good indicator for the current state of JavaScript engines. That being said their performance is simply not as good as the performance offered by a browser that is capable of optimizing Asm.js code." sound like something he would write? At all?
- I did not run performance benchmarks on my system because Asm.js does not yet support OS X (which is my primary OS). I fully intend to run some tests, and hopefully make some of my own, when that time comes. In the meantime it's not really beneficial for me to just re-run the same benchmarks that others have run on those platforms.
- I thought this was obvious: Chrome and normal Firefox are so much slower because they do not explicitly optimize the Asm.js code path.
- That's complete nonsense. I can't believe I have to say this but yes, I wrote those sentences.
I think the parent was asking for an explanation for why Chrome does so much worse than the non-asm.js Firefox. Which I guess is kind of a weird question given that Chrome beats non-asm.js FF in one of the three benchmarks, and is roughly tied with it in another.
The big difference is between Firefox+asm.js and both Firefox and Chrome.
"I did not run performance benchmarks on my system because Asm.js does not yet support OS X (which is my primary OS)."
Given the relative percentage of web developers who use OSX (which is certainly non-trivial), wouldn't you think it would have been wise to state that?
But I guess the more interesting question is: did you try it on a system that firefox nightly+asm.js runs on? If so, can you describe that process? Did you try writing some code by hand or try taking a dummy program and run it through emscripten?
Taking a step back, it just seems really strange (and certainly many others, if this involved some other company like microsoft or google) that you would talk about performance without trying it.
The better question is if it's the right approach, which is what mraleph has been arguing, and it's a much more appropriate argument.
Not everything is obvious here, actually.
If we are talking about vertex skinning benchmark where the difference between asm.js performance and Chrome's performance looks most "impressive" then a lot of that difference is caused by various bugs and limitations in V8's optimizing compiler: https://code.google.com/p/v8/issues/detail?id=2223
The same issues can easily affect other JavaScript code.
I personally strongly believe that one does not need to "explicitly optimize Asm.js code path" in the meaning "have a separate compilation pipeline for Asm.js code" to make asm.js code faster. All that one needs is to fix things that were neglected during JS VMs evolution.
I also largely agree with Jason's comment on that post: http://mrale.ph/blog/2013/03/28/why-asmjs-bothers-me.html#co...
I see no reason why these efforts can't run in parallel - as certain optimizations are needed to improve execution performance standardize them and expose them to user-written JavaScript.
I'll say that I would be totally happy if Asm.js was nothing more than a line drawn in the sand that all the browser vendors then aspired to match with normal JavaScript. Knowing what is theoretically possible in a browser is a huge motivator (as was seen in the last browser JS performance war of 2008/2009).
If you have some reasons that aren't technical, I can understand that. Otherwise, your insistence on ignoring "asm.js" can't be rationalized.
I am saying that if JS VMs already do a lot of optimizations which are not going to disappear anywhere even with "use asm" because they benefit normal JavaScript code. Now if JS VMs solve a range of known issues in implemented optimizations, fix known bugs, lift known limitations and then additionally implement certain optimizations then this would greatly improve performance of normal JavaScript code including its subset used by asm.js.
I don't understand desire to have another compilation pipeline on the side, if everything that is needed can be implemented in the main compilation pipeline and benefit JavaScript as whole, without restraining users to a strongly typed subset. This also leads to an unnecessary duplication.
I also think that if you think that restraining is essential you should push for another execution platform (e.g. statically typed bytecode or language). That would be much more honest towards language users and language evolution as whole.
I've never seen anybody proving that. Asm.js guys however proved that using the declaration that specifies the very fixed assertions, it's simple to achieve significant benefits. Once again, ignoring the precise and explicit information which otherwise is too demanding to be deduced simply doesn't have sense unless you're motivated by some non-technical reasons. So why you resist something that's technically better?
Nobody says that you need "a lot" of new code, you have only to introduce the implementation which uses the fixed assertions promised by the "asm.js" declaration. Note that in the approach you propose not only that same functionality has to be implemented but much much more code that would be just there to try to deduce what's otherwise obvious from that one single line.
So engine developers should implement asm.js support now, it's independent of whatever they'd want to introduce for any other optimizations. This simple approach is already there and it's proved it's effective.
Well, C compilers proved that long ago, nothing novel here. It is obviously easier to compile statically typed languages to efficient code. Especially if your language is limited to arithmetic and memory operations and your input source code is actually output of a sophisticated optimizing compiler that performs high-level optimizations for you.
> which otherwise is too demanding to be deduced
Let me repeat: JS engines already spend time on, as you say, deducing all kinds of information. This is not going anywhere, unless you are willing to make all JavaScript slower.
Because it is not going anywhere I am essentially arguing that it should be fixed to correctly infer more useful information than it does right now. Are you suggesting that VMs should just stay essentially unfixed?
There is hardly any duplication. All the optimizing machinery is being reused entirely. asm.js code is fast because the existing IonMonkey code generation makes it fast.
The only new part is something - the OdinMonkey module - that type checks asm.js code, and if it validates, then it feeds that into the existing IonMonkey compiler, with the types that were discovered during type checking.
There will be a clone of JavaScript parser. IR building is already duplicated as well.
I am aware that middle-end/back-end are shared, though there are some IR instructions are that specific for asm.js.
But I agree: duplication might be the wrong word here.
Actually, if they turned evil they'd employ someone better at it. I'm kind of convinced you're just trolling.
My comments are pretty short. If you can't be bothered to parse them, why respond?
This is just a JS enthusiast (understatement of the year, perhaps) discussing a JS topic.
If it were a paid service, perhaps not. But, it's not....the blog is a free service. Not trying to be rude, but the adage applies: you can 'take it or leave it'.
I'm not sure why you feel so entitled that he seemingly owes you something.
If you feel that it's inappropriate for HN, then flag it.