-
Notifications
You must be signed in to change notification settings - Fork 13.8k
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(dashboard): Virtualization POC #21438
Conversation
Codecov Report
@@ Coverage Diff @@
## master #21438 +/- ##
==========================================
- Coverage 66.84% 66.83% -0.02%
==========================================
Files 1800 1802 +2
Lines 68951 68972 +21
Branches 7335 7342 +7
==========================================
+ Hits 46092 46096 +4
- Misses 20965 20980 +15
- Partials 1894 1896 +2
Flags with carried forward coverage won't be shown. Click here to find out more.
📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more |
/testenv up FEATURE_DASHBOARD_VIRTUALIZATION |
@kgabryje Ephemeral environment spinning up at http://34.216.203.189:8080. Credentials are |
Love this feature. |
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.
LGTM, super nice feature! I kinda agree with @hushaoqing that leaving the charts rendered if they've already been rendered would be nicer. But since this is behind a FF we can probably iterate on these details in forthcoming PRs if there is a good reason not to make that change now.
We currently have |
Thank you for the feedback! @michael-s-molina I considered using |
One reason to render only visible items is memory footprint. Many virtualization libraries use that approach. That being said, may I suggest using pre-defined values for the feature flag instead of creating a new one? Like this: DASHBOARD_VIRTUALIZATION = NONE | VIEWPORT | PAGINATED |
Do we have an established pattern for 3-state feature flags? |
I'm not aware of one, and it might be worth mentioning that a lot of companies use feature flag manager platforms that prefer to work (or only work) with booleans. Booleans feel safer. Loving this feature, btw. I'm getting weird performance issues (i.e. the browser freezing) but i'll try it again in a bit and see if it's just a fluke. |
If you're getting perf issues with virtualization, but not without it, that might mean that the intersection observer is too expensive to be put on every chart. If that's the case, we might want to put it on |
I refactored it like this: |
If that is a concern, a possible approach would be to treat it like a configuration instead of a feature flag, similar to |
@rusackas @michael-s-molina Updated the PR:
|
Unfortunately I can't start a testenv with virtualization since now it's a config instead of a feature flag, so if you want to test manually, you need to pull my branch to your local setup |
Nice feature. Another case to consider is about color consistency. But this scenario is similar to the hidden tab, where the charts are lazy renderer, and this case will be addressed in another PR. cc @geido |
Awesome feature, tested locally. |
export enum DASHBOARD_VIRTUALIZATION_MODE { | ||
NONE = 'NONE', | ||
VIEWPORT = 'VIEWPORT', | ||
PAGINATED = 'PAGINATED', |
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.
Nit: I'm always nagging about this 😄 But I think we should stick to PascalCase enums in our TS codebase: https://www.typescriptlang.org/docs/handbook/enums.html
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.
+1 on PascalCase. In the latest graphql-codegen CLI, it'd even force the backend enums to be PascalCase by default.
Good catch @stephenLYZ. I think we can use the same approach we would use for the tabs. We would be catching series as they appear and either apply an existing color if that was seen before or assign a new color from the scheme and persist it. |
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.
Love it! Just one preference from me, I think the options VIEWPORT and PAGINATED are not super clear at first glance. If we set the charts to load on scroll I think LAZY might be a more appropriate keyword.
The problem is that both are lazy 😜. Anyway, I vote for removing the flag/configuration completely and choosing the strategy based on the number of charts that need to be rendered. |
@kgabryje Is this safe to support the screen capture from "Reports" worker? btw I recently introduced the similar feature (which only limits the runQuery) in #21488 |
Thank you all for feedback and suggestions! Great catch about the reports! Do you have any idea how to disable virtualization for celery workers? @michael-s-molina Agreed, but we need to figure out the threshold between the 2 strategies. I was thinking about this: if the chart hasn't been in view yet, draw it when it's 1 view height away from the viewport (like we do now). If the chart has been drawn and viewed, remove it when it's 5 (arbitrarily chosen number) view heights away from the viewport. That way we won't remove charts in regular dashboards, but we will in big dashboards. @villebro Good point about the Pascal case! However, if we can figure out the dynamic approach proposed by Michael we won't need that config, so I'm not changing that for now 🙂 |
Sounds good. We can determine the arbitrary number by displaying a heavy viewport of charts, measuring the consumed memory, and multiplying it by what we consider acceptable. |
IIRC, |
if ( | ||
isDashboardVirtualizationEnabled(this.props.dashboardVirtualizationMode) | ||
) { | ||
this.observer = new IntersectionObserver( |
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.
Should we disconnect and unobserve on unmount? Just to reduce the chance of memory leak.
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.
Done
0c7c41e
to
5d99cec
Compare
@michael-s-molina @justinpark @geido @villebro @hushaoqing @rusackas @ktmud Thank you all for feedback and suggestions... and your patience. I updated the PR - now the charts render when they are 1vh away from the viewport, but they're removed from DOM only if they are more than 4vh away from viewport. See the updated summary for more details |
/testenv up FEATURE_DASHBOARD_VIRTUALIZATION |
@kgabryje Ephemeral environment spinning up at http://52.42.75.81:8080. Credentials are |
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.
Thanks for the enhancements!
Ephemeral environment shutdown and build artifacts deleted. |
SUMMARY
This PR is a proof of concept for dashboard virtualization.
Due to a performance issues on large dashboards (60+ charts in a single tab/view), this PR introduces virtualization in an attempt to reduce the number of elements (DOM nodes) rendered at once.
In the initial state, we render only the charts in current viewport and charts max 1 view height away from current viewport.
When user scrolls down, charts that cross the 1 view height margin get rendered too.
We remove charts from DOM tree when they are at least 4 view heights away from current viewport.
Those values were chosen arbitrarily/experimentally to provide good middle-ground between memory efficiency and good user experience when scrolling up/down.
To sum it up: if chart is not rendered and it's less than 1 view height away from viewport - render it; if chart is rendered and it's more than 4 view heights away from viewport - remove it from DOM
Rerendering charts do NOT trigger new queries - we reuse data fetched on dashboard mount and only redraw the charts.
As of now, this feature is in proof-of-concept faze and should be considered as experimental. It's hidden behind a feature flag
DASHBOARD_VIRTUALIZATION
Virtualization is disabled for bot workers (like Celery) to ensure that reports and alerts work correctly
BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF
Screen.Recording.2022-10-09.at.18.45.21.mov
TESTING INSTRUCTIONS
DASHBOARD_VIRTUALIZATION
ADDITIONAL INFORMATION
DASHBOARD_VIRTUALIZATION