Skip to content
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

[EuiDataGrid] Memoization & perf improvements #7556

Merged
merged 20 commits into from
Mar 12, 2024

Conversation

cee-chen
Copy link
Member

@cee-chen cee-chen commented Mar 7, 2024

Summary

Pulled out from @kqualters-elastic's #7374 PR, with more atomic git history.

The goal of this PR is to improve existing EuiDataGrid performance by reducing rerenders, via useMemo, useCallback, memo, and replacing inline JSX with components.

When reviewing changes, I strongly recommend following by commit and hiding whitespace changes.

QA

General checklist

  • Browser QA
    • Checked in both light and dark modes
    • Checked in Chrome, Safari, Edge, and Firefox
      - [ ] Checked in mobile
      - [ ] Checked for accessibility including keyboard-only and screenreader modes
  • Docs site QA - N/A
  • Code quality checklist - N/A
  • Release checklist - N/A, as this is primarily a perf/tech debt PR and should not impact either consumers or end-users
  • Designer checklist - N/A

cee-chen and others added 8 commits March 8, 2024 09:10
- more granular breakup of memoized vars to reduce rerenders and increase readability
- use new deep equal memoization hook to reduce rerenders on consumer-passed `sorting` and `sortingColumns`

- separate out memoized `sortedRowMap` to reduce dependencies/rerenders further

- rewrite `inMemoryRowIndices` more succinctly
- remove more inline jsx vars

- move fn utilities to bottom of file + wrap in `memo()`

- get rid of `cellContentProps` obj, just use props
- performance changes worked I guess!
Copy link
Contributor

@mgadewoll mgadewoll left a comment

Choose a reason for hiding this comment

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

Overall the added performance optimization updates look good to me. 👍
But I think I'm still missing overall knowledge of the EuiDataGrid component to understand the full picture of it and how everything should work 😅

src/components/datagrid/utils/col_widths.ts Outdated Show resolved Hide resolved
cee-chen and others added 3 commits March 11, 2024 13:53
- `sorting` is _only_ used by header cells, so it makes sense to waterfall it just to the header row instead of to all cells (which causes rerenders across every cell every time `sorting` from a consumer is referentially unstable)

+ rename sorting context to `sorted` to make the purpose of the context it clearer

+ reorder props list slightly (by usage etc)
+ return null earlier (which requires creating new component)

+ convert args to obj for easier reuse

+ clean up/convert tests to RTL, reduce snapshots
@kibanamachine
Copy link

Preview staging links for this PR:

@elasticmachine
Copy link
Collaborator

💚 Build Succeeded

History

Copy link
Contributor

@mgadewoll mgadewoll left a comment

Choose a reason for hiding this comment

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

🚀 From what I can tell, those are nice code optimizations and cleanups!

@cee-chen
Copy link
Member Author

Thanks for being so on top of reviews Lene! Will go ahead and merge this in.

For context for others coming in after: Kevin and I worked pretty closely on this PR (I took his original code and wrote/pushed up the changes/refactors I wanted directly to this branch) which IMO constitutes as code review as well 😆

Huge thanks to Kevin for this impetus and his work on datagrid!

@cee-chen cee-chen merged commit 88911d7 into elastic:main Mar 12, 2024
6 of 7 checks passed
@cee-chen cee-chen deleted the datagrid/perf branch March 12, 2024 16:42
kqualters-elastic added a commit to elastic/kibana that referenced this pull request Apr 16, 2024
…180016)

## Summary

This pr makes use of a new prop (and some generic memoization fixes) in
2 eui prs merged recently (elastic/eui#7556 and
elastic/eui#7374) to improve the performance of
the alerts table. Mainly, the cellContext prop is now available to
consumers of the triggersActionsUi alerts table to pass in custom props
in a way that allows the renderCellValue/rowCellRender functions of the
various EuiDataGrid prop apis to remain referentially stable across
re-renders. There are also some various changes to various hooks and
props found throughout plugins that use the table to improve
performance. There should be no change in functionality, just a moderate
to substantial reduction in time the app spends rendering the alerts
table in various scenarios. Below will be some react dev tools
performance profiles, main compared to this branch, with the exact same
set of generated data.

Main, switching from 10-100 rows:

![main_alerts_table](https://github.com/elastic/kibana/assets/56408403/6b87093f-5b1b-4d22-8e23-ccc3406317f4)

This branch 10-100 rows:

![context_alerts_table](https://github.com/elastic/kibana/assets/56408403/75bf5d53-045d-42ae-979a-e52d6c0f8020)

Pretty modest gain here, 1 render is slower than any others on main, but
overall less time spent rendering by about a second.

Main, opening the cell popover on 2 cells

![main_open_cell_popover](https://github.com/elastic/kibana/assets/56408403/60c5d132-b526-4859-a29c-5d3157142d50)

This branch, opening cellpopover

![context_open_cell_popover](https://github.com/elastic/kibana/assets/56408403/2c60b250-6a9f-44b4-aec8-f9dcb8c87531)

Again nothing crazy here, modest improvement.

Main opening timeline and hitting refresh


![main_open_timeline](https://github.com/elastic/kibana/assets/56408403/7525200d-cf9b-4f43-9f24-43f314740db1)

This branch, opening timeline and hitting refresh


![context_open_timeline](https://github.com/elastic/kibana/assets/56408403/efd3cf95-a81a-4933-b310-fa61de24258f)

This is the case that brought this about in the first place, as security
solution shares a lot of code between tables, the alerts table
recreating all cells on every render was destroying performance of the
timeline rendering in a flyout/modal while users were on alerts page or
the rule detail page, which is probably the most common use case. 93ms
in this branch vs 2500+ ms in main. This type of performance hit happens
when almost any action is taken in timeline.

Main, selecting 3 alerts 1 at a time

![main_actions](https://github.com/elastic/kibana/assets/56408403/87487149-cf6d-4bcc-9192-b64411abe321)

This branch selecting 3 alerts 1 at a time


![context_actions](https://github.com/elastic/kibana/assets/56408403/8407953a-5af0-4cfd-9f2c-08c710c81fb3)

Pretty substantial improvement here as well, ~2000ms vs 67ms.

Apologies if some of the gifs are cut off, please try the branch vs main
on your own! This was done on a local kibana in dev mode, so things like
emotion are eating up more cpu than they would for a user, but there
still should be improvement, and I can't think of any circumstance where
things will be worse. Also this branch was a little longer lived than I
would have liked, so if you are reviewing and changed something around
these files recently please double check I didn't miss anything.



### Checklist

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants