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
Improve watch performance by using stable identities for Snapshot iterables #15991
Conversation
For maintainers only:
|
77b4af0
to
baea4f3
Compare
Opening as ready for review to get initial feedback. 🙂 I contacted my company's CLA management team to work out the EasyCLA. |
64514df
to
ff6f776
Compare
I believe I saw the same bottleneck before, then reported as #15231. |
@JoostK Thanks for linking that. I was curious if others had seen this issue. I would be interested to know if the patch here alleviates the problem for your team if you have a moment to manually apply and test. While this PR brought our team's |
I just checked with this patch applied and it didn't seem any faster. I haven't taken measurements but it doesn't seem like it resolves #15231. |
Got it. I'd wager there's more work needed here too. The next step I was thinking of was attempting to serialize the As a heads up, the |
Makes sense to me
I don't think that makes sense, since each iterator only keeps a referenced to the Snapshot, so it doesn't add any large memory overhead. Actually it reduces memory since only a single iterator is created per Snapshot.
It's interesting that reducing the count by 50% improves performance by 13x. Why is that? Maybe the SnapshotIterables are far more expensive than the remaining Iterables during merge, and the number of SnapshotIterables was also reduced by ~13x.
The way
👍 The PR looks good and I'll merge it afterwards |
Nice. Glad to have a second pair of eyes to confirm that.
I was surprised by this too and came to the same conclusion as you. I think the I hadn't thought of this until your memory comment, but I'd expect garbage collection of
👍 Thanks for confirming that. That's nice to know. |
ff6f776
to
7b3f4c0
Compare
EasyCLA should be good now. I force pushed a rebase without any changes. Thanks again for review @sokra. |
@gluxon Ignore it, it is normal for big changes, especial for |
Understood. Thanks! 😄 |
Thanks |
Thanks for the reviews and fast turnaround time! Hope this helps Webpack's users. 🤞 |
A large monorepo my team works on is seeing an issue where Webpack rebuilds report as finished, but
webpack-dev-server
doesn't respond until a minute later.Summary
Starting with performance changes up front. (See below for a description of what we were seeing.) Here's the
LazySet
merge
performance forcompilation.fileDependencies
in this monorepo before/after:merge
Loop IterationsThese aren't scientific timings ran over multiple trials. I can perform that if needed.
Investigation
CPU Profiling
Running the build in a CPU profiler revealed a large amount of time spent calling watchpack's
watch
function. This is after the initial Webpack build. The white space in the profile below is in between the initial build, and saving a file in the repo that has just been modified.webpack/lib/Watching.js
Lines 303 to 307 in e2f1592
Going down the call stack, it looks like watchpack iterates over
compilation.fileDependencies
, triggeringLazySet
'smerge
function.webpack/lib/util/LazySet.js
Lines 16 to 22 in 93ce24d
I patched the
merge
function to output how many items were being iterated over and their time.The results:
The 1st set iterated corresponds to
compilation.fileDependencies
.LazySet toMerge Duplicates
Inspecting
compilation.fileDependencies
in an interactive debugger shows that thisLazySet
has a lot of duplicates in itstoMerge
field.Adding a breakpoint to the
merge
function commented on above and inspecting thetoMerge
argument:This is after
LazySet._toMerge
has had its contents moved fromLazySet._toDeepMerge
. Attaching a screenshot of the call stack in VS Code's debugger if that helps.What kind of change does this PR introduce?
One of the reasons
_toMerge
gets so large is because everySnapshotIterable
is uniquely constructed, even if they're derived from the same underlyingSnapshot
class.This PR gives snapshot iterables stable identifiers, which reduces the items in the
_toMerge
set and significantly improved performance in this app.After this change, the log output from above becomes:
Did you add tests for your changes?
I added tests to ensure the snapshot iterables returned are stable across multiple calls, but the tests could probably be written better. I'd appreciate a gut check from the Webpack team that this change makes sense before improving tests more.
Does this PR introduce a breaking change?
It does not.
What needs to be documented once your changes are merged?
Questions for Reviewers
Thanks for looking at this!
watch
call in a different way?WeakRef
to prevent these saved iterable objects from living longer than necessary? I think we'd have to check for the API's existence and gracefully fallback to support older Node.js versions.fixes #15231