-
-
Notifications
You must be signed in to change notification settings - Fork 8.9k
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 performance of ModuleConcatenationPlugin for loop #6613
improve performance of ModuleConcatenationPlugin for loop #6613
Conversation
Such difference is really odd. When I made these changes and benchmarked them, the results were on par. It looks like a bug in v8. The escape analysis should produce optimal code for this hot path. @bmeurer, can you advice us on this? |
I'm working on a minimal repro for this situation, not having a heap of luck. I can see some difference, but not the massive drop. I'll check with @brentwilton at work tomorrow and see what we can figure out. |
As mentioned in the Twitter thread, I'm pretty sure this is a bug in TurboFan where something odd prevents the array iterator inlining, which in turn defeats escape analysis and all other optimizations. We'll need some repro for this, ideally something that doesn't involve the rest of webpack. 😀 Maybe as a starting point: Are the shapes involved monomorphic? I.e. do you have different |
Starting a repro here: https://github.com/phenomnomnominal/v8-for-of-for-loop |
@psmarshall will take a look when you have a repro. If it's a small fix we might be able to patch this in Node 8 as well. |
@bmeurer no, it's not monomorphic. |
While this appears to be a v8 defect, this is causing major performance problems with large Angular CLI projects; essentially wiping out and reversing the performance benefits of Webpack 4. Please considering merging this as soon as possible. |
@@ -281,9 +281,12 @@ class ModuleConcatenationPlugin { | |||
for (const reason of newModule.reasons) { | |||
reason.dependency.module = newModule; | |||
} | |||
for (const dep of newModule.dependencies) { | |||
for (let i = 0; i < newModule.dependencies.length; i++) { |
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.
Could you add a comment explaining why this isn't a for-of loop pointing to this PR and adding // TODO: remove when LTS node version contains fixed v8 version
Ok, I have a repro for V8. It's because the inlining of const N = 1e7;
function forOf(a) {
for (const x of a) {}
}
function test(f, a) {
let result;
for (let i = 0; i < N; ++i) result = f(a);
return result;
}
const a = [1,2,3,4];
const b = ['a', 'b', 'c', 'd'];
test(forOf, a);
for (let i = 0; i < 100; ++i) test(x => x, a);
console.time('mono');
test(forOf, a);
console.timeEnd('mono');
test(forOf, b);
console.time('poly');
test(forOf, a);
console.timeEnd('poly'); Filed v8:7510 upstream. |
@brentwilton Thanks for your update. I labeled the Pull Request so reviewers will review it again. @sokra Please review the new changes. |
Thank you for your pull request! The most important CI builds succeeded, we’ll review the pull request soon. |
Thanks |
Thanks for the heads-up. The bug (v8:7510) was just fixed upstream. Unfortunately just missed 6.6, so it might not make it into Node 10, unless we can float this patch on top. |
What kind of change does this PR introduce?
bugfix / performance improvement
Did you add tests for your changes?
No
If relevant, link to documentation update:
N/A
Summary
In our large Angular 5 project (~3400 modules) ModuleConcatenationPlugin is now taking 60% of the build time in webpack 4.
Webpack is spending 869499ms in 'chunk modules optimization' within ModuleConcatenationPlugin.
Most of this time is consumed in 2 nested for-of loops in the ModuleConcatenationPlugin. By changing the for-of loops to standard for loops we have reduced the time we spend in ModuleConcatenationPlugin from 14 minutes 29 seconds to 2 minutes 35 seconds.
Does this PR introduce a breaking change?
No
Other information
Node: 8.9.3
Webpack: 4.0.1 and 4.0.0
Windows 10
During our prod build the inner for-of loop is visited a total of 7,309,580,444 (7.3 billion) times.
When debugging most of the time was spent in the following 2 for loops in ModuleConcatenationPlugin.js. Original time taken: 14m 29s (869499ms)
webpack/lib/optimize/ModuleConcatenationPlugin.js
Lines 284 to 290 in 6a5d081
Changing the above for of loop to a standard for loop reduces the time taken to 6m 8s (368453ms)
Making a further change to
let reasons = dep.module.reasons;
reduces the time taken to 2m 35s (141326ms)