Summary
The data grid creates semantics for every visible cell. On Linux the embedder keeps the semantics tree enabled at all times (SemanticsBinding.instance.semanticsEnabled == true in a normal session), and on Windows it is enabled whenever any UI Automation client is attached. Rebuilding that tree is one of the largest per-frame costs of the grid, and it is invisible in FrameTiming.buildDuration because flushSemantics runs after Render, while still blocking the UI thread before the next frame.
Evidence (profile, Linux, window 2056×2616)
benchmark/grid_perf_bench.dart, engine timeline totals:
| Scenario |
SEMANTICS |
LAYOUT |
BUILD |
| New result set every 400 ms (5000×20), current |
565 ms / 31 frames |
543 ms |
288 ms |
Same, rows wrapped in ExcludeSemantics (experiment) |
38 ms / 33 frames |
542 ms |
281 ms |
≈ 17 ms of semantics per new result set. Horizontal scroll: ≈ 1.9 ms of semantics per frame (555 ms / 298 frames).
Scope
- Give each grid row one semantics node (e.g. a label joining header + value pairs, or at least the row index and values), instead of one node per cell with gesture actions.
- Keep the grid usable with a screen reader (row-level reading; cell actions via the existing keyboard shortcuts).
- Re-measure with
MODE=rerun and MODE=scroll, including the SEMANTICS timeline phase (not only FrameTiming).
Out of scope
Disabling semantics globally (accessibility must keep working).
Summary
The data grid creates semantics for every visible cell. On Linux the embedder keeps the semantics tree enabled at all times (
SemanticsBinding.instance.semanticsEnabled == truein a normal session), and on Windows it is enabled whenever any UI Automation client is attached. Rebuilding that tree is one of the largest per-frame costs of the grid, and it is invisible inFrameTiming.buildDurationbecauseflushSemanticsruns afterRender, while still blocking the UI thread before the next frame.Evidence (profile, Linux, window 2056×2616)
benchmark/grid_perf_bench.dart, engine timeline totals:ExcludeSemantics(experiment)≈ 17 ms of semantics per new result set. Horizontal scroll: ≈ 1.9 ms of semantics per frame (555 ms / 298 frames).
Scope
MODE=rerunandMODE=scroll, including the SEMANTICS timeline phase (not onlyFrameTiming).Out of scope
Disabling semantics globally (accessibility must keep working).