Status: New
Owner: ----

New issue 3650 by [email protected]: for x in y de-optimizations
https://code.google.com/p/v8/issues/detail?id=3650

Although it is known that `for (x in y) { }` will de-opt if `y` isn't safely enumerable, it is still a very common perf issue to see in the wild and typically the most egregious runtime induced slowdowns.

Alternatives exist, but unfortunately each alternative presents issues.

leaks low level ideas into a developers work-flow
Object.keys is limited to own Properties
Object.keys has stricter input requirements (x in y works with null, undefined, numbers, NaN etc)
Object.keys allocates an intermediate array (can't bailout early)
means additional guards must exist. example: emberjs/ember.js#9386
writing your own helper that returns all properties isn't aware of mutations during enumeration your own helper function that returns all properties is again susceptible to the inlining bailout poisoning
each above method has different performance implications
more....?

An example:

For example in chance.js, having the knowledge of branching to the "safe" enumeration mechanism for the given object (Object.keys for an object, and a for loop for an array) resulted in 28x performance improvement. victorquinn/chancejs#88

Also, as a function instance is shared (and its optimized state is as well) a library provided function such as `merge` can easily be poisoned causing application wide performance issues.

Another Example:

emberjs/ember.js#5645 in ember, I noticed it was quite common for unrelated parts of the framework to poison shared functions causing framework wide bailouts. The most common of these was related to `for (var x in y)` one such example was `Ember.merge`

given the obvious way to write merge.

function merge(a, b) {
  for (var key in b) {
    if (b.hasOwnProperty(key)) {
      a[key] = b[key];
    }
  }
  return b;
}

It took 1 slow-mode object or array `b` to cause some app wide slowdowns. This was due mostly to inlining bailouts, which often resulted in entire chunks of code being marked as not optimizable.

Knowing this, I was able to re-write Ember.merge to be resilient to such poisoning.

function merge(a, b) {
  var keys = Object.keys(b);
  var key;

  for (var i = 0, l = keys.length; i < l; i++) {
    key = keys[i];
    a[key] = b[key];
  }
  return b;
}

A  third example:
Just another set of optimizations where `for (x in y) { } ` was contributing to the performance issues.
emberjs/ember.js#5559

Conclusion:

In each example, a scenario specific solution resulted in tremendous performance improvements. These unfortunately relied on relatively deep understanding of the underlying platform and the resulting solutions had considerably more caveats and nearly where always followed up with one or more bug-fixes.

Although good performance is possible, having to know which levers to pull to align with that platforms preference is unfortunate. Even worse, making the wrong choice would very poison the larger system.

--
You received this message because this project is configured to send all issue notifications to this address.
You may adjust your notification preferences at:
https://code.google.com/hosting/settings

--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to