-
Notifications
You must be signed in to change notification settings - Fork 115
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
Stop cloning options for a massive performance boost #90
Conversation
This seemingly innocent operation is apparently responsible for some serious performance bottlenecks. In testing, I've seen that performance degrades by nearly an order of magnitute per file imported. By not cloning options, this bottleneck goes away, making this plugin significantly faster. On a project with 9 @import rules running this plugin took on average 7 seconds; by removing this clone operation it now takes on average 100ms, with roughly 90% of that time spent in file I/O.
During this investigation, I spent some time looking at whether async file I/O would provide any benefits. Hypothetically, those 90ms spent in I/O could be turned to 10ms but running all reads in parallel; however in practice I was unable to achieve any such gains. It may be that my experiment still ran reads in sequence, even though it was using async reads – I might have just misunderstood the structure of the code. Regardless, this change seems to be very low hanging fruit for significantly improving performance. Presumably, caching reads as per #47 would also provide gains but not in my case, because no file is depended on more than once. |
I'll see about fixing that broken test. |
Ah, I think I understand better why the cloning is there now in the first place – it's because |
By using Object.create, the original options become the prototype of the newly created object, and so any mutation of the options object should just shadow the properties of the prototype. Essentially, this is like cloning by reference, rather than by value, and has almost no performance penalties in this context.
I'd say 👍 |
@mstade I'd like to suggest for this case object-assign or extend-shallow |
Object-assign is already included btw
|
Sure – potato/tomato as far as I'm concerned since there's no practical difference between |
Heya! Any interest in getting this merged? I'm currently depending on my fork, and would love not to. If there's anything else missing from this PR before it can be merged, please let me know. |
I will take a deeper look this evening or tomorrow morning. I want to double check why I commited/merged something with clone in the first place. |
Right on – much obliged! |
FWIW, my cursory investigation suggest the cloning happens because the options get mutated down the line. If they aren't cloned, then subsequent imports may fail – this is why the test broke in my initial commit, so kudos for coverage! Does this help? |
The clone was a mistake by me. |
Released as 7.1.1 |
@MoOx Seems like not that PR |
Oh my bad lol. Releasing 7.1.2 sorry. |
Stop cloning options for a massive performance boost
@mstade You should use ponyfill. There isn't Object.assign on node 0.12 |
With all due respect @TrySound, you're just bike shedding. There was nothing wrong with using I'm sorry to come across as rude, but there it is. Thank you @MoOx for merging. |
@mstade Ah, yeah. exactly. Sorry. But still assign was already required.
|
@mstade The difference is here Object/assign |
First, my apologies for the tone in my previous comment. Second, I do know the difference (but thank you for the link anyway!) and what I'm saying is that in this context the difference is irrelevant. The way I used Regardless, I'm happy and thankful that this fix was merged; and after testing I can also happily report that using |
This seemingly innocent operation is apparently responsible for
some serious performance bottlenecks. In testing, I've seen that
performance degrades by nearly an order of magnitute per file
imported. By not cloning options, this bottleneck goes away,
making this plugin significantly faster.
On a project with 9
@import
rules running this plugin took onaverage 7 seconds; by removing this clone operation it now takes
on average 100ms, with roughly 90% of that time spent in file I/O.