-
Notifications
You must be signed in to change notification settings - Fork 492
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
fix: faster parse options #535
Conversation
Just to bring more attention, @ljharb points out a very interesting thing that could affect this PR at #536 (review). If the assumption is true, we can clean all the |
eccb1f2
to
cc7aadd
Compare
Here's my DT stress test using pnpm. Before:
This PR (
Which according to https://how-much-faster.glitch.me/ is:
|
I forgot to say the obvious: well done! Feel free to ping me if you want this rerun and I haven't already done so. |
Stepping back and broadly asking the question "what is
If all we did were ETA: if the function returns an object as-is then the memory concerns of |
Personally, if I were to rewrite this library from scratch (something I'm trying to do to explore perf improvements, though I don't know if I will actually publish it), I wouldn't be storing these options in Looking at
So to me, it feels like an equivalently good change to this PR would be to just check But, options is a part of the API, so, the currrent API is sorta locked in. |
cc7aadd
to
7e4e016
Compare
|
Well, I think we agree to keep the object as-is and don't do any modification, and just validate the cases of In this case, I will create a new commit instead of modifying the first one with the test modified and the new behavior. Also, this can be considered as breaking change? |
It depends on what the changes needed are. Just cause our tests have to change doesn't necessarily mean it's a breaking change. If folks are going to get different results after this change by passing the exact same things as before, then it is a breaking change. |
@wraithgar I thought it might be a breaking change if someone got the parsed object and access something in the options, but I don't think that will be the case, so maybe it's not a breaking change. I push the version returning just the options, we can now see if worth to keep like that. |
I think once the linting errors are fixed we are in a good place here. @H4ad how do you feel about this PR in contrast to your other idea of using bitmasks? Do you still think that is worth exploring? |
|
585125b
to
d0c20e3
Compare
@wraithgar About bitmasks, I think it could be good for big refactorings of the library, for this PR, I don't think it's worth having that level of refactoring for the entire lib just to use bitmasks, the perf is almost the same as this current PR. |
The performance of parse-options before:
After:
The performance improvement also extend for any method that use
parseOptions
, likesatisfies
:Before:
Then:
I also added parseOptions before any method that passes
options
down to range or semver to reduce the number of comparisons by looking intoisParsedConfigSymbol
.With this new way of parsing the options, the memory allocation is 0 for any parsed options.
The only downside is the maintenance, the number of variables to represent the options can increase depending on the number of options if we keep just 3 options, so is not a problem, if we add more, is more comparisons.
Alternative Version
I also made a version using bit masks, which you can see in this commit: h4ad-forks@6c7a68a
In that version, the performance benefits are the same, the maintenance is lower because is very easy to handle bit flags but is takes more memory and breaks one test of parse-options (about the number).
Also, the options now are just a getter and I introduce a new variable called
flagOptions
, which holds all the flags.Conclusion
In terms of lower changes and lower memory usage, the best option is
Object.freeze
.If you want to take more aggressive changes with lower maintenance in the future and allocating some memory in the process, the option with bit masks is the best.
References
Related to #528
benchmark.js