-
Notifications
You must be signed in to change notification settings - Fork 7.3k
path: refactor for performance and consistency #9289
Conversation
@woollybogger ... do you have benchmark numbers showing that this provides a net performance improvement? The nature of the changes would indicate an improvement but numbers always help :-). |
bbe4a0c
to
1b25d91
Compare
@jasnell I updated the PR description with benchmark data. I only included the functions that had a >1% change in performance. |
It's been over a week so...bump? |
@woollybogger ... sorry, was catching up on a few other items. Thanks for the profiling numbers. I'll queue this up to review on Monday. // cc @joyent/node-coreteam ... can one of you take a look as well? |
Generally LGTM. But let's run this on the servers and make sure all tests pass on all platforms. |
var lastIndex = arr.length - 1; | ||
var start = 0; | ||
for (; start <= lastIndex; start++) { | ||
if (arr[start]) break; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please move break
to the next line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch! I forgot that's the coding style.
isUnc = device && device.charAt(1) !== ':', | ||
isAbsolute = win32.isAbsolute(path), | ||
isUnc = device && device[1] !== ':', | ||
isAbsolute = isUnc || result[2], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not a big fan on inlining the call to win32.isAbsolute
here and in win32.normalize
. I'm concerned that we could get to a point where win32.isAbsolute
and these inline versions diverge.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could have another function similar to win32SplitPath
that returns the following properties:
device
isUnc
isAbsolute
tail
Also, is there any reason why win32SplitPath
returns an array? I feel like the code would be more readable if it returned an object instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I'm guessing the answer to my question ^ is so that win32SplitPath
returns the same data structure as posixSplitPath
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@misterdjules Are things good enough inline or should there be a helper function such as the one I outlined above? I tested Node with the changes in the PR against a version with the helper function and it does slow things down a little (about 2% to 5% slower for the functions the helper touches).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unless win32.isAbsolute
is on the critical path of a very common use case in terms of performance, I have a preference for using a helper function such as the one you described in your comment above.
I want to avoid subtle regressions due to potential divergence between several versions of inlined win32.isAbsolute
.
@woollybogger @trevnorris @jasnell Added a comment inline. Thoughts? |
I know the damage has already been done, but one of the objections I have against exposing the unix code on windows and vice versa is that Does anyone have an idea for fixing this. Maybe throw if the path is relative? |
@piscisaureus I'm not sure I understand what you're saying, could you please give us an example of what you're describing? |
I don't know what would happen if you did the opposite on unix, e.g.
But I am sure the results would not make sense. |
@piscisaureus OK thank you for the clarification!
work as expected because they are absolute paths, but like you said It seems that only Anyway, I think this should be handled outside of this PR and in my opinion it's worth creating a new issue. Do you want to do that @piscisaureus or should I do it? Thank you again! |
Ah, oops, you're right. Agreed btw that I should be handled in a separate issue. |
@piscisaureus created new issue here: #9430. |
7abada1
to
b770526
Compare
@misterdjules @jasnell Updated with the helper function as discussed here and updated the benchmark data. |
if (dir) { | ||
if (dir[dir.length - 1] === win32.sep) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this change (moving the check inside if (dir)
) fixes a bug where sometime dir
would be undefined and thus the code would throw? If so, then it would be great to add at least a test for that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I can think of at least two test cases that this fixes. I'll add some tests tonight.
Could you please take a look at my comment? Otherwise, LGTM. Thanks @woollybogger! 👍 Adding to the 0.12.2 milestone as node v0.12.1 will be a security release following the recent OpenSSL releases. |
@roryrjb You wrote the |
@woollybogger no, there's no reason I can think of, it can be removed. |
@roryrjb Cool, thanks! 👍 |
@misterdjules Ran into a little snag when writing tests: path.posix.format({root:'', dir: 'dir/other dir/', base: 'index.html'});
// -> 'dir/other dir//index.html'
path.win32.format({root:'', dir: 'dir\\other dir\\', base: 'index.html'});
// -> 'dir\\other dir\\index.html' The path.format(path.parse(input)) === input; // true for all |
@woollybogger If we want to make changes to Thank you very much again! |
@misterdjules Added a new commit with the tests and a couple other changes related to |
Thank you again @woollybogger. Added some comments, please let me know what you think. For some of the more controversial changes, we can always tackle them later in separate PRs. That way we can land the improvements you already made to the path's module performance and take more time to discuss the rest. |
Improve performance by: + Not leaking the `arguments` object! + Getting the last character of a string by index, instead of with `.substr()` or `.slice()` Improve code consistency by: + Using `[]` instead of `.charAt()` where possible + Using a function declaration instead of a var declaration + Using `.slice()` with clearer arguments + Checking if `dir` is truthy in `win32.format` (added tests for this) Improve both by: + Making the reusable `trimArray()` function + Standardizing getting certain path statistics with the new `win32StatPath()` function
@misterdjules I removed the controversial code and squashed into one commit. |
@woollybogger LGTM, thank you very much! 👍 |
Improve performance by: + Not leaking the `arguments` object! + Getting the last character of a string by index, instead of with `.substr()` or `.slice()` Improve code consistency by: + Using `[]` instead of `.charAt()` where possible + Using a function declaration instead of a var declaration + Using `.slice()` with clearer arguments + Checking if `dir` is truthy in `win32.format` (added tests for this) Improve both by: + Making the reusable `trimArray()` function + Standardizing getting certain path statistics with the new `win32StatPath()` function Reviewed-By: Julien Gilli <[email protected]> PR-URL: #9289
Landed in c66f8c2. |
Improve performance by:
arguments
object! (inwin32.join
).substr()
(here) or.slice()
(here)Improve code consistency by:
[]
instead of.charAt()
where possible (such as here).slice()
with clearer arguments (such as here)Improve both by:
trimArray()
functionwin32StatPath()
functionBenchmarks: (higher is better)
Benchmark code (gist)