Chakracore: Object constructor calls are slow

Created on 1 Sep 2017  Â·  4Comments  Â·  Source: chakra-core/ChakraCore

There was a discussion going on in https://github.com/webpack/webpack/issues/5600 that wraps all references into Object () which was slow. v8 recently fixed it and I piggy-backed the test case from here that was used to demonstrate v8's behavior and verified for chakracore and the results are similar. We are slow too and will be good to optimize to get boost in webpack module.

const identity = x => x;

function callDirect(o) {
  const foo = o.foo;
  return foo(1, 2, 3);
}

function callViaCall(o) {
  return o.foo.call(undefined, 1, 2, 3);
}

function callViaObject(o) {
  return Object(o.foo)(1, 2, 3);
}

function callViaIdentity(o) {
  return identity(o.foo)(1, 2, 3);
}

var TESTS = [
    callDirect,
    callViaObject,
    callViaCall,
    callViaIdentity
];

class A { foo(x, y, z) { return x + y + z; } };
var o = new A;
var n = 1e8;

function test(fn) {
  var result;
  for (var i = 0; i < n; ++i) result = fn(o);
  return result;
}

// Warmup.
for (var j = 0; j < TESTS.length; ++j) {
  test(TESTS[j]);
}

// Measure.
for (var j = 0; j < TESTS.length; ++j) {
  var startTime = Date.now();
  test(TESTS[j]);
  console.log(TESTS[j].name + ':', (Date.now() - startTime), 'ms.');
}

Results :

E:\git\Chakra\core>node f:\temp\object.js
callDirect: 664 ms.
callViaObject: 1906 ms.
callViaCall: 329 ms.
callViaIdentity: 454 ms.

E:\git\Chakra\core>node -pe "process.versions"
{ http_parser: '2.7.0',
  node: '8.4.0',
  chakracore: '1.7.1.0',
  uv: '1.13.1',
  zlib: '1.2.11',
  ares: '1.10.1-DEV',
  modules: '57',
  nghttp2: '1.22.0',
  openssl: '1.0.2l',
  icu: '59.1',
  unicode: '9.0',
  cldr: '31.0.1',
  tz: '2017b' }
Performance

Most helpful comment

I tried playing with his code a bit:
Original:

Test | Edge | Chrome
--------------- | ----- | ---------
callDirect | 716 | 546
callViaObject | 2156 | 1152
callViaCall | 196 | 579
callViaIdentity | 302 | 521

The reason for our poor callDirect score is that warmup wasn’t sufficient for us. Running the warmup twice, we get:

Test | Edge | Chrome
--------------- | ----- | ---------
callDirect | 198 | 545
callViaObject | 2157 | 1154
callViaCall | 190 | 582
callViaIdentity | 304 | 519

I then used a switch to get rid of the polymorphic calls:

Test | Edge | Chrome
--------------- | ----- | ---------
callDirect | 159 | 43
callViaObject | 1741 | 1309
callViaCall | 168 | 718
callViaIdentity | 281 | 667

Our numbers make sense here, but not sure what happened to Chrome…

We have some pretty easy optimizations (allowing non-fixed field inlining checks to be hoisted our of lops) that should speed up all of these significantly. Inlining Object() would certainly help the second case and we should look into it. It should be easy.

Firefox has pretty consistent results across all 3 runs:

Test | FireFox
--------------- | -----
callDirect|199ms.
callViaObject|1505ms.
callViaCall|194ms.
callViaIdentity|192ms.

All 4 comments

callViaObject looks seriously slow. However not sure its popularity. Do you have v8 numbers?

Yes. Check the blog in the description of this issue.

I tried playing with his code a bit:
Original:

Test | Edge | Chrome
--------------- | ----- | ---------
callDirect | 716 | 546
callViaObject | 2156 | 1152
callViaCall | 196 | 579
callViaIdentity | 302 | 521

The reason for our poor callDirect score is that warmup wasn’t sufficient for us. Running the warmup twice, we get:

Test | Edge | Chrome
--------------- | ----- | ---------
callDirect | 198 | 545
callViaObject | 2157 | 1154
callViaCall | 190 | 582
callViaIdentity | 304 | 519

I then used a switch to get rid of the polymorphic calls:

Test | Edge | Chrome
--------------- | ----- | ---------
callDirect | 159 | 43
callViaObject | 1741 | 1309
callViaCall | 168 | 718
callViaIdentity | 281 | 667

Our numbers make sense here, but not sure what happened to Chrome…

We have some pretty easy optimizations (allowing non-fixed field inlining checks to be hoisted our of lops) that should speed up all of these significantly. Inlining Object() would certainly help the second case and we should look into it. It should be easy.

Firefox has pretty consistent results across all 3 runs:

Test | FireFox
--------------- | -----
callDirect|199ms.
callViaObject|1505ms.
callViaCall|194ms.
callViaIdentity|192ms.

Awesome.

Note however that the polymorphic call site inside test is there by design to make sure we measure the right thing, i.e. the cost of the actual functions under test and not our ability to inline everything into the driver and then hoist checks out of the loop.

Was this page helpful?
0 / 5 - 0 ratings