Skip to content

module: skip directories known not to exist#9196

Merged
bnoordhuis merged 3 commits into
nodejs:masterfrom
bnoordhuis:skip-enoent-module-dirs
Oct 24, 2016
Merged

module: skip directories known not to exist#9196
bnoordhuis merged 3 commits into
nodejs:masterfrom
bnoordhuis:skip-enoent-module-dirs

Conversation

@bnoordhuis

@bnoordhuis bnoordhuis commented Oct 19, 2016

Copy link
Copy Markdown
Member

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

@silverwind silverwind left a comment

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.

LGTM

@bnoordhuis

Copy link
Copy Markdown
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

mscdex commented Oct 19, 2016

Copy link
Copy Markdown
Contributor

LGTM

@evanlucas evanlucas left a comment

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.

LGTM

@Fishrock123

Fishrock123 commented Oct 20, 2016

Copy link
Copy Markdown
Contributor

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
Copy Markdown
Member Author

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

assert.notEqual(threeFolder, three);

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

@jasnell jasnell Oct 20, 2016

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.

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

@bnoordhuis bnoordhuis Oct 20, 2016

Copy link
Copy Markdown
Member Author

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?

@bnoordhuis bnoordhuis Oct 24, 2016

Copy link
Copy Markdown
Member Author

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

@jasnell jasnell 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.

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 force-pushed the skip-enoent-module-dirs branch from 8f5dfbc to 678c094 Compare October 24, 2016 20:51
@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
Copy Markdown
Contributor

@bnoordhuis should this be backported?

@bnoordhuis

Copy link
Copy Markdown
Member Author

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

@sam-github

Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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.