Live data from Hacker News

A first look at WebAssembly performance

stefankrause.net

121–130 of 130 posts

Re: A first look at WebAssembly performance

#121

Earlier quoted context omitted.

Integers are hardly the worry. Any custom types the user makes are the problem.

Integers are the worry. the JIT being able to say "This here is an int, which means that this function takes an in and returns an int always, i'm going to compile it that way" means that now that function is "C-Speed". If your program were filled with functions similar to that where the compiler is easily able to optimize the shit out of it, then it will run suprisingly close to "C-Speed". Custom types (which I took…

I don't think you are getting it. Here is a custom type in C#:

  public class CustomType
  {
      public int A;
      public int B;
      public CustomType2 C;
  }
At runtime this will mean any instance of this type is 32bit * 3 = 96 bits, plus the size of any metadata. Any code that accesses an instance member such as 'customType.B' will simply need to deref the address of customType, then add 32bits, and then deref the address of 'B' to get straight to the value.

Now let's do the same in JS:

  var list = [];
  for (i = 0; i 
Perfectly normal dynamic JS code, but now at runtime the JS engine has no idea what 'customType' could possibly be, until is has attempted some sort of static analysis at runtime to figure out the fields. Additionally 'C' is optional, and whereas in C# that mean it may be null, in JS that means it could be undefined too.

There is also no guarantee that 'customType' is left as is and more fields aren't added to it later. All this leads to having to use dictionaries to store the information, which then require hash lookups every time you access a member. Fast, but not remotely near as fast as the C# runtime who has already mapped everything to an address.

Re: A first look at WebAssembly performance

#122
post #59

I really want to like web assembly, but every time I read about it I SMH. We already have a bunch of great runtimes, compilers, and opcodes. I hate to see the effort duplicated yet again. Or maybe I'm missing something obvious?

> We already have a bunch of great runtimes, compilers, and opcodes. I'm confused. Are you suggesting we, for example, use the JVM for this instead? WASM is being designed specifically with the web in mind, and has a lot of design goals which just weren't a concern for other runtimes. See: http://webassembly.org/docs/high-level-goals/

And Java was designed with the web in mind too. You could access the DOM from applets back in the day, it's not fundamentally so different.

I feel like "designed for the web" doesn't really mean much when you zoom out. When I look at that bytecode set, it is less strongly typed and has more opcodes than JVM bytecode, but otherwise is rather comparable. It isn't based on any actually existing hardware instruction set so it must be interpreted or JIT compiled. It has explicit opcodes for things like popcnt and clz instead of relying on compiler intrinsics, but that's not anything that matters when you need a translation layer anyway. It has bytecodes that do static and virtual method dispatch, just like JVM bytecode.

The main difference seems to be that it doesn't provide GC or locks or other things that higher level languages need.

As far as I can tell, the browser community insists on constantly reinventing the wheel because of a kind of NIH syndrome often justified by security, but how robust is that justification? You can't have regular sockets, you need "WebSockets", although the web has permissioned APIs in many other areas. You can't use any existing VM and bytecode set like the JVM because they're "insecure", although both Firefox and Chrome are constantly patching sandbox escapes too: it just comes with the space. However they're "web" and thus excused, Microsoft/Java aren't "web" and thus guilty. Ditto for Flash. You can't have threads like C#/Java have because Javascript engines happen not to be thread safe, instead you get "Web Workers" which are really just the Visual Basic 6 concurrency model reborn without the benefit of DCOM to assist with the messaging, but now it's "Web" it's hip and cool.

Maybe I'm just the grumpy old man yelling at the clouds, but browser tech is stuck in a hamster wheel where they insist on reinventing things that were already working fine elsewhere in the industry.

Re: A first look at WebAssembly performance

#123

Earlier quoted context omitted.

Floating point errors accumulate quite quickly when dt is small it could be a smoothing function.

Forgive me a boast about a nbody simulation ive been developing: I got the details 60 planets and moons etc. from Nasas JPL server and put them into it. Running at a timestep of 30 minutes or hours (virtual time) for a year, the Earth ends up within a moons orbit of where JPL says its supposed to go. I think the innaccuracy is due to limitation of javascripts 64bit float (rather than, possible relativistic effect). N…

Nice. Agreed on errors with big dt. For me it is usually when shortening the time step to try to minimize for these that floating point errors start to come in.

Now chuck in some velocity dependent forces and start screaming (that's what I've found with physical simulations anyway).

Re: A first look at WebAssembly performance

#124
post #69

Earlier quoted context omitted.

Well not exactly, but I feel like the JVM, LLVM, parrot, CLR, or any one of those that have well defined opcodes could be leveraged instead of producing something entirely new. There's quite a bit of investment in those projects... Does that make more sense what I was trying to say?

The reason for not using LLVM bitcode or ASM.js is already covered in detail here https://github.com/WebAssembly/design/blob/master/FAQ.md I am unsure how JVM or CLR are relevant. WebAssembly is not a virtual machine byte code (and neither is LLVM, despite the name). As the name "WebAssembly" suggests, it is like an assembly language level target for "the web" (more precisely, for JavaScript interpreters found in web…

I wrote more on this above, so I won't repeat myself in this comment, but yes WebAssembly is a "virtual machine byte code". It is literally a bytecode language that doesn't target physical machines. It bears no resemblence to x86 or ARM so it has to be JIT compiled or interpreted.

Saying it doesn't target a VM because it targets "the web" is meaningless.

Re: A first look at WebAssembly performance

#125

Earlier quoted context omitted.

Integers are the worry. the JIT being able to say "This here is an int, which means that this function takes an in and returns an int always, i'm going to compile it that way" means that now that function is "C-Speed". If your program were filled with functions similar to that where the compiler is easily able to optimize the shit out of it, then it will run suprisingly close to "C-Speed". Custom types (which I took…

I don't think you are getting it. Here is a custom type in C#: public class CustomType { public int A; public int B; public CustomType2 C; } At runtime this will mean any instance of this type is 32bit * 3 = 96 bits, plus the size of any metadata. Any code that accesses an instance member such as 'customType.B' will simply need to deref the address of customType, then add 32bits, and then deref the address of 'B' to…

That's almost the exact scenario I am talking about.

Your custom type there is perfect in JS. The JIT will VERY quickly determine that i is always an integer (actually before the code is first run it will have figured it out), and will "unbox" that to treat it as such (and not a JS "number" type). Objects in JS have a "hidden class" where they can be stamped out literally just like the C# example, so the JIT will be working with the exact same thing. A memory-mapped custom type.

Read up on "Hidden classes" [0] which can give you some insight into how it works. Basically as long as you treat a JS object like you'd treat that C# "custom type" (don't dynamically add or remove properties, stick to one type per property), it will instantly treat it identically to how C# would treat it until it changes (at which point it bails out and tries again, and if that happens too much, it will then default back to fully-dynamic).

But even if that weren't the case, you could still write your own data storage in JS that works like that. You could do something like this:

    const customType = new Uint32Array(3)
    const A = customType[0]
    const B = customType[1]
    const C = customType[2]
That storage will not only be typed, but will also have LESS overhead than the C# example, at the expense of clarity (after all, that's basically a C array there). This is basically how asm.js works, and what the code looks like when you compile C code into JS. Obviously you don't want to do that in most cases, but if the JS engine is your bottleneck and your data storage is causing slowness, then it might help.

JITs have come a LONG way in the past 5-10 years. It's pretty incredible what they can do, and it's actually not that hard any more to make smaller functions that can run at C speeds in V8 and SpiderMonkey.

[0] https://github.com/v8/v8/wiki/Design%20Elements

Re: A first look at WebAssembly performance

#126
post #110

Earlier quoted context omitted.

That's not really true, as JS engines will already compile things with the assumption that the types won't change and "bail out" if they do. So if you can "hint" to the JIT that a variable is an integer, and it will stay an integer, then it will not only "unbox" it and treat it as an integer, it will compile the code very similar to how a static language would. In asm.js, this is done by using little "tricks" of JS t…

> That's not really true, as JS engines will already compile things with the assumption that the types won't change and "bail out" if they do. Which makes for some great benchmarks but poor real world results.

It actually works suprisingly well.

After all, no JS engine out there would really tune their engines to benefit benchmarks at the expense of real-world performance.

Even with all the dynamic ability that something like JS gives you, most devs still create an object to store stuff, then don't change it. That means that an aggressive policy of "compile it as it is, and bail if it changes" ends up working much more often than it doesn't.

And in the cases where it doesn't, falling back to the "compile it dynamically" isn't going to be any slower than if they did that first, so it's basically a free optimization (as long as the compilation doesn't take that long).

Re: A first look at WebAssembly performance

#127

Earlier quoted context omitted.

Forgive me a boast about a nbody simulation ive been developing: I got the details 60 planets and moons etc. from Nasas JPL server and put them into it. Running at a timestep of 30 minutes or hours (virtual time) for a year, the Earth ends up within a moons orbit of where JPL says its supposed to go. I think the innaccuracy is due to limitation of javascripts 64bit float (rather than, possible relativistic effect). N…

Nice. Agreed on errors with big dt. For me it is usually when shortening the time step to try to minimize for these that floating point errors start to come in. Now chuck in some velocity dependent forces and start screaming (that's what I've found with physical simulations anyway).

One trick which improves stability heaps is 'tempering' the data to fit the dt. Weve got the verlet integration thing where they say the velocities should be half a step behind before updating forces. I find they should also be reduced a little as objects are cutting through the analog curve of their orbits in the timestep - as a hypotenuse instead of an arc. When I tempered the data like this orbits were all much stabilised. Its required for objects if they are added to the model later too. To have their precise velocities measured while tempered they also need 'de-tempered' to tell where they are going precisely. Just calculate their acceleration move them half step and adjust for ratio of hypot/curve.

"velocity dependent forces" I have been wondering how to implement a sort of quasi-electromagnetic force without the big expense of maintaining a magnetic field. I find the electro-magnetic force mind blowing compared to newtonian gravity. Like charges seem to be able to attract when travelling together, this would seem to produce patterns and structure more readily than gravitation.

Re: A first look at WebAssembly performance

#128
post #69

Earlier quoted context omitted.

The reason for not using LLVM bitcode or ASM.js is already covered in detail here https://github.com/WebAssembly/design/blob/master/FAQ.md I am unsure how JVM or CLR are relevant. WebAssembly is not a virtual machine byte code (and neither is LLVM, despite the name). As the name "WebAssembly" suggests, it is like an assembly language level target for "the web" (more precisely, for JavaScript interpreters found in web…

I wrote more on this above, so I won't repeat myself in this comment, but yes WebAssembly is a "virtual machine byte code". It is literally a bytecode language that doesn't target physical machines. It bears no resemblence to x86 or ARM so it has to be JIT compiled or interpreted. Saying it doesn't target a VM because it targets "the web" is meaningless.

Fair enough. You are correct, WebAssembly is a bytecode for the underlying machinery of current ECMAScript/JavaScript engines. I think you raise a very good question, why did the WebAssembly committee decide to implement their own stack machine bytecode instead of re-using an existing bytecode like JVM or CLI (which, interestingly, is an ECMA standard)? It's troubling. The closest explanation I could find is:

"Why not a fully-general stack machine?

The WebAssembly stack machine is restricted to structured control flow and structured use of the stack. This greatly simplifies one-pass verification, avoiding a fixpoint computation like that of other stack machines such as the Java Virtual Machine (prior to stack maps). This also simplifies compilation and manipulation of WebAssembly code by other tools. Further generalization of the WebAssembly stack machine is planned post-MVP, such as the addition of multiple return values from control flow constructs and function calls." [1]

[1] http://webassembly.org/docs/rationale/

Re: A first look at WebAssembly performance

#129
post #69

Earlier quoted context omitted.

The reason for not using LLVM bitcode or ASM.js is already covered in detail here https://github.com/WebAssembly/design/blob/master/FAQ.md I am unsure how JVM or CLR are relevant. WebAssembly is not a virtual machine byte code (and neither is LLVM, despite the name). As the name "WebAssembly" suggests, it is like an assembly language level target for "the web" (more precisely, for JavaScript interpreters found in web…

I wrote more on this above, so I won't repeat myself in this comment, but yes WebAssembly is a "virtual machine byte code". It is literally a bytecode language that doesn't target physical machines. It bears no resemblence to x86 or ARM so it has to be JIT compiled or interpreted. Saying it doesn't target a VM because it targets "the web" is meaningless.

I found the relevant discussion on this: https://github.com/WebAssembly/design/issues/960

Re: A first look at WebAssembly performance

#130

I think there is no js version implemented which accesses the bodies parameters like this: x = body.x[body_index] I expect this should be much faster than accessing them like this: x = body.[body_index].x Because the latter requires pointer-from-property calculation for every single values access (which must be somehow optimised) The former just requires pointer-from-property calculation for every array (not element)…

> Because the latter requires pointer-from-property calculation for every single values access (which must be somehow optimised) Global value numbering (GVN) should be trivially able to do this.

Perhaps when things are very simple, but we can end up with thousands of objects each with dozens of optional properties. With the fields declared as arrays only each array needs a GVN.
Post reply on HN