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

path: performance and stability improvements on all platforms #5123

Closed
wants to merge 4 commits into from

Conversation

mscdex
Copy link
Contributor

@mscdex mscdex commented Feb 6, 2016

This is more or less a rewrite of the entire path module and brings with it significant performance benefits. Overall the improvements bring up to an 18,000% performance increase. The ridiculously high number comes from the early returns that I've added for simple cases (e.g. empty or '/' inputs). The non-early return improvements are more like up to 2,000%.

Here are the benchmark results with these changes (note: these results were obtained from a benchmark.js-based benchmark runner I'm working on, but the inputs and actual test code are the same):

path/basename-posix.js pathext=
  ../node/node:          60,736,922 ops/sec ± 0.05% (94 runs sampled)
  ../node/node-pre-path:  5,388,231 ops/sec ± 0.28% (91 runs sampled)
                         1027.21%
path/basename-posix.js pathext=/
  ../node/node:          49,874,497 ops/sec ± 0.04% (97 runs sampled)
  ../node/node-pre-path:  6,690,152 ops/sec ± 0.23% (94 runs sampled)
                         645.49%
path/basename-posix.js pathext=/foo
  ../node/node:          20,269,451 ops/sec ± 0.33% (94 runs sampled)
  ../node/node-pre-path:  5,865,926 ops/sec ± 0.25% (93 runs sampled)
                         245.55%
path/basename-posix.js pathext=/foo/.bar.baz
  ../node/node:          14,410,695 ops/sec ± 0.20% (95 runs sampled)
  ../node/node-pre-path:  3,399,308 ops/sec ± 0.25% (93 runs sampled)
                         323.93%
path/basename-posix.js pathext=/foo/.bar.baz|.baz
  ../node/node:          8,506,502 ops/sec ± 0.19% (95 runs sampled)
  ../node/node-pre-path: 2,698,248 ops/sec ± 0.16% (96 runs sampled)
                         215.26%
path/basename-posix.js pathext=foo
  ../node/node:          24,815,912 ops/sec ± 0.09% (94 runs sampled)
  ../node/node-pre-path:  6,022,135 ops/sec ± 0.22% (97 runs sampled)
                         312.08%
path/basename-posix.js pathext=foo/bar.
  ../node/node:          18,895,190 ops/sec ± 0.21% (95 runs sampled)
  ../node/node-pre-path:  3,602,397 ops/sec ± 0.21% (98 runs sampled)
                         424.52%
path/basename-posix.js pathext=foo/bar.|.
  ../node/node:          10,157,151 ops/sec ± 0.18% (95 runs sampled)
  ../node/node-pre-path:  2,959,689 ops/sec ± 0.39% (98 runs sampled)
                         243.18%
path/basename-posix.js pathext=/foo/bar/baz/asdf/quux.html
  ../node/node:          13,663,596 ops/sec ± 0.59% (96 runs sampled)
  ../node/node-pre-path:  1,549,371 ops/sec ± 0.16% (94 runs sampled)
                         781.88%
path/basename-posix.js pathext=/foo/bar/baz/asdf/quux.html|.html
  ../node/node:          7,961,870 ops/sec ± 0.09% (95 runs sampled)
  ../node/node-pre-path: 1,374,684 ops/sec ± 0.16% (98 runs sampled)
                         479.18%
path/basename-win32.js pathext=
  ../node/node:          45,771,412 ops/sec ± 0.03% (97 runs sampled)
  ../node/node-pre-path:  3,096,743 ops/sec ± 0.14% (97 runs sampled)
                         1378.05%
path/basename-win32.js pathext=C:\
  ../node/node:          17,226,481 ops/sec ± 0.04% (92 runs sampled)
  ../node/node-pre-path:  3,180,356 ops/sec ± 0.61% (92 runs sampled)
                         441.65%
path/basename-win32.js pathext=C:\foo
  ../node/node:          11,716,014 ops/sec ± 0.31% (95 runs sampled)
  ../node/node-pre-path:  3,312,445 ops/sec ± 0.14% (95 runs sampled)
                         253.70%
path/basename-win32.js pathext=D:\foo\.bar.baz
  ../node/node:          9,184,819 ops/sec ± 1.85% (92 runs sampled)
  ../node/node-pre-path: 2,205,723 ops/sec ± 0.15% (99 runs sampled)
                         316.41%
path/basename-win32.js pathext=E:\foo\.bar.baz|.baz
  ../node/node:          6,861,189 ops/sec ± 0.13% (96 runs sampled)
  ../node/node-pre-path: 1,957,168 ops/sec ± 0.15% (97 runs sampled)
                         250.57%
path/basename-win32.js pathext=foo
  ../node/node:          12,706,409 ops/sec ± 0.40% (92 runs sampled)
  ../node/node-pre-path:  3,966,611 ops/sec ± 0.16% (95 runs sampled)
                         220.33%
path/basename-win32.js pathext=foo\bar.
  ../node/node:          10,724,488 ops/sec ± 0.28% (95 runs sampled)
  ../node/node-pre-path:  2,689,211 ops/sec ± 0.14% (98 runs sampled)
                         298.80%
path/basename-win32.js pathext=foo\bar.|.
  ../node/node:          7,706,289 ops/sec ± 0.18% (96 runs sampled)
  ../node/node-pre-path: 2,298,846 ops/sec ± 0.15% (97 runs sampled)
                         235.22%
path/basename-win32.js pathext=\foo\bar\baz\asdf\quux.html
  ../node/node:          9,090,728 ops/sec ± 0.25% (96 runs sampled)
  ../node/node-pre-path: 1,295,009 ops/sec ± 0.15% (95 runs sampled)
                         601.98%
path/basename-win32.js pathext=\foo\bar\baz\asdf\quux.html|.html
  ../node/node:          6,632,323 ops/sec ± 0.14% (97 runs sampled)
  ../node/node-pre-path: 1,158,558 ops/sec ± 0.15% (91 runs sampled)
                         472.46%
path/dirname-posix.js path=
  ../node/node:          55,059,005 ops/sec ± 0.59% (87 runs sampled)
  ../node/node-pre-path:  5,321,086 ops/sec ± 0.17% (93 runs sampled)
                         934.73%
path/dirname-posix.js path=/
  ../node/node:          37,838,465 ops/sec ± 0.77% (94 runs sampled)
  ../node/node-pre-path:  6,474,682 ops/sec ± 0.17% (96 runs sampled)
                         484.41%
path/dirname-posix.js path=/foo
  ../node/node:          26,849,416 ops/sec ± 0.55% (95 runs sampled)
  ../node/node-pre-path:  5,823,122 ops/sec ± 0.18% (98 runs sampled)
                         361.08%
path/dirname-posix.js path=/foo/bar
  ../node/node:          16,414,602 ops/sec ± 0.54% (91 runs sampled)
  ../node/node-pre-path:  3,291,898 ops/sec ± 0.47% (96 runs sampled)
                         398.64%
path/dirname-posix.js path=foo
  ../node/node:          29,484,014 ops/sec ± 0.61% (92 runs sampled)
  ../node/node-pre-path:  6,056,988 ops/sec ± 0.21% (95 runs sampled)
                         386.78%
path/dirname-posix.js path=foo/bar
  ../node/node:          16,489,603 ops/sec ± 1.03% (95 runs sampled)
  ../node/node-pre-path:  3,386,368 ops/sec ± 0.42% (94 runs sampled)
                         386.94%
path/dirname-posix.js path=/foo/bar/baz/asdf/quux
  ../node/node:          11,147,310 ops/sec ± 0.35% (94 runs sampled)
  ../node/node-pre-path:  1,523,732 ops/sec ± 0.22% (93 runs sampled)
                         631.58%
path/dirname-win32.js path=
  ../node/node:          62,687,752 ops/sec ± 0.03% (96 runs sampled)
  ../node/node-pre-path:  3,066,329 ops/sec ± 0.16% (95 runs sampled)
                         1944.39%
path/dirname-win32.js path=\
  ../node/node:          33,103,317 ops/sec ± 2.05% (93 runs sampled)
  ../node/node-pre-path:  3,479,457 ops/sec ± 0.06% (98 runs sampled)
                         851.39%
path/dirname-win32.js path=\foo
  ../node/node:          13,075,376 ops/sec ± 0.47% (94 runs sampled)
  ../node/node-pre-path:  3,542,488 ops/sec ± 0.14% (98 runs sampled)
                         269.10%
path/dirname-win32.js path=C:\foo\bar
  ../node/node:          9,051,564 ops/sec ± 0.23% (93 runs sampled)
  ../node/node-pre-path: 2,178,129 ops/sec ± 0.15% (96 runs sampled)
                         315.57%
path/dirname-win32.js path=foo
  ../node/node:          11,300,394 ops/sec ± 0.16% (95 runs sampled)
  ../node/node-pre-path:  3,997,263 ops/sec ± 0.18% (93 runs sampled)
                         182.70%
path/dirname-win32.js path=foo\bar
  ../node/node:          10,695,293 ops/sec ± 1.02% (93 runs sampled)
  ../node/node-pre-path:  2,509,608 ops/sec ± 0.16% (95 runs sampled)
                         326.17%
path/dirname-win32.js path=D:\foo\bar\baz\asdf\quux
  ../node/node:          9,242,228 ops/sec ± 0.23% (96 runs sampled)
  ../node/node-pre-path: 1,230,252 ops/sec ± 0.15% (96 runs sampled)
                         651.25%
path/extname-posix.js path=
  ../node/node:          64,718,888 ops/sec ± 0.04% (98 runs sampled)
  ../node/node-pre-path:  5,411,089 ops/sec ± 0.14% (97 runs sampled)
                         1096.04%
path/extname-posix.js path=/
  ../node/node:          50,536,335 ops/sec ± 0.06% (90 runs sampled)
  ../node/node-pre-path:  6,815,041 ops/sec ± 0.40% (96 runs sampled)
                         641.54%
path/extname-posix.js path=/foo
  ../node/node:          27,596,471 ops/sec ± 0.04% (97 runs sampled)
  ../node/node-pre-path:  6,027,179 ops/sec ± 0.80% (94 runs sampled)
                         357.87%
path/extname-posix.js path=foo/.bar.baz
  ../node/node:          11,597,175 ops/sec ± 0.23% (97 runs sampled)
  ../node/node-pre-path:  3,390,424 ops/sec ± 0.44% (98 runs sampled)
                         242.06%
path/extname-posix.js path=index.html
  ../node/node:          10,441,960 ops/sec ± 0.20% (97 runs sampled)
  ../node/node-pre-path:  5,485,541 ops/sec ± 0.20% (97 runs sampled)
                         90.35%
path/extname-posix.js path=index
  ../node/node:          22,762,184 ops/sec ± 0.04% (95 runs sampled)
  ../node/node-pre-path:  5,736,498 ops/sec ± 0.18% (96 runs sampled)
                         296.80%
path/extname-posix.js path=foo/bar/..baz.quux
  ../node/node:          9,988,141 ops/sec ± 0.33% (96 runs sampled)
  ../node/node-pre-path: 2,051,812 ops/sec ± 0.16% (95 runs sampled)
                         386.80%
path/extname-posix.js path=foo/bar/...baz.quux
  ../node/node:          9,417,260 ops/sec ± 0.29% (96 runs sampled)
  ../node/node-pre-path: 1,930,838 ops/sec ± 0.16% (96 runs sampled)
                         387.73%
path/extname-posix.js path=/foo/bar/baz/asdf/quux
  ../node/node:          23,755,447 ops/sec ± 0.68% (97 runs sampled)
  ../node/node-pre-path:  1,582,612 ops/sec ± 0.16% (93 runs sampled)
                         1401.03%
path/extname-posix.js path=/foo/bar/baz/asdf/quux.foobarbazasdfquux
  ../node/node:          6,023,930 ops/sec ± 0.16% (99 runs sampled)
  ../node/node-pre-path: 1,550,081 ops/sec ± 0.14% (96 runs sampled)
                         288.62%
path/extname-win32.js path=
  ../node/node:          57,503,179 ops/sec ± 0.08% (95 runs sampled)
  ../node/node-pre-path:  3,105,339 ops/sec ± 0.05% (98 runs sampled)
                         1751.75%
path/extname-win32.js path=\
  ../node/node:          31,385,494 ops/sec ± 0.03% (95 runs sampled)
  ../node/node-pre-path:  3,560,714 ops/sec ± 0.14% (98 runs sampled)
                         781.44%
path/extname-win32.js path=C:\foo
  ../node/node:          26,465,478 ops/sec ± 0.10% (95 runs sampled)
  ../node/node-pre-path:  3,308,328 ops/sec ± 0.15% (95 runs sampled)
                         699.97%
path/extname-win32.js path=foo\.bar.baz
  ../node/node:          10,590,880 ops/sec ± 0.23% (97 runs sampled)
  ../node/node-pre-path:  2,511,747 ops/sec ± 0.15% (98 runs sampled)
                         321.65%
path/extname-win32.js path=index.html
  ../node/node:          9,381,397 ops/sec ± 0.29% (97 runs sampled)
  ../node/node-pre-path: 3,512,039 ops/sec ± 0.48% (92 runs sampled)
                         167.12%
path/extname-win32.js path=index
  ../node/node:          21,752,039 ops/sec ± 0.03% (97 runs sampled)
  ../node/node-pre-path:  3,712,206 ops/sec ± 0.35% (97 runs sampled)
                         485.96%
path/extname-win32.js path=foo\bar\..baz.quux
  ../node/node:          9,317,659 ops/sec ± 0.29% (96 runs sampled)
  ../node/node-pre-path: 1,670,002 ops/sec ± 0.22% (96 runs sampled)
                         457.94%
path/extname-win32.js path=foo\bar\...baz.quux
  ../node/node:          8,846,509 ops/sec ± 0.23% (97 runs sampled)
  ../node/node-pre-path: 1,569,641 ops/sec ± 0.19% (96 runs sampled)
                         463.60%
path/extname-win32.js path=D:\foo\bar\baz\asdf\quux
  ../node/node:          22,984,767 ops/sec ± 0.28% (96 runs sampled)
  ../node/node-pre-path:  1,278,575 ops/sec ± 0.15% (94 runs sampled)
                         1697.69%
path/extname-win32.js path=\foo\bar\baz\asdf\quux.foobarbazasdfquux
  ../node/node:          5,712,389 ops/sec ± 0.15% (97 runs sampled)
  ../node/node-pre-path: 1,271,562 ops/sec ± 0.28% (98 runs sampled)
                         349.24%
path/isAbsolute-posix.js path=
  ../node/node:          68,211,422 ops/sec ± 0.04% (94 runs sampled)
  ../node/node-pre-path: 66,947,064 ops/sec ± 0.08% (98 runs sampled)
                         1.89%
path/isAbsolute-posix.js path=.
  ../node/node:          60,753,713 ops/sec ± 0.03% (96 runs sampled)
  ../node/node-pre-path: 58,910,368 ops/sec ± 0.03% (94 runs sampled)
                         3.13%
path/isAbsolute-posix.js path=/foo/bar
  ../node/node:          59,111,832 ops/sec ± 3.06% (94 runs sampled)
  ../node/node-pre-path: 57,650,823 ops/sec ± 1.32% (94 runs sampled)
                         2.53%
path/isAbsolute-posix.js path=/baz/..
  ../node/node:          60,268,074 ops/sec ± 1.58% (95 runs sampled)
  ../node/node-pre-path: 57,994,453 ops/sec ± 0.04% (92 runs sampled)
                         3.92%
path/isAbsolute-posix.js path=bar/baz
  ../node/node:          60,757,826 ops/sec ± 0.03% (97 runs sampled)
  ../node/node-pre-path: 58,897,296 ops/sec ± 0.05% (96 runs sampled)
                         3.16%
path/isAbsolute-win32.js path=
  ../node/node:          62,676,445 ops/sec ± 0.04% (88 runs sampled)
  ../node/node-pre-path:  5,823,604 ops/sec ± 0.22% (98 runs sampled)
                         976.25%
path/isAbsolute-win32.js path=.
  ../node/node:          36,878,290 ops/sec ± 0.18% (95 runs sampled)
  ../node/node-pre-path:  8,100,070 ops/sec ± 0.22% (96 runs sampled)
                         355.28%
path/isAbsolute-win32.js path=//server
  ../node/node:          16,273,911 ops/sec ± 0.09% (96 runs sampled)
  ../node/node-pre-path:  5,605,427 ops/sec ± 0.16% (94 runs sampled)
                         190.32%
path/isAbsolute-win32.js path=C:\baz\..
  ../node/node:          16,309,467 ops/sec ± 0.12% (98 runs sampled)
  ../node/node-pre-path:  5,805,978 ops/sec ± 0.07% (97 runs sampled)
                         180.91%
path/isAbsolute-win32.js path=C:baz\..
  ../node/node:          16,133,592 ops/sec ± 0.90% (96 runs sampled)
  ../node/node-pre-path:  6,236,127 ops/sec ± 0.28% (93 runs sampled)
                         158.71%
path/isAbsolute-win32.js path=bar\baz
  ../node/node:          19,816,670 ops/sec ± 0.14% (93 runs sampled)
  ../node/node-pre-path:  7,383,730 ops/sec ± 0.16% (94 runs sampled)
                         168.38%
path/join-posix.js paths=/foo|bar||baz/asdf|quux|..
  ../node/node:          1,147,945 ops/sec ± 0.18% (94 runs sampled)
  ../node/node-pre-path:   444,986 ops/sec ± 0.26% (93 runs sampled)
                         157.97%
path/join-win32.js paths=
  ../node/node:          19,299,094 ops/sec ± 0.67% (92 runs sampled)
  ../node/node-pre-path:  1,657,372 ops/sec ± 0.48% (96 runs sampled)
                         1064.44%
path/join-win32.js paths=|
  ../node/node:          16,784,888 ops/sec ± 0.45% (94 runs sampled)
  ../node/node-pre-path:  1,690,413 ops/sec ± 0.41% (92 runs sampled)
                         892.95%
path/join-win32.js paths=C:\foo|bar||baz\asdf|quux|..
  ../node/node:          1,151,258 ops/sec ± 0.23% (96 runs sampled)
  ../node/node-pre-path:   280,403 ops/sec ± 0.21% (94 runs sampled)
                         310.57%
path/join-win32.js paths=//server|share
  ../node/node:          2,809,417 ops/sec ± 0.52% (97 runs sampled)
  ../node/node-pre-path:   429,884 ops/sec ± 0.32% (95 runs sampled)
                         553.53%
path/makeLong-win32.js path=foo\bar
  ../node/node:          966,520 ops/sec ± 0.43% (98 runs sampled)
  ../node/node-pre-path: 210,928 ops/sec ± 0.17% (98 runs sampled)
                         358.22%
path/makeLong-win32.js path=C:\foo
  ../node/node:          4,083,005 ops/sec ± 0.18% (97 runs sampled)
  ../node/node-pre-path:   789,913 ops/sec ± 0.33% (95 runs sampled)
                         416.89%
path/makeLong-win32.js path=\\foo\bar
  ../node/node:          3,371,488 ops/sec ± 0.09% (98 runs sampled)
  ../node/node-pre-path:   469,272 ops/sec ± 0.25% (92 runs sampled)
                         618.45%
path/makeLong-win32.js path=\\?\foo
  ../node/node:          4,156,203 ops/sec ± 0.16% (97 runs sampled)
  ../node/node-pre-path:   488,108 ops/sec ± 0.22% (96 runs sampled)
                         751.49%
path/normalize-posix.js path=
  ../node/node:          62,322,348 ops/sec ± 0.49% (92 runs sampled)
  ../node/node-pre-path:  4,106,707 ops/sec ± 1.36% (92 runs sampled)
                         1417.57%
path/normalize-posix.js path=.
  ../node/node:          15,269,539 ops/sec ± 0.18% (96 runs sampled)
  ../node/node-pre-path:  4,074,758 ops/sec ± 1.28% (90 runs sampled)
                         274.73%
path/normalize-posix.js path=/../
  ../node/node:          11,631,669 ops/sec ± 0.08% (98 runs sampled)
  ../node/node-pre-path:  3,737,792 ops/sec ± 1.28% (93 runs sampled)
                         211.19%
path/normalize-posix.js path=/foo
  ../node/node:          8,492,295 ops/sec ± 0.28% (95 runs sampled)
  ../node/node-pre-path: 3,263,140 ops/sec ± 0.90% (93 runs sampled)
                         160.25%
path/normalize-posix.js path=/foo/bar
  ../node/node:          5,176,713 ops/sec ± 0.32% (94 runs sampled)
  ../node/node-pre-path:   842,729 ops/sec ± 0.34% (94 runs sampled)
                         514.28%
path/normalize-posix.js path=/foo/bar//baz/asdf/quux/..
  ../node/node:          1,884,575 ops/sec ± 0.59% (92 runs sampled)
  ../node/node-pre-path:   850,966 ops/sec ± 0.28% (93 runs sampled)
                         121.46%
path/normalize-win32.js path=
  ../node/node:          62,710,064 ops/sec ± 0.04% (94 runs sampled)
  ../node/node-pre-path:  2,284,844 ops/sec ± 0.36% (93 runs sampled)
                         2644.61%
path/normalize-win32.js path=.
  ../node/node:          10,685,028 ops/sec ± 0.18% (97 runs sampled)
  ../node/node-pre-path:  2,410,632 ops/sec ± 0.36% (91 runs sampled)
                         343.25%
path/normalize-win32.js path=C:\..\
  ../node/node:          5,228,664 ops/sec ± 0.18% (98 runs sampled)
  ../node/node-pre-path: 1,708,049 ops/sec ± 0.43% (94 runs sampled)
                         206.12%
path/normalize-win32.js path=C:\foo
  ../node/node:          4,597,329 ops/sec ± 0.17% (94 runs sampled)
  ../node/node-pre-path: 1,846,776 ops/sec ± 0.46% (94 runs sampled)
                         148.94%
path/normalize-win32.js path=C:\foo\bar
  ../node/node:          3,391,409 ops/sec ± 0.15% (98 runs sampled)
  ../node/node-pre-path:   568,832 ops/sec ± 0.27% (95 runs sampled)
                         496.21%
path/normalize-win32.js path=C:\foo\bar\\baz\asdf\quux\..
  ../node/node:          1,549,669 ops/sec ± 0.47% (93 runs sampled)
  ../node/node-pre-path:   512,726 ops/sec ± 0.22% (97 runs sampled)
                         202.24%
path/parse-posix.js path=
  ../node/node:          51,725,940 ops/sec ± 0.17% (94 runs sampled)
  ../node/node-pre-path:  3,962,238 ops/sec ± 0.23% (94 runs sampled)
                         1205.47%
path/parse-posix.js path=/
  ../node/node:          22,631,316 ops/sec ± 0.65% (93 runs sampled)
  ../node/node-pre-path:  4,599,338 ops/sec ± 0.13% (92 runs sampled)
                         392.06%
path/parse-posix.js path=/foo
  ../node/node:          9,822,464 ops/sec ± 0.16% (91 runs sampled)
  ../node/node-pre-path: 4,204,710 ops/sec ± 0.15% (94 runs sampled)
                         133.61%
path/parse-posix.js path=/foo/bar.baz
  ../node/node:          4,551,479 ops/sec ± 0.31% (92 runs sampled)
  ../node/node-pre-path: 2,689,473 ops/sec ± 0.14% (96 runs sampled)
                         69.23%
path/parse-posix.js path=foo/.bar.baz
  ../node/node:          4,675,828 ops/sec ± 0.23% (97 runs sampled)
  ../node/node-pre-path: 2,536,967 ops/sec ± 0.14% (95 runs sampled)
                         84.31%
path/parse-posix.js path=foo/bar
  ../node/node:          7,957,977 ops/sec ± 0.16% (96 runs sampled)
  ../node/node-pre-path: 2,836,123 ops/sec ± 0.45% (94 runs sampled)
                         180.59%
path/parse-posix.js path=/foo/bar/baz/asdf/.quux
  ../node/node:          6,909,367 ops/sec ± 0.11% (97 runs sampled)
  ../node/node-pre-path: 1,385,578 ops/sec ± 0.13% (96 runs sampled)
                         398.66%
path/parse-win32.js path=
  ../node/node:          51,876,610 ops/sec ± 0.15% (92 runs sampled)
  ../node/node-pre-path:  2,571,702 ops/sec ± 0.19% (98 runs sampled)
                         1917.21%
path/parse-win32.js path=C:\
  ../node/node:          10,228,188 ops/sec ± 0.24% (95 runs sampled)
  ../node/node-pre-path:  2,599,189 ops/sec ± 0.30% (97 runs sampled)
                         293.51%
path/parse-win32.js path=C:\foo
  ../node/node:          4,879,112 ops/sec ± 0.13% (97 runs sampled)
  ../node/node-pre-path: 2,694,691 ops/sec ± 0.14% (98 runs sampled)
                         81.06%
path/parse-win32.js path=\foo
  ../node/node:          7,368,074 ops/sec ± 0.14% (97 runs sampled)
  ../node/node-pre-path: 2,892,543 ops/sec ± 0.14% (97 runs sampled)
                         154.73%
path/parse-win32.js path=E:\foo\bar.baz
  ../node/node:          3,451,330 ops/sec ± 0.15% (96 runs sampled)
  ../node/node-pre-path: 1,893,949 ops/sec ± 0.15% (97 runs sampled)
                         82.23%
path/parse-win32.js path=foo\.bar.baz
  ../node/node:          4,123,900 ops/sec ± 0.25% (91 runs sampled)
  ../node/node-pre-path: 2,080,935 ops/sec ± 0.18% (98 runs sampled)
                         98.18%
path/parse-win32.js path=foo\bar
  ../node/node:          6,513,933 ops/sec ± 0.18% (96 runs sampled)
  ../node/node-pre-path: 2,264,710 ops/sec ± 0.14% (96 runs sampled)
                         187.63%
path/parse-win32.js path=\foo\bar\baz\asdf\.quux
  ../node/node:          6,494,671 ops/sec ± 0.12% (95 runs sampled)
  ../node/node-pre-path: 1,185,057 ops/sec ± 0.15% (95 runs sampled)
                         448.05%
path/relative-posix.js paths=/data/orandea/test/aaa|/data/orandea/impl/bbb
  ../node/node:          719,967 ops/sec ± 0.17% (98 runs sampled)
  ../node/node-pre-path: 138,392 ops/sec ± 0.19% (94 runs sampled)
                         420.24%
path/relative-posix.js paths=/|/var
  ../node/node:          3,664,820 ops/sec ± 0.58% (95 runs sampled)
  ../node/node-pre-path:   440,914 ops/sec ± 0.34% (93 runs sampled)
                         731.19%
path/relative-posix.js paths=/|/
  ../node/node:          67,000,769 ops/sec ± 0.05% (95 runs sampled)
  ../node/node-pre-path:    556,765 ops/sec ± 0.30% (95 runs sampled)
                         11933.94%
path/relative-posix.js paths=/var|/bin
  ../node/node:          2,614,903 ops/sec ± 0.13% (98 runs sampled)
  ../node/node-pre-path:   256,215 ops/sec ± 0.19% (96 runs sampled)
                         920.59%
path/relative-posix.js paths=/foo/bar/baz/quux|/
  ../node/node:          1,241,799 ops/sec ± 0.32% (95 runs sampled)
  ../node/node-pre-path:   181,497 ops/sec ± 0.19% (94 runs sampled)
                         584.20%
path/relative-posix.js paths=/foo/bar/baz/quux|/foo/bar/baz/quux
  ../node/node:          19,834,969 ops/sec ± 1.39% (97 runs sampled)
  ../node/node-pre-path:    165,904 ops/sec ± 0.17% (97 runs sampled)
                         11855.69%
path/relative-posix.js paths=/foo/bar/baz/quux|/var/log
  ../node/node:          993,357 ops/sec ± 0.19% (94 runs sampled)
  ../node/node-pre-path: 142,777 ops/sec ± 0.15% (93 runs sampled)
                         595.74%
path/relative-win32.js paths=C:\orandea\test\aaa|C:\orandea\impl\bbb
  ../node/node:          709,544 ops/sec ± 0.19% (95 runs sampled)
  ../node/node-pre-path:  89,223 ops/sec ± 0.08% (94 runs sampled)
                         695.25%
path/relative-win32.js paths=C:\|D:\
  ../node/node:          2,403,766 ops/sec ± 0.15% (98 runs sampled)
  ../node/node-pre-path:   215,161 ops/sec ± 0.16% (96 runs sampled)
                         1017.19%
path/relative-win32.js paths=C:\foo\bar\baz|C:\foo\bar\baz
  ../node/node:          20,121,868 ops/sec ± 0.34% (95 runs sampled)
  ../node/node-pre-path:    109,693 ops/sec ± 0.20% (98 runs sampled)
                         18243.84%
path/relative-win32.js paths=C:\foo\BAR\BAZ|C:\foo\bar\baz
  ../node/node:          1,048,353 ops/sec ± 0.31% (97 runs sampled)
  ../node/node-pre-path:   112,641 ops/sec ± 0.09% (95 runs sampled)
                         830.71%
path/relative-win32.js paths=C:\foo\bar\baz\quux|C:\
  ../node/node:          972,323 ops/sec ± 0.34% (95 runs sampled)
  ../node/node-pre-path: 103,457 ops/sec ± 0.23% (96 runs sampled)
                         839.84%
path/resolve-posix.js paths=
  ../node/node:          1,302,790 ops/sec ± 0.27% (97 runs sampled)
  ../node/node-pre-path:   409,326 ops/sec ± 0.28% (94 runs sampled)
                         218.28%
path/resolve-posix.js paths=|
  ../node/node:          1,295,471 ops/sec ± 0.39% (94 runs sampled)
  ../node/node-pre-path:   405,510 ops/sec ± 0.25% (94 runs sampled)
                         219.47%
path/resolve-posix.js paths=foo/bar|/tmp/file/|..|a/../subfile
  ../node/node:          1,390,770 ops/sec ± 0.43% (94 runs sampled)
  ../node/node-pre-path:   470,475 ops/sec ± 0.23% (94 runs sampled)
                         195.61%
path/resolve-posix.js paths=a/b/c/|../../..
  ../node/node:          777,494 ops/sec ± 0.27% (96 runs sampled)
  ../node/node-pre-path: 349,649 ops/sec ± 0.28% (94 runs sampled)
                         122.36%
path/resolve-win32.js paths=
  ../node/node:          1,234,473 ops/sec ± 0.36% (97 runs sampled)
  ../node/node-pre-path:   248,446 ops/sec ± 0.34% (93 runs sampled)
                         396.88%
path/resolve-win32.js paths=|
  ../node/node:          1,254,651 ops/sec ± 0.32% (95 runs sampled)
  ../node/node-pre-path:   244,289 ops/sec ± 0.22% (97 runs sampled)
                         413.59%
path/resolve-win32.js paths=c:/ignore|d:\a/b\c/d|\e.exe
  ../node/node:          3,226,369 ops/sec ± 0.20% (95 runs sampled)
  ../node/node-pre-path:   795,161 ops/sec ± 0.32% (94 runs sampled)
                         305.75%
path/resolve-win32.js paths=c:/blah\blah|d:/games|c:../a
  ../node/node:          1,289,325 ops/sec ± 0.34% (95 runs sampled)
  ../node/node-pre-path:   240,762 ops/sec ± 0.15% (95 runs sampled)
                         435.52%

The | in some of the benchmark inputs is a delimiter to be able to pass multiple arguments to the function being benchmarked.

This commit splits each path benchmark into separate posix and
Windows benchmark files. This allows benchmarking (platform-)specific
inputs against specific platforms (only).
This commit adds new tests, executes tests for other platforms
instead of limiting platform-specific tests to those platforms,
and fixes a few style/formatting inconsistencies.
@mscdex
Copy link
Contributor Author

mscdex commented Feb 6, 2016

CI is green except for some flaky tests on ARM: https://ci.nodejs.org/job/node-test-commit/2132/

@mscdex mscdex added the path Issues and PRs related to the path subsystem. label Feb 6, 2016
@evanlucas
Copy link
Contributor

Wow. Thanks @mscdex. I wonder if this brings any performance improvements to require as well.

@Fishrock123
Copy link
Contributor

Is the diff not showing up for anyone else?

This commit significantly improves performance of all path functions.

Optimization strategies include:
* Replacing regexps with manual parsers
* Avoiding unnecessary array creation (including split() + join())
* Returning earlier where possible to avoid unnecessary work
* Minimize unnecessary string creation and concatenations
* Combining string iterations
@mscdex
Copy link
Contributor Author

mscdex commented Feb 6, 2016

@evanlucas I just ran the misc/module-loader benchmark several times and I see ~17-35% improvement there.

@jasnell
Copy link
Member

jasnell commented Feb 7, 2016

Nice. Bit difficult to review given the amount of change. I assume there are no API changes?

@jasnell
Copy link
Member

jasnell commented Feb 7, 2016

Marking this don't land on v4 for now... this is definitely one that we'd want to prove out for a while before backporting.

@mscdex
Copy link
Contributor Author

mscdex commented Feb 7, 2016

@jasnell With regard to API changes, these changes should be 100% backwards compatible. It passes all tests, including additional tests that this PR adds. citgm tests would be nice but from what I understand those are a bit cumbersome to do at the moment because npm is broken to some degree in master currently?

@jasnell
Copy link
Member

jasnell commented Feb 7, 2016

LGTM given that CI is green :-) great work

@mathiasbynens
Copy link
Contributor

👍

these results were obtained from a benchmark.js-based benchmark runner I'm working on

I’d be interested in the runner as well. Is it open-source?

@mscdex
Copy link
Contributor Author

mscdex commented Feb 8, 2016

@mathiasbynens Not yet, it's still a work-in-progress. I'm still trying to get benchmark.js to be flexible enough to be used for the (more complex) async benchmarks node currently has. It works great for the synchronous stuff (like the path tests) though.

@silverwind
Copy link
Contributor

LGTM pending another CI run: https://ci.nodejs.org/job/node-test-pull-request/1587/

jasnell pushed a commit that referenced this pull request Feb 10, 2016
PR-URL: #5123
Reviewed-By: Roman Reiss <[email protected]>
Reviewed-By: James M Snell <[email protected]>
jasnell pushed a commit that referenced this pull request Feb 10, 2016
This commit splits each path benchmark into separate posix and
Windows benchmark files. This allows benchmarking (platform-)specific
inputs against specific platforms (only).

PR-URL: #5123
Reviewed-By: Roman Reiss <[email protected]>
Reviewed-By: James M Snell <[email protected]>
jasnell pushed a commit that referenced this pull request Feb 10, 2016
This commit adds new tests, executes tests for other platforms
instead of limiting platform-specific tests to those platforms,
and fixes a few style/formatting inconsistencies.

PR-URL: #5123
Reviewed-By: Roman Reiss <[email protected]>
Reviewed-By: James M Snell <[email protected]>
jasnell pushed a commit that referenced this pull request Feb 10, 2016
This commit significantly improves performance of all path functions.

Optimization strategies include:
* Replacing regexps with manual parsers
* Avoiding unnecessary array creation (including split() + join())
* Returning earlier where possible to avoid unnecessary work
* Minimize unnecessary string creation and concatenations
* Combining string iterations

PR-URL: #5123
Reviewed-By: Roman Reiss <[email protected]>
Reviewed-By: James M Snell <[email protected]>
@jasnell
Copy link
Member

jasnell commented Feb 10, 2016

Landed in 72d0f88, e1348b0, 5a54e45 and b212be0

@jasnell jasnell closed this Feb 10, 2016
@Fishrock123
Copy link
Contributor

@thealphanerd you should probably citgm this.

@mscdex mscdex deleted the perf-path branch February 13, 2016 01:32
rvagg pushed a commit that referenced this pull request Feb 15, 2016
PR-URL: #5123
Reviewed-By: Roman Reiss <[email protected]>
Reviewed-By: James M Snell <[email protected]>
rvagg pushed a commit that referenced this pull request Feb 15, 2016
This commit splits each path benchmark into separate posix and
Windows benchmark files. This allows benchmarking (platform-)specific
inputs against specific platforms (only).

PR-URL: #5123
Reviewed-By: Roman Reiss <[email protected]>
Reviewed-By: James M Snell <[email protected]>
rvagg pushed a commit that referenced this pull request Feb 15, 2016
This commit adds new tests, executes tests for other platforms
instead of limiting platform-specific tests to those platforms,
and fixes a few style/formatting inconsistencies.

PR-URL: #5123
Reviewed-By: Roman Reiss <[email protected]>
Reviewed-By: James M Snell <[email protected]>
@rvagg
Copy link
Member

rvagg commented Feb 15, 2016

Cherry pick is fine, it's just these annoying error message format updates that have messed things up, manually working around them is not hard though so no need for another PR, I'll deal with it when it lands

@MylesBorins
Copy link
Contributor

ah ok cool. I'm multi-tasking like mad now and was just doing sanity checks without diving to far in. Thanks for taking the time

@rvagg rvagg removed the semver-major PRs that contain breaking changes and should be released in the next major version. label Feb 18, 2016
@rvagg
Copy link
Member

rvagg commented Feb 18, 2016

removed semver-major label

rvagg added a commit that referenced this pull request Feb 21, 2016
* buffer:
  - You can now supply an encoding argument when filling a
    Buffer Buffer#fill(string[, start[, end]][, encoding]), supplying
    an existing Buffer will also work with
    Buffer#fill(buffer[, start[, end]]). See the API documentation for
    details on how this works. (Trevor Norris) #4935
  - Buffer#indexOf() no longer requires a byteOffset argument if you
    also wish to specify an encoding:
    Buffer#indexOf(val[, byteOffset][, encoding]).
    (Trevor Norris) #4803
* child_process: spawn() and spawnSync() now support a 'shell' option
  to allow for optional execution of the given command inside a shell.
  If set to true, cmd.exe will be used on Windows and /bin/sh
  elsewhere. A path to a custom shell can also be passed to override
  these defaults. On Windows, this option allows .bat. and .cmd files
  to be executed with spawn() and spawnSync(). (Colin Ihrig) #4598
* http_parser: Update to http-parser 2.6.2 to fix an unintentionally
  strict limitation of allowable header characters.
  (James M Snell) #5237
* dgram: socket.send() now supports accepts an array of Buffers or
  Strings as the first argument. See the API docs for details on how
  this works. (Matteo Collina) #4374
* http: Fix a bug where handling headers will mistakenly trigger an
  'upgrade' event where the server is just advertising its protocols.
  This bug can prevent HTTP clients from communicating with HTTP/2
  enabled servers. (Fedor Indutny) #4337
* net: Added a listening Boolean property to net and http servers to
  indicate whether the server is listening for connections.
  (José Moreira) #4743
* node: The C++ node::MakeCallback() API is now reentrant and calling
  it from inside another MakeCallback() call no longer causes the
  nextTick queue or Promises microtask queue to be processed out of
  order. (Trevor Norris) #4507
* tls: Add a new tlsSocket.getProtocol() method to get the negotiated
  TLS protocol version of the current connection. (Brian White) #4995
* vm: Introduce new 'produceCachedData' and 'cachedData' options to
  new vm.Script() to interact with V8's code cache. When a new
  vm.Script object is created with the 'produceCachedData' set to true
  a Buffer with V8's code cache data will be produced and stored in
  cachedData property of the returned object. This data in turn may be
  supplied back to another vm.Script() object with a 'cachedData'
  option if the supplied source is the same. Successfully executing a
  script from cached data can speed up instantiation time. See the API
  docs for details. (Fedor Indutny) #4777
* performance: Improvements in:
  - process.nextTick() (Ruben Bridgewater) #5092
  - path module (Brian White) #5123
  - querystring module (Brian White) #5012
  - streams module when processing small chunks (Matteo Collina) #4354
rvagg added a commit that referenced this pull request Feb 21, 2016
* buffer:
  - You can now supply an encoding argument when filling a
    Buffer Buffer#fill(string[, start[, end]][, encoding]), supplying
    an existing Buffer will also work with
    Buffer#fill(buffer[, start[, end]]). See the API documentation for
    details on how this works. (Trevor Norris) #4935
  - Buffer#indexOf() no longer requires a byteOffset argument if you
    also wish to specify an encoding:
    Buffer#indexOf(val[, byteOffset][, encoding]).
    (Trevor Norris) #4803
* child_process: spawn() and spawnSync() now support a 'shell' option
  to allow for optional execution of the given command inside a shell.
  If set to true, cmd.exe will be used on Windows and /bin/sh
  elsewhere. A path to a custom shell can also be passed to override
  these defaults. On Windows, this option allows .bat. and .cmd files
  to be executed with spawn() and spawnSync(). (Colin Ihrig) #4598
* http_parser: Update to http-parser 2.6.2 to fix an unintentionally
  strict limitation of allowable header characters.
  (James M Snell) #5237
* dgram: socket.send() now supports accepts an array of Buffers or
  Strings as the first argument. See the API docs for details on how
  this works. (Matteo Collina) #4374
* http: Fix a bug where handling headers will mistakenly trigger an
  'upgrade' event where the server is just advertising its protocols.
  This bug can prevent HTTP clients from communicating with HTTP/2
  enabled servers. (Fedor Indutny) #4337
* net: Added a listening Boolean property to net and http servers to
  indicate whether the server is listening for connections.
  (José Moreira) #4743
* node: The C++ node::MakeCallback() API is now reentrant and calling
  it from inside another MakeCallback() call no longer causes the
  nextTick queue or Promises microtask queue to be processed out of
  order. (Trevor Norris) #4507
* tls: Add a new tlsSocket.getProtocol() method to get the negotiated
  TLS protocol version of the current connection. (Brian White) #4995
* vm: Introduce new 'produceCachedData' and 'cachedData' options to
  new vm.Script() to interact with V8's code cache. When a new
  vm.Script object is created with the 'produceCachedData' set to true
  a Buffer with V8's code cache data will be produced and stored in
  cachedData property of the returned object. This data in turn may be
  supplied back to another vm.Script() object with a 'cachedData'
  option if the supplied source is the same. Successfully executing a
  script from cached data can speed up instantiation time. See the API
  docs for details. (Fedor Indutny) #4777
* performance: Improvements in:
  - process.nextTick() (Ruben Bridgewater) #5092
  - path module (Brian White) #5123
  - querystring module (Brian White) #5012
  - streams module when processing small chunks (Matteo Collina) #4354
rvagg added a commit that referenced this pull request Feb 23, 2016
* buffer:
  - You can now supply an encoding argument when filling a
    Buffer Buffer#fill(string[, start[, end]][, encoding]), supplying
    an existing Buffer will also work with
    Buffer#fill(buffer[, start[, end]]). See the API documentation for
    details on how this works. (Trevor Norris) #4935
  - Buffer#indexOf() no longer requires a byteOffset argument if you
    also wish to specify an encoding:
    Buffer#indexOf(val[, byteOffset][, encoding]).
    (Trevor Norris) #4803
* child_process: spawn() and spawnSync() now support a 'shell' option
  to allow for optional execution of the given command inside a shell.
  If set to true, cmd.exe will be used on Windows and /bin/sh
  elsewhere. A path to a custom shell can also be passed to override
  these defaults. On Windows, this option allows .bat. and .cmd files
  to be executed with spawn() and spawnSync(). (Colin Ihrig) #4598
* http_parser: Update to http-parser 2.6.2 to fix an unintentionally
  strict limitation of allowable header characters.
  (James M Snell) #5237
* dgram: socket.send() now supports accepts an array of Buffers or
  Strings as the first argument. See the API docs for details on how
  this works. (Matteo Collina) #4374
* http: Fix a bug where handling headers will mistakenly trigger an
  'upgrade' event where the server is just advertising its protocols.
  This bug can prevent HTTP clients from communicating with HTTP/2
  enabled servers. (Fedor Indutny) #4337
* net: Added a listening Boolean property to net and http servers to
  indicate whether the server is listening for connections.
  (José Moreira) #4743
* node: The C++ node::MakeCallback() API is now reentrant and calling
  it from inside another MakeCallback() call no longer causes the
  nextTick queue or Promises microtask queue to be processed out of
  order. (Trevor Norris) #4507
* tls: Add a new tlsSocket.getProtocol() method to get the negotiated
  TLS protocol version of the current connection. (Brian White) #4995
* vm: Introduce new 'produceCachedData' and 'cachedData' options to
  new vm.Script() to interact with V8's code cache. When a new
  vm.Script object is created with the 'produceCachedData' set to true
  a Buffer with V8's code cache data will be produced and stored in
  cachedData property of the returned object. This data in turn may be
  supplied back to another vm.Script() object with a 'cachedData'
  option if the supplied source is the same. Successfully executing a
  script from cached data can speed up instantiation time. See the API
  docs for details. (Fedor Indutny) #4777
* performance: Improvements in:
  - process.nextTick() (Ruben Bridgewater) #5092
  - path module (Brian White) #5123
  - querystring module (Brian White) #5012
  - streams module when processing small chunks (Matteo Collina) #4354

PR-URL: #5295
@geek
Copy link
Member

geek commented Feb 23, 2016

Related issue:

#5383

@mscdex
Copy link
Contributor Author

mscdex commented Feb 23, 2016

@geek #5393 is not related.

@geek
Copy link
Member

geek commented Feb 23, 2016

@mscdex oops, its related to #4892 instead... I will update

rvagg added a commit that referenced this pull request Feb 24, 2016
* buffer:
  - You can now supply an encoding argument when filling a
    Buffer Buffer#fill(string[, start[, end]][, encoding]), supplying
    an existing Buffer will also work with
    Buffer#fill(buffer[, start[, end]]). See the API documentation for
    details on how this works. (Trevor Norris) #4935
  - Buffer#indexOf() no longer requires a byteOffset argument if you
    also wish to specify an encoding:
    Buffer#indexOf(val[, byteOffset][, encoding]).
    (Trevor Norris) #4803
* child_process: spawn() and spawnSync() now support a 'shell' option
  to allow for optional execution of the given command inside a shell.
  If set to true, cmd.exe will be used on Windows and /bin/sh
  elsewhere. A path to a custom shell can also be passed to override
  these defaults. On Windows, this option allows .bat. and .cmd files
  to be executed with spawn() and spawnSync(). (Colin Ihrig) #4598
* http_parser: Update to http-parser 2.6.2 to fix an unintentionally
  strict limitation of allowable header characters.
  (James M Snell) #5237
* dgram: socket.send() now supports accepts an array of Buffers or
  Strings as the first argument. See the API docs for details on how
  this works. (Matteo Collina) #4374
* http: Fix a bug where handling headers will mistakenly trigger an
  'upgrade' event where the server is just advertising its protocols.
  This bug can prevent HTTP clients from communicating with HTTP/2
  enabled servers. (Fedor Indutny) #4337
* net: Added a listening Boolean property to net and http servers to
  indicate whether the server is listening for connections.
  (José Moreira) #4743
* node: The C++ node::MakeCallback() API is now reentrant and calling
  it from inside another MakeCallback() call no longer causes the
  nextTick queue or Promises microtask queue to be processed out of
  order. (Trevor Norris) #4507
* tls: Add a new tlsSocket.getProtocol() method to get the negotiated
  TLS protocol version of the current connection. (Brian White) #4995
* vm: Introduce new 'produceCachedData' and 'cachedData' options to
  new vm.Script() to interact with V8's code cache. When a new
  vm.Script object is created with the 'produceCachedData' set to true
  a Buffer with V8's code cache data will be produced and stored in
  cachedData property of the returned object. This data in turn may be
  supplied back to another vm.Script() object with a 'cachedData'
  option if the supplied source is the same. Successfully executing a
  script from cached data can speed up instantiation time. See the API
  docs for details. (Fedor Indutny) #4777
* performance: Improvements in:
  - process.nextTick() (Ruben Bridgewater) #5092
  - path module (Brian White) #5123
  - querystring module (Brian White) #5012
  - streams module when processing small chunks (Matteo Collina) #4354

PR-URL: #5295
@eggggger
Copy link

v5.7
> path.relative('app/index.js', '.') '../../../yadan'
v5.6
> path.relative('app/index.js', '.') '../..'
???

@evanlucas
Copy link
Contributor

@eggggger that is fixed by #5389. A release with the fix should be going out soon. Thanks!

@eggggger
Copy link

:) Thanks @evanlucas

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
path Issues and PRs related to the path subsystem.
Projects
None yet
Development

Successfully merging this pull request may close these issues.