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
perf: reducing ast node memory overhead #5133
perf: reducing ast node memory overhead #5133
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
dbac69b
to
a0844f6
Compare
Looking into test failures. I don't recall seeing them locally, but I think that's because it was failing in [Update] Fixed and rebased. Also, I figured out why I couldn't run the tests and created a doc PR to update the contributing guide: #5134 |
a0844f6
to
f7f5952
Compare
Codecov Report
@@ Coverage Diff @@
## master #5133 +/- ##
==========================================
- Coverage 98.86% 98.82% -0.04%
==========================================
Files 230 231 +1
Lines 8805 8849 +44
Branches 2314 2314
==========================================
+ Hits 8705 8745 +40
- Misses 39 43 +4
Partials 61 61
|
f7f5952
to
3d23432
Compare
Nice work!
If this commit does not significantly reduce memory size (I personally think the 9MB memory increase is acceptable), I prefer I have some quesions, Are the memory sizes of |
@TrickyPi the size of null or undefined would be the same. The key difference here is that we don't ever set these values to undefined, but they are instead unset if there is no value. When you read these properties it comes back as undefined, but the properties aren't allocated on the object. |
Oh, I see! I've only seen some declaration properties before. For some properties that are initialized in Rollup, such as |
What I don't like about that approach is there is less uniformity in the values and you'd have to know why some properties check |
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.
Nice work!
As for the general |
I think TS types prompt can help us know if the value is
I'm not sure about it. Oh, sorry! I just ran the |
I'm collecting the feedback from above and testing a few different approaches with some more extensive profiling runs with around 100 build iterations each. I'm pretty sure when I switched to using member functions there was a regression and performance and I'm trying to track that down while keeping the code as clean as possible. The main things I'm testing:
|
I would also expect member functions to be slower because even it they are inlined in some cases, the inlining would need to be deoptimized again once anything changes about the hidden class, and then you have the property access again. |
The enum member implementation seems to give stable result over time, allowing more predictable build time. |
My next thing to try is basically:
|
If you share the code to perform the benchmark, maybe people following the PR will also run it to confirm or infirm the results and their trends. |
@jerome-benoit I moved the benchmark scaffolding into its own repo you can clone and run yourself: https://github.com/thebanjomatic/test-rollup-perf/ I can't share my larger test case, but you can modify The code that is in there is just bundling three.js, lodash-es, and d3 into a single bundled js file with sourcemaps and takes about 4.5 seconds for me to run vs 32 seconds for my other build. It also uses the interleaved approach described above so it should hopefully produce more consistent results. Test run is still in progress.... |
I think tomorrow I will be able to give it a try. Thanks. |
Did some instrumentation to figure out how many times each flag is getting read/written to, so we might be able to get some of that performance back by doing things as discussed like removing the extra indirection for the getter/setter for things for the more heavily used properties:
|
I think the project would benefit from running a lightweight benchmark on each PRs with report as a github CI workflow to trap obvious performance regression before they go in. |
Sorry this got a little stale. The main reason were efforts to finalize and release Rollup 4. If this PR can be updated accordingly, I would still be interested in merging this soon. |
@lukastaegert No problem, I figured the other 4.0 stuff was more important at the time. I'm still a little torn on this optimization as it does consistently build a little slower after this change, but uses less memory in the process. Perhaps the SWC performance improvements will even things out a little. I wasn't able to try it sooner than that because I was getting a ton of errors trying to build with the swc PR a few weeks back, but I will at least rebase this PR now that that is merged and then we can see where things are at. |
3d23432
to
f1aff13
Compare
What is the root cause of the slowdown? |
f1aff13
to
a9d0d38
Compare
@jerome-benoit Between the However, if we just use regular booleans for those two flags, we also lose a lot of the memory savings from this change. Its not really drastically slower either, it was 1% slower overall. I think we just need to make a decision about whether or not the juice is worth the squeeze. |
The tradeoff between the overall memory usage reduction and the very small building time slowdown "regression" seems reasonable. |
There are still some open conversations, do we want to address them before merging? |
Booleans are represented by numbers and take up 4 bytes each at the time of this commit in v8. This commit packs all the boolean fields of the AST nodes into a single 32-bit integer which ammortizes the cost of the boolean fields. The end result is smaller AST nodes.
We now just access through `this.scope.context` directly.
a9d0d38
to
22d9c39
Compare
@lukastaegert I have resolved all the open conversations. I decided it was probably best to defer one task to a separate/future PR: #5133 (comment) let me know if you would prefer I do that refactor before merging, or if it is ok to merge as is. |
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.
Looks good to me!
This PR has been released as part of rollup@4.1.0. You can test it via |
<p>This PR was automatically created by Snyk using the credentials of a real user.</p><br /><h3>Snyk has created this PR to upgrade rollup from 4.0.2 to 4.1.3.</h3> :information_source: Keep your dependencies up-to-date. This makes it easier to fix existing vulnerabilities and to more quickly identify and fix newly disclosed vulnerabilities when they affect your project. <hr/> - The recommended version is **3 versions** ahead of your current version. - The recommended version was released **21 days ago**, on 2023-10-15. <details> <summary><b>Release notes</b></summary> <br/> <details> <summary>Package name: <b>rollup</b></summary> <ul> <li> <b>4.1.3</b> - <a href="https://snyk.io/redirect/github/rollup/rollup/releases/tag/v4.1.3">2023-10-15</a></br><h2>4.1.3</h2> <p><em>2023-10-15</em></p> <h3>Bug Fixes</h3> <ul> <li>Fix WASM build as hash function was not exported (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="1943384459" data-permission-text="Title is private" data-url="rollup/rollup#5203" data-hovercard-type="pull_request" data-hovercard-url="/rollup/rollup/pull/5203/hovercard" href="https://snyk.io/redirect/github/rollup/rollup/pull/5203">#5203</a>)</li> </ul> <h3>Pull Requests</h3> <ul> <li><a href="https://snyk.io/redirect/github/rollup/rollup/pull/5203" data-hovercard-type="pull_request" data-hovercard-url="/rollup/rollup/pull/5203/hovercard">#5203</a>: fix: export xxhashBase64Url from wasm (<a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/sapphi-red/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://snyk.io/redirect/github/sapphi-red">@ sapphi-red</a>)</li> </ul> </li> <li> <b>4.1.1</b> - <a href="https://snyk.io/redirect/github/rollup/rollup/releases/tag/v4.1.1">2023-10-15</a></br><h2>4.1.1</h2> <p><em>2023-10-15</em></p> <h3>Bug Fixes</h3> <ul> <li>Improve Node parsing performance (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="1943329369" data-permission-text="Title is private" data-url="rollup/rollup#5201" data-hovercard-type="pull_request" data-hovercard-url="/rollup/rollup/pull/5201/hovercard" href="https://snyk.io/redirect/github/rollup/rollup/pull/5201">#5201</a>)</li> </ul> <h3>Pull Requests</h3> <ul> <li><a href="https://snyk.io/redirect/github/rollup/rollup/pull/5201" data-hovercard-type="pull_request" data-hovercard-url="/rollup/rollup/pull/5201/hovercard">#5201</a>: perf: use mimalloc for bindings_napi (<a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/sapphi-red/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://snyk.io/redirect/github/sapphi-red">@ sapphi-red</a>)</li> </ul> </li> <li> <b>4.1.0</b> - <a href="https://snyk.io/redirect/github/rollup/rollup/releases/tag/v4.1.0">2023-10-14</a></br><h2>4.1.0</h2> <p><em>2023-10-14</em></p> <h3>Features</h3> <ul> <li>Reduce memory usage of Rollup builds (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="1891270290" data-permission-text="Title is private" data-url="rollup/rollup#5133" data-hovercard-type="pull_request" data-hovercard-url="/rollup/rollup/pull/5133/hovercard" href="https://snyk.io/redirect/github/rollup/rollup/pull/5133">#5133</a>)</li> </ul> <h3>Pull Requests</h3> <ul> <li><a href="https://snyk.io/redirect/github/rollup/rollup/pull/5133" data-hovercard-type="pull_request" data-hovercard-url="/rollup/rollup/pull/5133/hovercard">#5133</a>: perf: reducing ast node memory overhead (<a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/thebanjomatic/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://snyk.io/redirect/github/thebanjomatic">@ thebanjomatic</a>)</li> <li><a href="https://snyk.io/redirect/github/rollup/rollup/pull/5177" data-hovercard-type="pull_request" data-hovercard-url="/rollup/rollup/pull/5177/hovercard">#5177</a>: chore: explicitly set rust toolchain channel (<a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/cijiugechu/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://snyk.io/redirect/github/cijiugechu">@ cijiugechu</a>)</li> <li><a href="https://snyk.io/redirect/github/rollup/rollup/pull/5179" data-hovercard-type="pull_request" data-hovercard-url="/rollup/rollup/pull/5179/hovercard">#5179</a>: Update migration guide for Rollup 4 (<a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/lukastaegert/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://snyk.io/redirect/github/lukastaegert">@ lukastaegert</a>)</li> <li><a href="https://snyk.io/redirect/github/rollup/rollup/pull/5180" data-hovercard-type="pull_request" data-hovercard-url="/rollup/rollup/pull/5180/hovercard">#5180</a>: Resolve clippy errors (<a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/cijiugechu/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://snyk.io/redirect/github/cijiugechu">@ cijiugechu</a>)</li> <li><a href="https://snyk.io/redirect/github/rollup/rollup/pull/5183" data-hovercard-type="pull_request" data-hovercard-url="/rollup/rollup/pull/5183/hovercard">#5183</a>: Add clippy to pipeline and fix remaining issues (<a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/lukastaegert/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://snyk.io/redirect/github/lukastaegert">@ lukastaegert</a>)</li> <li><a href="https://snyk.io/redirect/github/rollup/rollup/pull/5184" data-hovercard-type="pull_request" data-hovercard-url="/rollup/rollup/pull/5184/hovercard">#5184</a>: docs: fix code example for <code>onLog</code> (<a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/tjenkinson/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://snyk.io/redirect/github/tjenkinson">@ tjenkinson</a>)</li> <li><a href="https://snyk.io/redirect/github/rollup/rollup/pull/5186" data-hovercard-type="pull_request" data-hovercard-url="/rollup/rollup/pull/5186/hovercard">#5186</a>: Improve wording for native artifacts in migration guide (<a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/lukastaegert/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://snyk.io/redirect/github/lukastaegert">@ lukastaegert</a>)</li> <li><a href="https://snyk.io/redirect/github/rollup/rollup/pull/5190" data-hovercard-type="pull_request" data-hovercard-url="/rollup/rollup/pull/5190/hovercard">#5190</a>: test: add verifyAst type (<a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/TrickyPi/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://snyk.io/redirect/github/TrickyPi">@ TrickyPi</a>)</li> <li><a href="https://snyk.io/redirect/github/rollup/rollup/pull/5196" data-hovercard-type="pull_request" data-hovercard-url="/rollup/rollup/pull/5196/hovercard">#5196</a>: chore(deps): update dependency rollup to v4 (<a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/renovate/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://snyk.io/redirect/github/renovate">@ renovate</a>[bot])</li> <li><a href="https://snyk.io/redirect/github/rollup/rollup/pull/5197" data-hovercard-type="pull_request" data-hovercard-url="/rollup/rollup/pull/5197/hovercard">#5197</a>: chore(deps): lock file maintenance minor/patch updates (<a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/renovate/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://snyk.io/redirect/github/renovate">@ renovate</a>[bot])</li> </ul> </li> <li> <b>4.0.2</b> - <a href="https://snyk.io/redirect/github/rollup/rollup/releases/tag/v4.0.2">2023-10-06</a></br><h2>4.0.2</h2> <p><em>2023-10-06</em></p> <h3>Bug Fixes</h3> <ul> <li>Fix annotation detection logic to not fail when a non-ASCII character precedes a double underscore (<a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="1930196242" data-permission-text="Title is private" data-url="rollup/rollup#5178" data-hovercard-type="pull_request" data-hovercard-url="/rollup/rollup/pull/5178/hovercard" href="https://snyk.io/redirect/github/rollup/rollup/pull/5178">#5178</a>)</li> </ul> <h3>Pull Requests</h3> <ul> <li><a href="https://snyk.io/redirect/github/rollup/rollup/pull/5178" data-hovercard-type="pull_request" data-hovercard-url="/rollup/rollup/pull/5178/hovercard">#5178</a>: Handle special characters before double underscores (<a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/lukastaegert/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://snyk.io/redirect/github/lukastaegert">@ lukastaegert</a>)</li> </ul> </li> </ul> from <a href="https://snyk.io/redirect/github/rollup/rollup/releases">rollup GitHub release notes</a> </details> </details> <details> <summary><b>Commit messages</b></summary> </br> <details> <summary>Package name: <b>rollup</b></summary> <ul> <li><a href="https://snyk.io/redirect/github/rollup/rollup/commit/c61a1507a88fc71be431550642b040da4b9422b0">c61a150</a> 4.1.3</li> <li><a href="https://snyk.io/redirect/github/rollup/rollup/commit/70f79ad2f11a45524fcb89cbbb7138d8bb828b68">70f79ad</a> Fix publish script</li> <li><a href="https://snyk.io/redirect/github/rollup/rollup/commit/ebd96c447bab292e33b05628ec8e7d0e61bb59b8">ebd96c4</a> 4.1.2</li> <li><a href="https://snyk.io/redirect/github/rollup/rollup/commit/ee0639e711672b552fcd2928a700bc5541a564f0">ee0639e</a> fix: export xxhashBase64Url from wasm (#5203)</li> <li><a href="https://snyk.io/redirect/github/rollup/rollup/commit/d8b31a202a246758b8d67eefe77361a894d37005">d8b31a2</a> 4.1.1</li> <li><a href="https://snyk.io/redirect/github/rollup/rollup/commit/f3eaa288b6afbb0ea5ad60b21238e950122a1766">f3eaa28</a> perf: use mimalloc for bindings_napi (#5201)</li> <li><a href="https://snyk.io/redirect/github/rollup/rollup/commit/cb144b2be4262b3743b31983b26f7fa985be3ceb">cb144b2</a> 4.1.0</li> <li><a href="https://snyk.io/redirect/github/rollup/rollup/commit/72c66398cd3e8d52e6812ff94b721a1a56ad7cdd">72c6639</a> perf: reducing ast node memory overhead (#5133)</li> <li><a href="https://snyk.io/redirect/github/rollup/rollup/commit/e2f947f28ef921568ae03af9b9e868b9e7c712fa">e2f947f</a> chore(deps): update dependency rollup to v4 (#5196)</li> <li><a href="https://snyk.io/redirect/github/rollup/rollup/commit/4bcf4e124b534c5fe39cee12f683028f0895a635">4bcf4e1</a> chore(deps): lock file maintenance minor/patch updates (#5197)</li> <li><a href="https://snyk.io/redirect/github/rollup/rollup/commit/dddf626a77e15d4e0baa5f1689fd233634a29a9a">dddf626</a> Reduce workflow concurrency</li> <li><a href="https://snyk.io/redirect/github/rollup/rollup/commit/97bffa81987b72a9fe6168962bc1fe38cb948048">97bffa8</a> Enable Renovate automerge</li> <li><a href="https://snyk.io/redirect/github/rollup/rollup/commit/d90f274832b28429bd593ad0e34791ca7c2888ba">d90f274</a> test: add verifyAst type (#5190)</li> <li><a href="https://snyk.io/redirect/github/rollup/rollup/commit/f52a2ebfdcd568b0876af3fadf9e85f7c4af6e5d">f52a2eb</a> Improve wording for native artifacts in migration guide (#5186)</li> <li><a href="https://snyk.io/redirect/github/rollup/rollup/commit/080d2245ab6b6298229ebe7258c2b96816e7c52d">080d224</a> Add clippy to pipeline and fix remaining issues (#5183)</li> <li><a href="https://snyk.io/redirect/github/rollup/rollup/commit/c45366402e1841b6a2fd1f1bd0a4319571acd09f">c453664</a> docs: fix code example for `onLog` (#5184)</li> <li><a href="https://snyk.io/redirect/github/rollup/rollup/commit/e99ff72b3a60a4f5483a401b0423704675537ca3">e99ff72</a> Resolve clippy errors (#5180)</li> <li><a href="https://snyk.io/redirect/github/rollup/rollup/commit/2a86412433bd4e1a2a344db75ad180ade62a856e">2a86412</a> Fix toolchain for REPL workflow</li> <li><a href="https://snyk.io/redirect/github/rollup/rollup/commit/15d321bf7da5d48ed9a8ed9f87d7f88736ce837d">15d321b</a> chore: explicitly set rust toolchain channel (#5177)</li> <li><a href="https://snyk.io/redirect/github/rollup/rollup/commit/8b217ce2288bd268ed50f23990cced830f2644f2">8b217ce</a> Update migration guide for Rollup 4 (#5179)</li> </ul> <a href="https://snyk.io/redirect/github/rollup/rollup/compare/3d9c833c4fcb666301967554bac7ab0a0a698efe...c61a1507a88fc71be431550642b040da4b9422b0">Compare</a> </details> </details> <hr/> **Note:** *You are seeing this because you or someone else with access to this repository has authorized Snyk to open upgrade PRs.* For more information: <img src="https://api.segment.io/v1/pixel/track?data=eyJ3cml0ZUtleSI6InJyWmxZcEdHY2RyTHZsb0lYd0dUcVg4WkFRTnNCOUEwIiwiYW5vbnltb3VzSWQiOiJjMGRjZTAxNC0wMjlhLTQ2ZTctOWMxNS02YTM0NDg0MTM4NmYiLCJldmVudCI6IlBSIHZpZXdlZCIsInByb3BlcnRpZXMiOnsicHJJZCI6ImMwZGNlMDE0LTAyOWEtNDZlNy05YzE1LTZhMzQ0ODQxMzg2ZiJ9fQ==" width="0" height="0"/> 🧐 [View latest project report](https://app.snyk.io/org/woodpile37/project/edb93f5a-17e2-4a56-beb9-1796f0e58302?utm_source=github&utm_medium=referral&page=upgrade-pr) 🛠 [Adjust upgrade PR settings](https://app.snyk.io/org/woodpile37/project/edb93f5a-17e2-4a56-beb9-1796f0e58302/settings/integration?utm_source=github&utm_medium=referral&page=upgrade-pr) 🔕 [Ignore this dependency or unsubscribe from future upgrade PRs](https://app.snyk.io/org/woodpile37/project/edb93f5a-17e2-4a56-beb9-1796f0e58302/settings/integration?pkg=rollup&utm_source=github&utm_medium=referral&page=upgrade-pr#auto-dep-upgrades) <!--- (snyk:metadata:{"prId":"c0dce014-029a-46e7-9c15-6a344841386f","prPublicId":"c0dce014-029a-46e7-9c15-6a344841386f","dependencies":[{"name":"rollup","from":"4.0.2","to":"4.1.3"}],"packageManager":"npm","type":"auto","projectUrl":"https://app.snyk.io/org/woodpile37/project/edb93f5a-17e2-4a56-beb9-1796f0e58302?utm_source=github&utm_medium=referral&page=upgrade-pr","projectPublicId":"edb93f5a-17e2-4a56-beb9-1796f0e58302","env":"prod","prType":"upgrade","vulns":[],"issuesToFix":[],"upgrade":[],"upgradeInfo":{"versionsDiff":3,"publishedDate":"2023-10-15T17:48:53.269Z"},"templateVariants":[],"hasFixes":false,"isMajorUpgrade":false,"isBreakingChange":false,"priorityScoreList":[]}) --->
This PR contains:
Are tests included?
Breaking Changes?
List any relevant issue numbers:
resolves #5127
Description
This PR implements the suggestions outlined in the linked issue and reduces the memory overhead of the AST that rollup creates for each source file. Note: I have split the changes into 4 distinct commits that should be easier to review individually.
I have primarily been testing on one large project which is a storybook application building with vite and by extension, building with rollup. As mentioned in the issue, the aim of these 4 commits is to reduce the object size for each node instance since there are millions of node instances, shaving a few bytes here and there can lead to tangible memory reductions.
To validate the memory savings, I took heap snapshots using the node devtools, but I also found it useful to identify the value for
--max-old-space-size
at which point the build runs out of memory and node stack dumps. This is a rough measurement because I only found this value to the nearest 25MB. I also tested using 3.26.0 to capture the heap size reduction from #5075 as my current test project is a different project than the one I was testing with in that PR.--max-old-space-size
works at2750 MB
& crashes at2725 MB
--max-old-space-size
works at2425 MB
& crashes at2400 MB
--max-old-space-size
works at2250 MB
& crashes at2225 MB
So for this particular build, it was able to complete with around
175MB
less memory which lines up with what I saw in the heap snapshots (170 MB
).As far as build times are concerned, the linked issue had some concerns about extra overhead due to needing to do bitwise operations instead of simpler boolean access patterns. I also had concerns when developing the last commit in particular (perf: make ast fields optional instead of null) about whether or not making that change would reduce build performance due to creating more hidden classes and maybe some functions would no longer be monomorphic. After identifying and fixing a bug in one of my optimizations, I don't really see any noticeable runtime performance difference with this PR.
I tested the same builds as above and found the time difference was within the noise threshold:
31.378 seconds
(averaged over 25 builds)31.267 seconds
(averaged over 100 builds)31.259 seconds
(averaged over 100 builds)The last commit which switches from null to optional / undefined is perhaps the most controversial of the changes, so I wanted to also test without that change and allow the maintainers to determine whether or not to pursue that, or it can be split to its own PR if we feel like more testing / validation is needed.
Measuring with a heap snapshot taken just before
await renderChunks
gets called inside ofgenerate()
:Heap Size without last commit:
1564 MB
Heap Size with last commit:
1555 MB
So that commit contributes
9 MB
to the170 MB
reduction and it would be at161 MB
otherwise.