Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

util: improve util.format performance #5360

Merged
merged 3 commits into from
Mar 4, 2016

Conversation

evanlucas
Copy link
Contributor

By manually copying arguments and breaking the try/catch out, we are able to improve the performance of util.format by 20-100% (depending on the types).

Also includes a util.format benchmark.

The numbers:

running ./node
util/format.js
running ./node_before
util/format.js

util/format.js n=1000000 type=string: ./node: 7866600 ./node_before: 1705900 ... 361.13%
util/format.js n=1000000 type=number: ./node: 7718000 ./node_before: 1778900 ... 333.87%
util/format.js n=1000000 type=object: ./node: 1811800 ./node_before: 800160 .... 126.43%
util/format.js n=1000000 type=unknown: ./node: 13045000 ./node_before: 2650300 . 392.22%
util/format.js n=1000000 type=no-replace: ./node: 1541500 ./node_before: 956760 . 61.11%

EDIT: I updated the numbers after rebasing on master and with @mscdex's changes included as well.

@evanlucas evanlucas added util Issues and PRs related to the built-in util module. benchmark Issues and PRs related to the benchmark subsystem. performance Issues and PRs related to the performance of Node.js. labels Feb 22, 2016
@evanlucas
Copy link
Contributor Author

@@ -21,21 +29,20 @@ exports.format = function(f) {

if (arguments.length === 1) return f;

const len = arguments.length;
const args = new Array(len);
for (let i = 0; i < len; i++) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Use var here until v8 can optimize let better.

@@ -21,21 +29,20 @@ exports.format = function(f) {

if (arguments.length === 1) return f;

const len = arguments.length;
const args = new Array(len);
for (var i = 0; i < len; i++) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry, you'll also need to move the var i declaration out and above and change var i = 1; a few lines below to i = 1 to avoid a linter error.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yep, just noticed that locally. Thanks

@mscdex
Copy link
Contributor

mscdex commented Feb 22, 2016

For bonus points, you can change

for (var x = args[i]; i < len; x = args[++i]) {

to

while (i < len) {
  const x = args[i++];

to avoid an eager deopt due to potential out of bounds access on args.

@evanlucas evanlucas force-pushed the utilformatbench branch 2 times, most recently from 7a00928 to 91fc8b4 Compare February 22, 2016 09:39
@evanlucas
Copy link
Contributor Author

Ah, totally missed the case where f is not a string. Added a benchmark and updated for that as well

args[i] = arguments[i];
}

i = 1;
var str = String(f).replace(formatRegExp, function(x) {
Copy link
Contributor

Choose a reason for hiding this comment

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

String(f) here can probably just be replaced with just f since it should already be a string at that point.

@evanlucas
Copy link
Contributor Author

ooo good catch

@mscdex
Copy link
Contributor

mscdex commented Feb 22, 2016

@mscdex
Copy link
Contributor

mscdex commented Feb 22, 2016

Just for fun I replaced the regexp + replace function with a simple loop and improved performance an additional 60-200% in the benchmarks included (and no change in the no-replace case) in this PR.

@evanlucas
Copy link
Contributor Author

wow, nice

@jasnell
Copy link
Member

jasnell commented Mar 2, 2016

Marking this LTS watch but I'd rather this sit for a bit before getting pulled back.

@jasnell
Copy link
Member

jasnell commented Mar 2, 2016

LGTM

@evanlucas
Copy link
Contributor Author

evanlucas and others added 3 commits March 4, 2016 17:27
PR-URL: nodejs#5360
Reviewed-By: James M Snell <jasnell@gmail.com>
By manually copying arguments and breaking the try/catch out, we are
able to improve the performance of util.format by 20-100% (depending on
the types).

PR-URL: nodejs#5360
Reviewed-By: James M Snell <jasnell@gmail.com>
Replacing the regexp and replace function with a loop improves
performance by ~60-200%.

PR-URL: nodejs#5360
Reviewed-By: James M Snell <jasnell@gmail.com>
@evanlucas evanlucas closed this Mar 4, 2016
@evanlucas evanlucas deleted the utilformatbench branch March 4, 2016 23:28
@evanlucas evanlucas merged commit c490b8b into nodejs:master Mar 4, 2016
@MylesBorins
Copy link
Contributor

@jasnell would you want to include this in a future lts?

@jasnell
Copy link
Member

jasnell commented May 17, 2016

I believe so yes.

@MylesBorins
Copy link
Contributor

@jasnell / @nodejs/lts how much longer to we want this to live before backporting?

@jasnell
Copy link
Member

jasnell commented Jul 1, 2016

I haven't heard of any regressions. We may be good on this one
On Jun 30, 2016 5:11 PM, "Myles Borins" notifications@github.com wrote:

@jasnell https://github.com/jasnell / @nodejs/lts
https://github.com/orgs/nodejs/teams/lts how much longer to we want
this to live before backporting?


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#5360 (comment), or mute
the thread
https://github.com/notifications/unsubscribe/AAa2eVV5PJs-GWjQjX7nl55qNJMiSNYGks5qRFtAgaJpZM4HfWa3
.

MylesBorins pushed a commit that referenced this pull request Jul 11, 2016
By manually copying arguments and breaking the try/catch out, we are
able to improve the performance of util.format by 20-100% (depending on
the types).

PR-URL: #5360
Reviewed-By: James M Snell <jasnell@gmail.com>
MylesBorins pushed a commit that referenced this pull request Jul 11, 2016
Replacing the regexp and replace function with a loop improves
performance by ~60-200%.

PR-URL: #5360
Reviewed-By: James M Snell <jasnell@gmail.com>
@MylesBorins
Copy link
Contributor

I've gone ahead and added this to v4.x-staging and will include it in the v4.5.0 rc.

@evanlucas please let me know if there are any accompanying patch's we need to make this work

@MylesBorins
Copy link
Contributor

@evanlucas as a heads up you need to provide the commit before your initial commit when doing the ... syntax to specify a range.

735e0df...c490b8b does not include 735e0df

MylesBorins pushed a commit that referenced this pull request Jul 11, 2016
By manually copying arguments and breaking the try/catch out, we are
able to improve the performance of util.format by 20-100% (depending on
the types).

PR-URL: #5360
Reviewed-By: James M Snell <jasnell@gmail.com>
MylesBorins pushed a commit that referenced this pull request Jul 11, 2016
Replacing the regexp and replace function with a loop improves
performance by ~60-200%.

PR-URL: #5360
Reviewed-By: James M Snell <jasnell@gmail.com>
MylesBorins pushed a commit that referenced this pull request Jul 11, 2016
PR-URL: #5360
Reviewed-By: James M Snell <jasnell@gmail.com>
MylesBorins pushed a commit that referenced this pull request Jul 12, 2016
PR-URL: #5360
Reviewed-By: James M Snell <jasnell@gmail.com>
@evanlucas
Copy link
Contributor Author

@thealphanerd there shouldn't be anything else need to land these. Thanks for the heads up on the range syntax as well :]

MylesBorins pushed a commit that referenced this pull request Jul 12, 2016
By manually copying arguments and breaking the try/catch out, we are
able to improve the performance of util.format by 20-100% (depending on
the types).

PR-URL: #5360
Reviewed-By: James M Snell <jasnell@gmail.com>
MylesBorins pushed a commit that referenced this pull request Jul 12, 2016
Replacing the regexp and replace function with a loop improves
performance by ~60-200%.

PR-URL: #5360
Reviewed-By: James M Snell <jasnell@gmail.com>
MylesBorins pushed a commit that referenced this pull request Jul 12, 2016
PR-URL: #5360
Reviewed-By: James M Snell <jasnell@gmail.com>
@MylesBorins MylesBorins mentioned this pull request Jul 12, 2016
MylesBorins pushed a commit that referenced this pull request Jul 14, 2016
PR-URL: #5360
Reviewed-By: James M Snell <jasnell@gmail.com>
MylesBorins pushed a commit that referenced this pull request Jul 14, 2016
PR-URL: #5360
Reviewed-By: James M Snell <jasnell@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
benchmark Issues and PRs related to the benchmark subsystem. performance Issues and PRs related to the performance of Node.js. util Issues and PRs related to the built-in util module.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants