Skip to content

perf(grid): rebuild only the rows and cells whose inputs changed (#972) - #973

Merged
ZhuchkaTriplesix merged 1 commit into
devfrom
issue/972-grid-row-rebuild-120hz
Sep 25, 2026
Merged

ZhuchkaTriplesix merged 1 commit into
devfrom
issue/972-grid-row-rebuild-120hz

Conversation

@ZhuchkaTriplesix

Copy link
Copy Markdown
Member

Описание изменений

Профиль по функциям (см. комментарий в #972) показал: правка одной ячейки пересобирала все видимые строки (~67% времени кадра), а внутри них ~25% уходило на inherited-lookups в каждой ячейке. Поэтому правки убирают саму пересборку неизменившегося, а не удешевляют ячейку.

  • VirtualResultGrid хранит последний _DataRow для каждой видимой строки и возвращает фреймворку тот же экземпляр, если новая сборка дала бы такую же строку (_DataRow.sameAs). Для == у Widget нельзя (он @nonVirtual), поэтому повторное использование идёт по экземпляру. Element.updateChild пропускает идентичный виджет.
  • _DataRow стал StatefulWidget и так же хранит _GridCell по колонкам (ячейки с ключом ValueKey(column)), поэтому при сдвиге окна колонок уже построенные ячейки не пересобираются.
  • Выделение и редактируемая ячейка передаются только в ту строку, которой они касаются, поэтому смена выделения не инвалидирует остальные строки.
  • DataGridStagingBuffer.rowRenderSignature(row): отпечаток статуса строки и изменённых ячеек, нужен, чтобы сравнение видело staged-изменения (буфер одна и та же изменяемая ссылка).
  • Окно колонок держится, пока все видимые колонки построены, а перестраивается при выходе за край (columnOverscan 2 → 6). Пересборка теперь раз в несколько колонок, а не на каждой.
  • Добавлен benchmark/grid_perf_bench.dart (MODE=scroll|edit, PROFILE=true печатает профиль по функциям).

Замеры (profile, Impeller GLES, AMD iGPU, 120 Гц, окно 4096×2576, 5000×120)

Сценарий build p50 / p90 кадров build > 8,33 мс
Скролл, до 0,67 / 79,6 мс 31 / 104
Скролл, после 0,67 / 1,46 мс 6 / 272
Правка на отсортированной сетке, до 31,7 / 49,7 мс 99 / 100
Правка на отсортированной сетке, после 2,50 / 3,78 мс 22 / 289

Критерии из #972 по build выполнены. Растр не менялся и теперь ограничивает: около 6–7 мс p50 и 9–16 мс p90 на таком окне, то есть часть кадров при панорамировании всё ещё не укладывается в 8,33 мс по растру. Это отдельная работа (меньше draw-операций на ячейку).

Тесты

  • result_grid_sorting_model_test: правка одной ячейки пересобирает только свою строку, смена выделения затрагивает только старую и новую строки, staged-статус по-прежнему перерисовывает строку, ячейки внутри окна переиспользуются при скролле.
  • data_grid_staging_buffer_test: rowRenderSignature меняется только вместе со staged-состоянием своей строки.
  • Весь каталог test/features/workspace (253 теста) прогнал локально, все проходят.

Не входит

  • Растровая часть (см. выше).
  • Ширины колонок: если таблица уже окна и ширины перераспределяются по содержимому, правка текста может законно менять ширины и пересобрать все строки.

Связанные Issue

Closes #972

 #972)

A staged cell edit rebuilt every visible row, and each row rebuilt all of its
cells; a function-level profile showed ~67% of frame time in that rebuild and
~25% in per-cell inherited lookups. Panning also rebuilt the whole window on
every column boundary.

- VirtualResultGrid keeps the last _DataRow per visual row and hands the
  framework the same instance when a rebuild would produce an identical row;
  _DataRow keeps the same per column for _GridCell (keyed by column). Widgets
  cannot override ==, so reuse is by instance with a sameAs comparison.
- Selection and editing cell are clipped to the row they touch, so a selection
  change no longer invalidates every row.
- DataGridStagingBuffer.rowRenderSignature fingerprints the staged state that
  affects drawing a row (status and modified cells).
- The column window is kept until the viewport reaches its edge, with a wider
  overscan (6), so it is rebuilt every few columns instead of on each one.
- Add benchmark/grid_perf_bench.dart for repeatable frame-timing and CPU
  profile runs in profile mode.
@github-actions github-actions Bot added frontend Theme parser epic label: frontend performance Theme parser epic label: performance ui User interface components and widgets data-grid Interactive data grid, cell editor, filtering, groupings labels Sep 25, 2026
@ZhuchkaTriplesix
ZhuchkaTriplesix merged commit 0c2369e into dev Sep 25, 2026
4 checks passed
@ZhuchkaTriplesix
ZhuchkaTriplesix deleted the issue/972-grid-row-rebuild-120hz branch September 28, 2026 08:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

data-grid Interactive data grid, cell editor, filtering, groupings frontend Theme parser epic label: frontend performance Theme parser epic label: performance ui User interface components and widgets

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant