Skip to content

[DataGrid] Performance: avoid style invalidation#12019

Merged
romgrk merged 15 commits intomui:nextfrom
romgrk:perf-style-invalidation
Feb 15, 2024
Merged

[DataGrid] Performance: avoid style invalidation#12019
romgrk merged 15 commits intomui:nextfrom
romgrk:perf-style-invalidation

Conversation

@romgrk
Copy link
Contributor

@romgrk romgrk commented Feb 10, 2024

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

@romgrk romgrk added the scope: data grid Changes related to the data grid. label Feb 10, 2024
@mui-bot
Copy link

mui-bot commented Feb 10, 2024

Deploy preview: https://deploy-preview-12019--material-ui-x.netlify.app/

Generated by 🚫 dangerJS against cda4e3c

@romgrk romgrk mentioned this pull request Feb 10, 2024
9 tasks
@oliviertassinari oliviertassinari changed the title [DataGrid] Performance: avoid style invalidation [data grid] Performance: avoid style invalidation Feb 10, 2024
Copy link
Member

@oliviertassinari oliviertassinari left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

@romgrk
Copy link
Contributor Author

romgrk commented Feb 11, 2024

It looks like we still have to optimize this JavaScript rerendering, and we might even be faster than before 🚀

Yeah the offsets prop is an object and it's breaking react.memo in a few places, I got a commit fixing it in #12023 but it depends on this PR plus #12019, so it should be fixed shortly once we get these merged. I'm trying to make small PRs, the team has suffered enough with #10059.

Comment on lines 72 to 76
export const GridColumnHeaderRow = styled('div', {
name: 'MuiDataGrid',
slot: 'ColumnHeaderRow',
overridesResolver: (props, styles) => styles.columnHeaderRow,
})<{ ownerState: { params?: GetHeadersParams; leftOverflow?: number } }>(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you manage to fix it? All tests pass

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have restored the ownerState thing.

* @category Virtualization
* @ignore - do not document.
*/
export const gridOffsetsSelector = createSelector(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's meant to be internal only, we shouldn't export it from the package.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Member

@MBilalShafi MBilalShafi Feb 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be fine to remove it in a follow-up since it is not documented anyways.

Comment on lines 72 to 76
export const GridColumnHeaderRow = styled('div', {
name: 'MuiDataGrid',
slot: 'ColumnHeaderRow',
overridesResolver: (props, styles) => styles.columnHeaderRow,
})<{ ownerState: { params?: GetHeadersParams; leftOverflow?: number } }>(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you manage to fix it? All tests pass

Copy link
Member

@MBilalShafi MBilalShafi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice 👍

>
{leftCells}
<div className={gridClasses.cellOffsetLeft} role="presentation" />
<div
Copy link
Member

@MBilalShafi MBilalShafi Feb 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
image

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
image

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@MBilalShafi MBilalShafi changed the title [data grid] Performance: avoid style invalidation [DataGrid] Performance: avoid style invalidation Feb 15, 2024
@romgrk romgrk enabled auto-merge (squash) February 15, 2024 16:57
@romgrk romgrk merged commit 4613e48 into mui:next Feb 15, 2024
@romgrk romgrk deleted the perf-style-invalidation branch February 15, 2024 17:58
@oliviertassinari
Copy link
Member

oliviertassinari commented Feb 19, 2024

One more step in the right direction 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance scope: data grid Changes related to the data grid.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[DataGrid] Improve vertical scrolling performance

5 participants