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

Optimized in-memory datagrid mount performance #3628

Merged

Conversation

chandlerprall
Copy link
Contributor

@chandlerprall chandlerprall commented Jun 17, 2020

Summary

  • Mutation observer previously wrapped each individual in-memory cell, this has been moved to a single observer wrapping the entire in-memory table
  • Less components are rendered in the Virtual DOM hierarchy
  • onCellRender callback updated to mutate the values object instead of cloning every time a cell reports a new value

Performance

I modified the in_memory_sorting.js example and took the timings from the first 3 togglings-on

see modified example file
import React, { Fragment, useCallback, useMemo, useState } from 'react';
import { fake } from 'faker';

import { EuiDataGrid, EuiLink, EuiButton } from '../../../../src/components/';

const columns = [
  {
    id: 'name',
  },
  {
    id: 'email',
  },
  {
    id: 'location',
  },
  {
    id: 'account',
  },
  {
    id: 'date',
  },
  {
    id: 'amount',
  },
  {
    id: 'phone',
  },
  {
    id: 'version',
  },
];

const raw_data = [];

for (let i = 1; i < 1000; i++) {
  raw_data.push({
    name: fake('{{name.lastName}}, {{name.firstName}} {{name.suffix}}'),
    email: <EuiLink href="">{fake('{{internet.email}}')}</EuiLink>,
    location: (
      <Fragment>
        {`${fake('{{address.city}}')}, `}
        <EuiLink href="https://google.com">
          {fake('{{address.country}}')}
        </EuiLink>
      </Fragment>
    ),
    date: fake('{{date.past}}'),
    account: fake('{{finance.account}}'),
    amount: fake('${{commerce.price}}'),
    phone: fake('{{phone.phoneNumber}}'),
    version: fake('{{system.semver}}'),
  });
}

export default () => {
  // ** Pagination config
  const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 1 });
  const onChangeItemsPerPage = useCallback(
    pageSize =>
      setPagination(pagination => ({ ...pagination, pageSize, pageIndex: 0 })),
    [setPagination]
  );
  const onChangePage = useCallback(
    pageIndex => setPagination(pagination => ({ ...pagination, pageIndex })),
    [setPagination]
  );

  // ** Sorting config
  const [sortingColumns, setSortingColumns] = useState([]);
  const onSort = useCallback(
    sortingColumns => {
      setSortingColumns(sortingColumns);
    },
    [setSortingColumns]
  );

  // Column visibility
  const [visibleColumns, setVisibleColumns] = useState(() =>
    columns.map(({ id }) => id)
  ); // initialize to the full set of columns

  const renderCellValue = useMemo(() => {
    return ({ rowIndex, columnId }) => {
      return raw_data.hasOwnProperty(rowIndex)
        ? raw_data[rowIndex][columnId]
        : null;
    };
  }, []);

  const [isOpen, setIsOpen] = useState(false);

  return (
    <>
      <EuiButton onClick={() => setIsOpen(!isOpen)}>toggle</EuiButton>
      {isOpen && (
        <EuiDataGrid
          aria-label="inMemory level set to sorting data grid demo"
          columns={columns}
          columnVisibility={{ visibleColumns, setVisibleColumns }}
          rowCount={raw_data.length}
          renderCellValue={renderCellValue}
          inMemory={{ level: 'sorting' }}
          sorting={{ columns: sortingColumns, onSort }}
          pagination={{
            ...pagination,
            pageSizeOptions: [10, 50, 100],
            onChangeItemsPerPage: onChangeItemsPerPage,
            onChangePage: onChangePage,
          }}
        />
      )}
    </>
  );
};

Previous
Mount - 2760ms, 2520ms, 2400ms
Set inMemory values - 349ms, 384ms, 326ms

Optimized
Mount - 1160ms, 1040ms, 946ms
Set inMemory values - 119ms, 92ms, 95ms

Checklist

- [ ] Check against all themes for compatibility in both light and dark modes

  • Checked in mobile
  • Checked in IE11 and Firefox
    - [ ] Props have proper autodocs
    - [ ] Added documentation
  • Checked Code Sandbox works for the any docs examples
    - [ ] Added or updated jest tests
  • Checked for breaking changes and labeled appropriately
    - [ ] Checked for accessibility including keyboard-only and screenreader modes
    - [ ] A changelog entry exists and is marked appropriately

@chandlerprall
Copy link
Contributor Author

PUPPETEER_SKIP_CHROMIUM_DOWNLOAD

jenkins test this

@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_3628/

Copy link
Contributor

@snide snide left a comment

Choose a reason for hiding this comment

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

I did a functional test to see if anything changed. I noticed a sorting error (maybe, could just be unclear docs) that also seems to happen in master.

Column sorting in particular is going to be imprecise because there is no backend service to call, and data grid instead defaults to naively applying JavaScript's default array sort which doesn't work well with numeric data and doesn't sort React elements such as the links. This is a good example of what happens when you don't utilize schemas for complex data.

Should we instead say that sorting does not work at all? It gives the impression it would try? This might be because we now pass these things as react elements where we didn't before (possibly before it was just as strings).

Basically, this is unrelated to this PR, but we might want to clean up the docs while we're in there.

Enhancements only sorting does not apply

image

Enhancements with pagination does

image

@snide
Copy link
Contributor

snide commented Jun 18, 2020

^^ ignore my comment above. The location is a React node that has links in it. The docs are clear, I just didn't notice the makeup of that column.

Copy link
Contributor

@snide snide left a comment

Choose a reason for hiding this comment

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

I see no functional changes or regressions from this change. I did not review the code.

Copy link
Contributor

@thompsongl thompsongl left a comment

Choose a reason for hiding this comment

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

Code changes look good. I really like the version approach.
Was able to verify substantial performance improvements via profiling
🚀

@chandlerprall chandlerprall merged commit 5318c2f into elastic:master Jun 18, 2020
@chandlerprall chandlerprall deleted the datagrid-inmemory-mount-performance branch June 18, 2020 20:23
@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_3628/

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.

4 participants