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

lib: improve module loading performance #5172

Merged
merged 2 commits into from
Apr 14, 2016

Conversation

mscdex
Copy link
Contributor

@mscdex mscdex commented Feb 10, 2016

This commit improves module loading performance by at least ~17-23% in the module-loader benchmarks.

This improvement is on top of the module loading performance boost brought on by #5123. Both PRs combined bring a total of ~54% improvement in module loading.

Some optimization strategies include:

  • Try-finally/try-catch isolation
  • Replacing regular expressions with manual parsers
  • Avoiding unnecessary string and array creation
  • Avoiding constant recompilation of anonymous functions and
    function definitions within functions

@mscdex mscdex added the module Issues and PRs related to the module subsystem. label Feb 10, 2016
@mscdex
Copy link
Contributor Author

mscdex commented Feb 10, 2016

}
return st;
}
function tryCreateBuffer(size, fd, isUserFd) {
Copy link
Member

Choose a reason for hiding this comment

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

some spacing between functions would be nice

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

var i = start;
for (; i < path.length; ++i) {
const code = path.charCodeAt(i);
if (code === 47/*/*/ || code === 92/*\*/)
Copy link
Member

Choose a reason for hiding this comment

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

can you quote and space these so it doesn't just look like weird comments?
if (code === 47 /* '/' */ || code === 92 /* '\' */)
or
if (code === 47 || code === 92) // '/' or '\'
I personally find the latter clearest

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was mainly keeping things consistent with the path perf PR. I don't really have a strong preference either way, but I do think that having the literals next to the character codes is easier to scan.

Copy link
Contributor

Choose a reason for hiding this comment

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

I have to agree with @rvagg that the current code comment is rather unreadable (makes my eyes spin ;)) And Rod's latter example is the nicest alternative imho too.

@rvagg
Copy link
Member

rvagg commented Feb 10, 2016

Pretty impressive work, I find the regex replacement with manual parsers the most confronting part of this and worry about its maintainability and approachability. Any idea what portion of the speedup is due to those bits?

If the functions are a nearly direct translation of the regexes then maybe put the regex at the top in a comment to show what it's trying to do.

@mscdex
Copy link
Contributor Author

mscdex commented Feb 10, 2016

I don't recall the actual numbers for each regexp removal, but they are a decent amount.

The added path root extraction functions were mostly ripped from the new path changes and I thought about adding them as new path methods, but wasn't so sure about it.

@jasnell
Copy link
Member

jasnell commented Feb 10, 2016

LGTM but I do agree with the concerns over maintainability. Hopefully that's not going to be too much of an issue tho given that this code is pretty stable.


// For each path
for (var i = 0, PL = paths.length; i < PL; i++) {
for (var i = 0; i < paths.length; i++) {

Choose a reason for hiding this comment

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

Any reason to not use let here instead of var ?

Copy link
Member

Choose a reason for hiding this comment

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

let apparently still has some optimization issues in V8. For hot code paths var is still preferred

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, what @jasnell said.

@ChALkeR ChALkeR added the performance Issues and PRs related to the performance of Node.js. label Feb 16, 2016
@mscdex
Copy link
Contributor Author

mscdex commented Feb 19, 2016

FWIW merging these changes with #3594 actually provides a much larger increase (since less time is spent doing path resolution): ~34% for the full path case and ~25% for the directory case.

@jasnell
Copy link
Member

jasnell commented Feb 19, 2016

Cautiously putting a don't land on v4.x label on. Would want this to sit in a stable for a while before pulling back

@ronkorving
Copy link
Contributor

Is anything blocking this from landing? (besides the merge conflict, cc @mscdex)
If I had to guess, the big regex replacement, similar to #5256 is something worth debating (but then let's have that debate).

@mscdex
Copy link
Contributor Author

mscdex commented Feb 27, 2016

@ronkorving As soon as the realpath/realpathSync PR (#3594) (and its accompanying libuv update) get merged, the entire custom userland implementation of those methods goes away.

@jasnell
Copy link
Member

jasnell commented Mar 21, 2016

@mscdex ... ping... where is this one at?

@mscdex
Copy link
Contributor Author

mscdex commented Mar 21, 2016

@jasnell Well, when both the next version of libuv and #3594 lands, the realpath-related changes can be removed. I'm waiting on those changes to happen first.

@jasnell
Copy link
Member

jasnell commented Mar 21, 2016

sounds good!

@mscdex mscdex added this to the 6.0.0 milestone Apr 6, 2016
@mscdex
Copy link
Contributor Author

mscdex commented Apr 7, 2016

I've rebased and removed the realpath changes in anticipation of #3594.

@jasnell
Copy link
Member

jasnell commented Apr 7, 2016

Still LGTM if CI is green

@mscdex
Copy link
Contributor Author

mscdex commented Apr 14, 2016

This commit improves module loading performance by at least ~25-35%
in the module-loader benchmarks.

Some optimization strategies include:
* Try-finally/try-catch isolation
* Replacing regular expressions with manual parsing
* Avoiding unnecessary string and array creation
* Avoiding constant recompilation of anonymous functions and
function definitions within functions

PR-URL: nodejs#5172
Reviewed-By: James M Snell <[email protected]>
@mscdex mscdex merged commit ae18bbe into nodejs:master Apr 14, 2016
@mscdex mscdex deleted the perf-module-loading branch April 14, 2016 19:11
@MylesBorins
Copy link
Contributor

@mscdex did you use the merge button for this???? if so I'm glad to see it is working as expected

@mscdex
Copy link
Contributor Author

mscdex commented Apr 14, 2016

@thealphanerd No, I didn't use the merge button.

@MylesBorins
Copy link
Contributor

@mscdex never mind then... was thrown off by the merge message above. Thanks for the heads up

@mhdawson
Copy link
Member

Benchmark graph at benchmarking.nodejs.org shows a bump from 14603 to 24127 for the "new" case, nice !

Require new Ops/s

@MylesBorins
Copy link
Contributor

Should we land this on v5.x? There are conflicts and I'm imagining we may not want to land something that touches module and may have regressions if we are not cutting another v5.x

@mscdex
Copy link
Contributor Author

mscdex commented Apr 19, 2016

@thealphanerd Something else to keep in mind is that the jump you see in that graph is also including the realpath changes, so it's not just this PR. I would probably hold off on backporting to v5.x just to be safe for now.

@MylesBorins
Copy link
Contributor

added dont-land thanks fo the quick response

MylesBorins pushed a commit that referenced this pull request Apr 19, 2016
MylesBorins pushed a commit that referenced this pull request Apr 20, 2016
MylesBorins pushed a commit that referenced this pull request Apr 20, 2016
@MylesBorins MylesBorins mentioned this pull request Apr 20, 2016
MylesBorins pushed a commit that referenced this pull request Apr 20, 2016
This was referenced Apr 21, 2016
MylesBorins pushed a commit that referenced this pull request Apr 21, 2016
jasnell pushed a commit that referenced this pull request Apr 26, 2016
jasnell pushed a commit that referenced this pull request Apr 26, 2016
This commit improves module loading performance by at least ~25-35%
in the module-loader benchmarks.

Some optimization strategies include:
* Try-finally/try-catch isolation
* Replacing regular expressions with manual parsing
* Avoiding unnecessary string and array creation
* Avoiding constant recompilation of anonymous functions and
function definitions within functions

PR-URL: #5172
Reviewed-By: James M Snell <[email protected]>
kevinoid pushed a commit to kevinoid/fs-file-sync-fd that referenced this pull request Dec 13, 2016
This commit improves module loading performance by at least ~25-35%
in the module-loader benchmarks.

Some optimization strategies include:
* Try-finally/try-catch isolation
* Replacing regular expressions with manual parsing
* Avoiding unnecessary string and array creation
* Avoiding constant recompilation of anonymous functions and
function definitions within functions

PR-URL: nodejs/node#5172
Reviewed-By: James M Snell <[email protected]>
@mscdex mscdex mentioned this pull request Jan 27, 2017
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
module Issues and PRs related to the module subsystem. performance Issues and PRs related to the performance of Node.js.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants