Skip to content

url: avoid instanceof for WHATWG URL - #11690

Closed
mscdex wants to merge 1 commit into
nodejs:masterfrom
mscdex:url-whatwg-perf
Closed

url: avoid instanceof for WHATWG URL#11690
mscdex wants to merge 1 commit into
nodejs:masterfrom
mscdex:url-whatwg-perf

Conversation

@mscdex

@mscdexmscdex commented Mar 5, 2017

Copy link
Copy Markdown
Contributor

This PR replaces instanceof checks with symbol checks. Various relevant results:

 improvement confidence p.value
url/url-searchparams-read.js n=50000000 param="nonexistent" method="get" 195.08 % *** 5.548226e-41
url/url-searchparams-read.js n=50000000 param="nonexistent" method="getAll" 174.48 % *** 3.225875e-29
url/url-searchparams-read.js n=50000000 param="nonexistent" method="has" 190.68 % *** 9.000669e-32
url/url-searchparams-read.js n=50000000 param="one" method="get" 269.63 % *** 2.180791e-33
url/url-searchparams-read.js n=50000000 param="one" method="getAll" 111.73 % *** 1.724534e-25
url/url-searchparams-read.js n=50000000 param="one" method="has" 266.25 % *** 5.498456e-33
url/url-searchparams-read.js n=50000000 param="three" method="get" 203.56 % *** 2.754902e-45
url/url-searchparams-read.js n=50000000 param="three" method="getAll" 108.95 % *** 1.790912e-35
url/url-searchparams-read.js n=50000000 param="three" method="has" 198.65 % *** 1.896093e-32
url/url-searchparams-read.js n=50000000 param="two" method="get" 248.88 % *** 4.737990e-41
url/url-searchparams-read.js n=50000000 param="two" method="getAll" 112.93 % *** 2.182157e-31
url/url-searchparams-read.js n=50000000 param="two" method="has" 224.41 % *** 2.056153e-30
url/whatwg-url-properties.js n=10000000 prop="origin" input="auth" 12.59 % ** 0.0035532598
url/whatwg-url-properties.js n=10000000 prop="origin" input="dot" 10.53 % ** 0.0041671062
url/whatwg-url-properties.js n=10000000 prop="origin" input="file" 72.86 % *** 0.0004049447
url/whatwg-url-properties.js n=10000000 prop="origin" input="idn" 5.76 % 0.1494657794
url/whatwg-url-properties.js n=10000000 prop="origin" input="javascript" 54.73 % ** 0.0018129659
url/whatwg-url-properties.js n=10000000 prop="origin" input="long" 10.20 % * 0.0429791847
url/whatwg-url-properties.js n=10000000 prop="origin" input="percent" 1.84 % 0.3920201593
url/whatwg-url-properties.js n=10000000 prop="origin" input="short" 11.54 % *** 0.0001064664
url/whatwg-url-properties.js n=10000000 prop="origin" input="ws" 10.64 % ** 0.0074980105

CI: https://ci.nodejs.org/job/node-test-pull-request/6707/

/cc @nodejs/url

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • commit message follows commit guidelines
Affected core subsystem(s)
  • url-whatwg

@mscdexmscdex added performance Issues and PRs related to the performance of Node.js. whatwg-url Issues and PRs related to the WHATWG URL implementation. labels Mar 5, 2017
@nodejs-github-botnodejs-github-bot added dont-land-on-v4.x whatwg-url Issues and PRs related to the WHATWG URL implementation. labels Mar 5, 2017

@joyeecheungjoyeecheung left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I vaguely remember some of the slowdowns of instanceof are already fixed in the v8 lkgr fork(5.8-ish)...at least for Buffer last time I played around with it. Nonethess I think testing for internal symbols is better anyway.

@joyeecheungjoyeecheung left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hit the wrong option..

TimothyGu
TimothyGu previously requested changes Mar 5, 2017
Comment threadlib/internal/url.js Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The searchParams symbol is used by the URL class as well, so this will no longer error out on URL objects.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've now added per-class symbols that are checked instead.

@mscdex

Copy link
Copy Markdown
ContributorAuthor

CI again after symbol check changes: https://ci.nodejs.org/job/node-test-pull-request/6718/

Comment threadlib/internal/url.js Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer urlInstance just to be consistent with searchParamsInstance.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed.

Comment threadlib/internal/url.js Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still reluctant about writing out this[searchParamsInstance] !== true when a !this[searchParamsInstance] would do. Is this change visible performance-wise?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just being more explicit about the expected value.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 to be more explicit.

@TimothyGu
TimothyGu dismissed their stale reviewMarch 6, 2017 02:52

Review of an older iteration of the PR

Comment threadlib/internal/url.js Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use the existing context and searchParams symbols rather than introducing new ones? All URL objects should have the context symbol set. Likewise all URLSearchParams instances should have the searchParams symbol set (I believe)

@mscdexmscdexMar 7, 2017

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As @TimothyGu noted, both classes use both of those symbols, so they don't currently each have a unique symbol?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can probably separate them like this:

if(url[searchParams]){if(url[searchParams][searchParams]){}// URL, it's an arrayelse{}// URLSearchParams, it's undefined}

@TimothyGuTimothyGu left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any updates on this?

Comment threadlib/internal/url.js Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might put the urlInstance in the prototype to avoid having to set this every single time an object is created.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then URL.prototype will pass the brand check, which seems bad.

Comment threadlib/internal/url.js Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

@mscdex

Copy link
Copy Markdown
ContributorAuthor

Alright, I've switched to checking using only searchParams. New results with V8 5.7:

 improvement confidence p.value
url/url-searchparams-read.js n=20000000 param="nonexistent" method="get" 163.51 % *** 2.269241e-61
url/url-searchparams-read.js n=20000000 param="nonexistent" method="getAll" 160.05 % *** 5.142371e-51
url/url-searchparams-read.js n=20000000 param="nonexistent" method="has" 167.00 % *** 1.355736e-46
url/url-searchparams-read.js n=20000000 param="one" method="get" 236.25 % *** 8.197452e-52
url/url-searchparams-read.js n=20000000 param="one" method="getAll" 120.78 % *** 2.622135e-51
url/url-searchparams-read.js n=20000000 param="one" method="has" 243.64 % *** 6.676611e-50
url/url-searchparams-read.js n=20000000 param="three" method="get" 194.93 % *** 5.614993e-59
url/url-searchparams-read.js n=20000000 param="three" method="getAll" 106.35 % *** 3.023894e-81
url/url-searchparams-read.js n=20000000 param="three" method="has" 189.66 % *** 7.362414e-46
url/url-searchparams-read.js n=20000000 param="two" method="get" 218.28 % *** 1.350097e-67
url/url-searchparams-read.js n=20000000 param="two" method="getAll" 113.33 % *** 2.637819e-83
url/url-searchparams-read.js n=20000000 param="two" method="has" 218.26 % *** 4.443562e-86
url/whatwg-url-properties.js n=300000 prop="origin" input="auth" 12.40 % *** 3.767663e-16
url/whatwg-url-properties.js n=300000 prop="origin" input="dot" 7.74 % *** 8.915982e-09
url/whatwg-url-properties.js n=300000 prop="origin" input="file" 77.36 % *** 1.300946e-26
url/whatwg-url-properties.js n=300000 prop="origin" input="idn" 4.96 % *** 2.077301e-10
url/whatwg-url-properties.js n=300000 prop="origin" input="javascript" 83.97 % *** 6.470616e-48
url/whatwg-url-properties.js n=300000 prop="origin" input="long" 9.44 % *** 3.128818e-11
url/whatwg-url-properties.js n=300000 prop="origin" input="percent" 7.26 % *** 3.400718e-14
url/whatwg-url-properties.js n=300000 prop="origin" input="short" 9.22 % *** 1.478553e-11
url/whatwg-url-properties.js n=300000 prop="origin" input="ws" 7.70 % *** 9.628009e-09

Results are pretty close to what they were before.

@jasnelljasnell left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally LGTM with a question/suggestion

Comment threadlib/internal/url.js
input = `${input}`;
if (base !== undefined && !(base instanceof URL))
if (base !== undefined &&
(!base[searchParams] || !base[searchParams][searchParams])) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mscdex ... is there benefit to moving this into a separate isURL(u) function that can be exported by internal/url?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Performance-wise? No. There's actually a small but measurable performance hit when extracting all of the logic to a separate function, compared to having it inline. For example:

 improvement confidence p.value
url/url-searchparams-read.js n=20000000 param="nonexistent" method="get" 165.07 % *** 1.189398e-66
url/url-searchparams-read.js n=20000000 param="nonexistent" method="getAll" 139.46 % *** 4.331942e-46
url/url-searchparams-read.js n=20000000 param="nonexistent" method="has" 161.48 % *** 2.741360e-52
url/url-searchparams-read.js n=20000000 param="one" method="get" 222.70 % *** 3.111318e-46
url/url-searchparams-read.js n=20000000 param="one" method="getAll" 113.31 % *** 1.122968e-53
url/url-searchparams-read.js n=20000000 param="one" method="has" 232.04 % *** 1.571222e-55
url/url-searchparams-read.js n=20000000 param="three" method="get" 184.13 % *** 2.078669e-48
url/url-searchparams-read.js n=20000000 param="three" method="getAll" 100.34 % *** 4.591714e-56
url/url-searchparams-read.js n=20000000 param="three" method="has" 181.29 % *** 7.340053e-43
url/url-searchparams-read.js n=20000000 param="two" method="get" 209.77 % *** 4.581349e-54
url/url-searchparams-read.js n=20000000 param="two" method="getAll" 102.89 % *** 2.001755e-36
url/url-searchparams-read.js n=20000000 param="two" method="has" 203.09 % *** 1.810527e-44

@joyeecheungjoyeecheung left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still LGTM

@joyeecheung

Copy link
Copy Markdown
Member

@jasnell

Copy link
Copy Markdown
Member

@TimothyGu

Copy link
Copy Markdown
Member

Landed in b76a350.

TimothyGu pushed a commit that referenced this pull request Apr 5, 2017
PR-URL: #11690
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Reviewed-By: Timothy Gu <timothygu99@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Daijiro Wachi <daijiro.wachi@gmail.com>
@mscdex
mscdex deleted the url-whatwg-perf branch April 5, 2017 04:09
@italoacasas

Copy link
Copy Markdown

cc @mscdex

@guybedford

Copy link
Copy Markdown
Contributor

This has come up again in #22506. @mscdex do you think we could move to an instanceof check at this point from a performance perspective yet? Would value your feedback on this.

@mscdex

Copy link
Copy Markdown
ContributorAuthor

@guybedford I do not know offhand. Someone would have to be sure to run benchmarks on both implementations and compare the results for master.

@devsnek

Copy link
Copy Markdown
Member

I think there's also a concern about Object.create(URL.prototype) matching instanceof. If we use instanceof and then try to access our symbol properties it will fail.

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

Labels

performanceIssues and PRs related to the performance of Node.js.whatwg-urlIssues and PRs related to the WHATWG URL implementation.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants

@mscdex@joyeecheung@jasnell@TimothyGu@italoacasas@guybedford@devsnek@domenic@watilde@nodejs-github-bot