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

module: skip directories known not to exist #9196

Merged
merged 3 commits into from
Oct 24, 2016

Conversation

bnoordhuis
Copy link
Member

@bnoordhuis bnoordhuis commented Oct 19, 2016

There is no point in trying to search for files in a directory that
we know does not exist, so stop doing that.

Reduces the total number of stat(2) calls and the number of stat(2)
misses on a medium-sized application by about 21% and 29% respectively.

Reduces the total number of package.json open(2) calls and the number
of open(2) misses by about 21% and 93% (!) respectively.

Before:

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 50.93    0.178419          38      4702           lstat
 29.08    0.101875          36      2800      2010 stat
 11.36    0.039796          43       932       215 open
  5.39    0.018897          34       550           fstat
  3.24    0.011337          34       336           pread
------ ----------- ----------- --------- --------- ----------------
100.00    0.350324                  9320      2225 total

After:

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 55.49    0.176638          38      4702           lstat
 24.76    0.078826          35      2225      1435 stat
 10.19    0.032434          44       733        16 open
  6.19    0.019719          36       550           fstat
  3.37    0.010723          32       336           pread
------ ----------- ----------- --------- --------- ----------------
100.00    0.318340                  8546      1451 total

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

@nodejs-github-bot nodejs-github-bot added the module Issues and PRs related to the module subsystem. label Oct 19, 2016
Copy link
Contributor

@silverwind silverwind left a comment

Choose a reason for hiding this comment

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

LGTM

@bnoordhuis
Copy link
Member Author

Here is what the access pattern looked liked before this pull request. (File paths shortened for brevity.)

29754 stat(".../node_modules/finalhandler", 0x7fff639476d0) = -1 ENOENT (No such file or directory)
29754 stat(".../node_modules/finalhandler.js", 0x7fff63947630) = -1 ENOENT (No such file or directory)
29754 stat(".../node_modules/finalhandler.json", 0x7fff63947630) = -1 ENOENT (No such file or directory)
29754 stat(".../node_modules/finalhandler.node", 0x7fff63947630) = -1 ENOENT (No such file or directory)
29754 open(".../node_modules/finalhandler/package.json", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
29754 stat(".../node_modules/finalhandler/index.js", 0x7fff63947630) = -1 ENOENT (No such file or directory)
29754 stat(".../node_modules/finalhandler/index.json", 0x7fff63947630) = -1 ENOENT (No such file or directory)
29754 stat(".../node_modules/finalhandler/index.node", 0x7fff63947630) = -1 ENOENT (No such file or directory)

Note how the last four are guaranteed to fail because of the first one.

@mscdex
Copy link
Contributor

mscdex commented Oct 19, 2016

LGTM

Copy link
Contributor

@evanlucas evanlucas left a comment

Choose a reason for hiding this comment

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

LGTM

@Fishrock123
Copy link
Contributor

Fishrock123 commented Oct 20, 2016

Does attempting to require from a directory, failing and making a new directory, writing into, and then loading files from that directory still work?

@bnoordhuis
Copy link
Member Author

You say 'still' but does it work now? The stat cache persists for the duration of a module's top-level code.

@@ -69,6 +69,8 @@ assert.equal(threeFolder, threeIndex);
assert.notEqual(threeFolder, three);

console.error('test package.json require() loading');
assert.equal(require('../fixtures/packages/index').ok, 'ok',
Copy link
Member

@jasnell jasnell Oct 20, 2016

Choose a reason for hiding this comment

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

strictEqual?
I know equal is consistent with the rest of the test but updating the test may be worthwhile

Copy link
Member Author

@bnoordhuis bnoordhuis Oct 20, 2016

Choose a reason for hiding this comment

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

I followed the style of the surrounding code here.

EDIT: Never mind, didn't see you edited your comment. Still, consistency is important, right?

Copy link
Member Author

@bnoordhuis bnoordhuis Oct 24, 2016

Choose a reason for hiding this comment

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

I'll update the test en bloc in a separate pull request.

EDIT: #9263

Copy link
Member

@jasnell jasnell left a comment

Choose a reason for hiding this comment

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

LGTM with a nit

Verify that a package.json without a .main property loads index.js.

PR-URL: nodejs#9196
Reviewed-By: Brian White <mscdex@mscdex.net>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Evan Lucas <evanlucas@me.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Discourage using require.extensions because it slows down the module
loader.  The number of file system operations that the module system
has to perform in order to resolve a `require(...)` statement to a
filename is proportional to the number of registered extensions.

PR-URL: nodejs#9196
Reviewed-By: Brian White <mscdex@mscdex.net>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Evan Lucas <evanlucas@me.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
There is no point in trying to search for files in a directory that
we know does not exist, so stop doing that.

Reduces the total number of stat(2) calls and the number of stat(2)
misses on a medium-sized application by about 21% and 29% respectively.

Reduces the total number of package.json open(2) calls and the number
of open(2) misses by about 21% and 93% (!) respectively.

Before:

    % time     seconds  usecs/call     calls    errors syscall
    ------ ----------- ----------- --------- --------- ----------------
     50.93    0.178419          38      4702           lstat
     29.08    0.101875          36      2800      2010 stat
     11.36    0.039796          43       932       215 open
      5.39    0.018897          34       550           fstat
      3.24    0.011337          34       336           pread
    ------ ----------- ----------- --------- --------- ----------------
    100.00    0.350324                  9320      2225 total

After:

    % time     seconds  usecs/call     calls    errors syscall
    ------ ----------- ----------- --------- --------- ----------------
     55.49    0.176638          38      4702           lstat
     24.76    0.078826          35      2225      1435 stat
     10.19    0.032434          44       733        16 open
      6.19    0.019719          36       550           fstat
      3.37    0.010723          32       336           pread
    ------ ----------- ----------- --------- --------- ----------------
    100.00    0.318340                  8546      1451 total

PR-URL: nodejs#9196
Reviewed-By: Brian White <mscdex@mscdex.net>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Evan Lucas <evanlucas@me.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
@bnoordhuis bnoordhuis closed this Oct 24, 2016
@bnoordhuis bnoordhuis deleted the skip-enoent-module-dirs branch October 24, 2016 20:51
@bnoordhuis bnoordhuis merged commit 678c094 into nodejs:master Oct 24, 2016
evanlucas pushed a commit that referenced this pull request Nov 2, 2016
Verify that a package.json without a .main property loads index.js.

PR-URL: #9196
Reviewed-By: Brian White <mscdex@mscdex.net>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Evan Lucas <evanlucas@me.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
evanlucas pushed a commit that referenced this pull request Nov 2, 2016
There is no point in trying to search for files in a directory that
we know does not exist, so stop doing that.

Reduces the total number of stat(2) calls and the number of stat(2)
misses on a medium-sized application by about 21% and 29% respectively.

Reduces the total number of package.json open(2) calls and the number
of open(2) misses by about 21% and 93% (!) respectively.

Before:

    % time     seconds  usecs/call     calls    errors syscall
    ------ ----------- ----------- --------- --------- ----------------
     50.93    0.178419          38      4702           lstat
     29.08    0.101875          36      2800      2010 stat
     11.36    0.039796          43       932       215 open
      5.39    0.018897          34       550           fstat
      3.24    0.011337          34       336           pread
    ------ ----------- ----------- --------- --------- ----------------
    100.00    0.350324                  9320      2225 total

After:

    % time     seconds  usecs/call     calls    errors syscall
    ------ ----------- ----------- --------- --------- ----------------
     55.49    0.176638          38      4702           lstat
     24.76    0.078826          35      2225      1435 stat
     10.19    0.032434          44       733        16 open
      6.19    0.019719          36       550           fstat
      3.37    0.010723          32       336           pread
    ------ ----------- ----------- --------- --------- ----------------
    100.00    0.318340                  8546      1451 total

PR-URL: #9196
Reviewed-By: Brian White <mscdex@mscdex.net>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Evan Lucas <evanlucas@me.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
evanlucas pushed a commit that referenced this pull request Nov 2, 2016
Discourage using require.extensions because it slows down the module
loader.  The number of file system operations that the module system
has to perform in order to resolve a `require(...)` statement to a
filename is proportional to the number of registered extensions.

PR-URL: #9196
Reviewed-By: Brian White <mscdex@mscdex.net>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Evan Lucas <evanlucas@me.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
@MylesBorins
Copy link
Contributor

@bnoordhuis should this be backported?

@bnoordhuis
Copy link
Member Author

It could but it doesn't have to be. It's an optimization, not a bug fix.

@sam-github
Copy link
Contributor

@bnoordhuis @MylesBorins should be labelled either dont-land-on-v6.x or backport-requested-to-v6.x, what say you? I think making v6.x faster is good, but not essential.

@bnoordhuis
Copy link
Member Author

It should be a zero-risk back-port but then again, no one complained it's slow. The most compelling reason would be to avoid future merge conflicts but OTOH, lib/module.js doesn't see all that many updates so probably not much of an issue. /stream-of-consciousness

Don't bother, it's fine.

@MylesBorins
Copy link
Contributor

I think we should just keep this labelled and be ready to backport if we run into problems in the future... would prefer not to touch module

@MylesBorins MylesBorins added the baking-for-lts PRs that need to wait before landing in a LTS release. label May 8, 2017
@MylesBorins MylesBorins removed the baking-for-lts PRs that need to wait before landing in a LTS release. label Aug 17, 2018
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.
Projects
None yet
Development

Successfully merging this pull request may close these issues.