Skip to content

Performance regression of instanceof in v7 and master #9634

Description

@mcollina
  • Version: v7 and master
  • Platform: Mac
  • Subsystem:

instanceof checks has become almost 100 times slower in Node v7+ (and current master)

var r = /hello/

console.time('instanceof RegExp')
for (var i = 0; i < 100000000; i++) {
  r instanceof RegExp
}
console.timeEnd('instanceof RegExp')

var o = {}

console.time('instanceof Object')
for (var i = 0; i < 100000000; i++) {
  o instanceof Object
}
console.timeEnd('instanceof Object')

In node v6:

$ node instanceof.js
instanceof RegExp: 133.519ms
instanceof Object: 134.572ms

In node v7:

$ node instanceof.js
instanceof RegExp: 9858.616ms
instanceof Object: 9839.696ms

I know this is a problem in V8, but I think it's good to track it here as well.

v8 issue: https://bugs.chromium.org/p/v8/issues/detail?id=5640

cc @fhinkel

Activity

  1. targos commented on Nov 16, 2016

    @targos
    Member

    Could you also create a V8 bug and link to it here ?

  2. mcollina commented on Nov 16, 2016

    @mcollina
    SponsorMemberAuthor

    @targos done, thanks.

  3. targos commented on Nov 16, 2016

    @targos
    Member

    I cannot reproduce this regression in Chrome 54.

  4. mcollina commented on Nov 16, 2016

    @mcollina
    SponsorMemberAuthor

    Now that I test it... neither can I, and in theory they use the same v8 version.
    Maybe there is a patch to backport to the v8 version we are using.

  5. bnoordhuis commented on Nov 16, 2016

    @bnoordhuis
    Member

    Found the cause: commit 2a4b068 from last September, cc @addaleax.

    Chrome 54 ships the exact same version as node.js master, 5.4.500.41, and I can confirm that it's fast in Chrome and d8 (./configure --enable-d8) but not in Node.js.

    I checked with perf(1) and it showed that V8 was spending a phenomenal amount of time in v8::internal::Object::InstanceOf(), more specifically the code path that checks for the presence of a @@hasInstance method. Here is a minimal test case:

    function F() {}
    const hasInstance = Function.prototype[Symbol.hasInstance];
    Object.defineProperty(F, Symbol.hasInstance, { value: hasInstance });
    for (var o = {}, i = 0; i < 1e8; i++) o instanceof Object;

    Basically, if V8 sees that @@hasInstance is used, it starts emitting conservative slow path code.

  6. mcollina commented on Nov 16, 2016

    @mcollina
    SponsorMemberAuthor

    Oh no! :(

    We have some possible solutions:

    a. revert that fix, but probably it's semver-major. If we could do it semver-minor it will be the best solution.
    b. wait until there is a patch from upstream V8, and apply that.

    It would be nice to a quick post-mortem on this one. How can we spot those before releasing?

  7. addaleax commented on Nov 16, 2016

    @addaleax
    Member

    Huh… yeah, I did not see that coming.

  8. addaleax commented on Nov 16, 2016

    @addaleax
    Member

    (sorry, mis-clicked and posted the comment too early)

    How can we spot those before releasing?

    • Does V8 have benchmarks for this kind of thing? Is running them inside Node helpful?
    • Would people from the V8 team have spotted that this is problematic?
    • @mcollina I’m curious – how did you spot this?
  9. mcollina commented on Nov 16, 2016

    @mcollina
    SponsorMemberAuthor

    @mcollina I’m curious – how did you spot this?

    I found out that https://github.com/mcollina/bloomrun was 10 times slower in v7 rather than v6. It boiled down to instanceof, I did not do a git bisect on core, and I should have (that's awesome @bnoordhuis!!!).

  10. bnoordhuis commented on Nov 16, 2016

    @bnoordhuis
    Member

    Truthfully, I didn't bisect. I had a pretty good idea from looking at the perf data where the problem came from and reverting the commit confirmed that. :-)

  11. bmeurer commented on Nov 17, 2016

    @bmeurer
    Member

    I think I can come up with a small(ish) mitigation for the problem. Let me have a look.

  12. changed the title [-]Performance regression in instanceof in v7 and master[/-] [+]Performance regression of instanceof in v7 and master[/+] on Nov 17, 2016
  13. 14 remaining items

  14. fhinkel commented on Nov 21, 2016

    @fhinkel
    Contributor

    Should we wait until #9697 has landed?

  15. mcollina commented on Nov 21, 2016

    @mcollina
    SponsorMemberAuthor

    We need to get this into node v7.

  16. bnoordhuis commented on Nov 21, 2016

    @bnoordhuis
    Member

    We will probably upgrade to V8 5.5 during the v7 release cycle if we can work out the kinks, see #9618.

  17. bengl commented on Apr 21, 2017

    @bengl
    Member

    It looks like this might have regressed back to a 50(ish)x slowdown for RegExp on the Node 8 nightlies, and for non-builtins (which I added a test for in @mcollina's original example code), it seems to be a 10(ish)x slowdown on both Node 7 and Node 8 nightlies. (Should I open a new issue?)

    System: Linux 4.9.11 x86_64

    $ cat instanceof.js 
    var r = /hello/
    
    console.time('instanceof RegExp')
    for (var i = 0; i < 100000000; i++) {
      r instanceof RegExp
    }
    console.timeEnd('instanceof RegExp')
    
    var o = {}
    
    console.time('instanceof Object')
    for (var i = 0; i < 100000000; i++) {
      o instanceof Object
    }
    console.timeEnd('instanceof Object')
    
    function F () {}
    var f = new F
    
    console.time('instanceof F')
    for (var i = 0; i < 100000000; i++) {
      f instanceof F
    }
    console.timeEnd('instanceof F')
    $ ~/.nvm/versions/node/v6.10.2/bin/node instanceof.js 
    instanceof RegExp: 127.840ms
    instanceof Object: 129.514ms
    instanceof F: 635.539ms
    $ ~/.nvm/versions/node/v7.9.0/bin/node instanceof.js 
    instanceof RegExp: 163.946ms
    instanceof Object: 120.818ms
    instanceof F: 6786.285ms
    $ ~/.nvm/versions/node/v8.0.0-nightly2017042158066d16d5/bin/node instanceof.js 
    instanceof RegExp: 7501.615ms
    instanceof Object: 121.429ms
    instanceof F: 7219.541ms
    
  18. addaleax commented on Apr 21, 2017

    @addaleax
    Member

    Should I open a new issue?

    @bengl Yes, that seems like a good idea (and ping nodejs/v8 in it:))

  19. hashseed commented on Apr 22, 2017

    @hashseed
    Member

    This is https://bugs.chromium.org/p/v8/issues/detail?id=5902

    I'll merge this on Monday to 5.8.

  20. hashseed commented on Apr 24, 2017

    @hashseed
    Member
  21. hashseed commented on Apr 24, 2017

    @hashseed
    Member
  22. mcollina commented on May 2, 2017

    @mcollina
    SponsorMemberAuthor

    @hashseed fantastic!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    performanceIssues and PRs related to the performance of Node.js.v8 engineIssues and PRs related to the V8 dependency.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions