[DataGrid] Performance: avoid style invalidation#12019
Conversation
|
Deploy preview: https://deploy-preview-12019--material-ui-x.netlify.app/ |
There was a problem hiding this comment.
Avoid style invalidation by avoiding changing the CSS variables on the root container during scrolling.
Oh cool, so it's the same root cause as in https://emilkowal.ski/ui/building-a-drawer-component. CSS variables work well for static values but it's unusable for CSS variables who changes at 120 Hz (macOS screen refresh rate) with a lot of DOM descendants.
Regarding the benchmark, what I can measure on this PR is a reduction of about 70ms spent on Rendering for every 1,000 ms of scrolling but an increase of about 80ms spent on JavaScript.
Before https://deploy-preview-11650--material-ui-x.netlify.app/x/react-data-grid/#pro-plan
After #10059 (add position: sticky) https://deploy-preview-10059--material-ui-x.netlify.app/x/react-data-grid/#pro-plan

After #11924 (solve Layerize) https://deploy-preview-11924--material-ui-x.netlify.app/x/react-data-grid/#pro-plan

This PR (solve CSS variable cascading) https://deploy-preview-12019--material-ui-x.netlify.app/x/react-data-grid/#pro-plan

It looks like we still have to optimize this JavaScript rerendering, and we might even be faster than before 🚀
The offsets prop leaks as a DOM attribute
Yeah the |
| export const GridColumnHeaderRow = styled('div', { | ||
| name: 'MuiDataGrid', | ||
| slot: 'ColumnHeaderRow', | ||
| overridesResolver: (props, styles) => styles.columnHeaderRow, | ||
| })<{ ownerState: { params?: GetHeadersParams; leftOverflow?: number } }>( |
There was a problem hiding this comment.
This test breaks if this slot doesn't have an ownerState prop, and I don't understand why. Removing the slot stuff made the test pass. Passing an empty ownerState={{}} also made it pass, but didn't felt clean.
There was a problem hiding this comment.
Did you manage to fix it? All tests pass
There was a problem hiding this comment.
Well I removed the slot stuff, so yes but the slot ColumnHeaderRow doesn't exist now. Is that ok?
Also why is that test failing? Isn't that override targetting the root slot of the datagrid?
There was a problem hiding this comment.
I have restored the ownerState thing.
| * @category Virtualization | ||
| * @ignore - do not document. | ||
| */ | ||
| export const gridOffsetsSelector = createSelector( |
There was a problem hiding this comment.
If it's meant to be internal only, we shouldn't export it from the package.
There was a problem hiding this comment.
I have commits to evolve this a bit and get rid of it, in #12023. I'll adjust in a follow-up PR if that's fine.
There was a problem hiding this comment.
I think it should be fine to remove it in a follow-up since it is not documented anyways.
| export const GridColumnHeaderRow = styled('div', { | ||
| name: 'MuiDataGrid', | ||
| slot: 'ColumnHeaderRow', | ||
| overridesResolver: (props, styles) => styles.columnHeaderRow, | ||
| })<{ ownerState: { params?: GetHeadersParams; leftOverflow?: number } }>( |
There was a problem hiding this comment.
Did you manage to fix it? All tests pass
| > | ||
| {leftCells} | ||
| <div className={gridClasses.cellOffsetLeft} role="presentation" /> | ||
| <div |
There was a problem hiding this comment.
Could you mention the steps you are doing to test it, in a few of my performance snapshots I could see a noticeable reduction in the recalculate styles portion, but it regresses a bit the layout part of the rendering.
I took into account those style revalidations which came right after the scroll event.
Here are the average results from a few tests on the M1 Pro and Chrome Version 121.0.6167.184
Before: (on https://next.mui.com/x/react-data-grid/#pro-plan)
Recalculate style: 4.95ms
Layout: 0.91ms
Pre-paint: 0.91
Paint: 1.14ms

After: (on https://deploy-preview-12019--material-ui-x.netlify.app/x/react-data-grid/#pro-plan)
Recalculate style: 2.91ms
Layout: 7.75ms
Pre-paint: 0.90
Paint: 0.80ms

Am I testing it incorrectly?
Bdw, on 4x CPU slowdown, it appears to improve the layout phase as well (almost 40% improvement), so overall it seems improved, especially on low-end devices. I am all in for pushing for this improvement since the overall performance (summary) is better in all the tests I did!
But if you can guess the possible reason for the increase in the layout calculation time without throttling, that'd add to my knowledge.
There was a problem hiding this comment.
I run scroller.scrollTo({ top: 100_000, behavior: 'smooth' }) and inspect one of the cycles in the middle of the graph. I'm not sure exactly, but it could be fixed in #12023. Using an offsetTop on the row container in sticky was a mistake, it triggers style invalidation, and it might be triggering layout invalidation.
|
One more step in the right direction 🙏 |
Closes #11866
Follow-up of #10059 (comment)
Avoid style invalidation by avoiding changing the CSS variables on the root container during scrolling.
Before:

After:

Preview: https://deploy-preview-12019--material-ui-x.netlify.app/x/react-data-grid/#pro-plan
See https://www.youtube.com/watch?v=WRiOWJZoKlw