ui: Paginate GpuCompute summary table Limit the summary table to 100 rows per page with prev/next pagination controls. Previously the entire table (potentially thousands of rows with percent-bar elements) was rendered into the DOM, causing expensive browser paint and hit-test operations on every frame even when the vdom itself was skipped.
diff --git a/ui/src/plugins/com.meta.GpuCompute/summary.ts b/ui/src/plugins/com.meta.GpuCompute/summary.ts index d3e10ce..f7f4666 100644 --- a/ui/src/plugins/com.meta.GpuCompute/summary.ts +++ b/ui/src/plugins/com.meta.GpuCompute/summary.ts
@@ -27,6 +27,7 @@ COMPUTE_RENDER_STAGE_CATEGORY, } from './details'; import {Icons} from '../../base/semantic_icons'; +import {Button} from '../../widgets/button'; import {Icon} from '../../widgets/icon'; import type {GpuComputeContext} from './index'; import {adjustSeconds} from './humanize'; @@ -42,6 +43,8 @@ gridSize: number | string | null; }; +const PAGE_SIZE = 100; + // Component state holding the fetched rows and per-column max values. type SummaryState = { rows?: SummaryRow[]; @@ -54,6 +57,7 @@ sortKey: SortKey | null; sortDescending: boolean; dirty: boolean; + pageOffset: number; }; // Renders a bar whose width is proportional to `val / max`. @@ -272,6 +276,7 @@ state.launchIndexBySliceId = new Map(); state.sortKey = 'id'; state.sortDescending = false; + state.pageOffset = 0; const rows = await fetchKernelSummaryRows(attrs.ctx, attrs.engine); @@ -359,6 +364,7 @@ state.sortKey = key; state.sortDescending = true; } + state.pageOffset = 0; state.dirty = true; m.redraw(); }; @@ -426,67 +432,97 @@ m( 'tbody', - sortedRows.map((r) => - m( - 'tr.pf-gpu-compute__summary-row', - { - ondblclick: () => attrs.openSliceInDetail?.(r.id), - }, - [ - m( - 'td.pf-gpu-compute__summary-td', - String(launchIndexBySliceId.get(r.id) ?? r.id), - ), - m( - 'td.pf-gpu-compute__summary-td.pf-gpu-compute__summary-td--name', - {title: r.demangledName}, - r.demangledName, - ), - m( - 'td.pf-gpu-compute__summary-td', - renderRelPercentBar( - Number(r.durationNSecNum), - state.maxDurationNSec, - label(Number(r.durationNSecNum), 'nsecond'), + sortedRows + .slice(state.pageOffset, state.pageOffset + PAGE_SIZE) + .map((r) => + m( + 'tr.pf-gpu-compute__summary-row', + { + ondblclick: () => attrs.openSliceInDetail?.(r.id), + }, + [ + m( + 'td.pf-gpu-compute__summary-td', + String(launchIndexBySliceId.get(r.id) ?? r.id), ), - ), - m( - 'td.pf-gpu-compute__summary-td', - renderRelPercentBar( - Number(r.computePct), - state.maxComputePct, - label(r.computePct), + m( + 'td.pf-gpu-compute__summary-td.pf-gpu-compute__summary-td--name', + {title: r.demangledName}, + r.demangledName, ), - ), - m( - 'td.pf-gpu-compute__summary-td', - renderRelPercentBar( - Number(r.memoryPct), - state.maxMemoryPct, - label(r.memoryPct), + m( + 'td.pf-gpu-compute__summary-td', + renderRelPercentBar( + Number(r.durationNSecNum), + state.maxDurationNSec, + label(Number(r.durationNSecNum), 'nsecond'), + ), ), - ), - m( - 'td.pf-gpu-compute__summary-td', - renderRelPercentBar( - Number(r.registersPerThread), - state.maxRegisters, - label(r.registersPerThread), + m( + 'td.pf-gpu-compute__summary-td', + renderRelPercentBar( + Number(r.computePct), + state.maxComputePct, + label(r.computePct), + ), ), - ), - m( - 'td.pf-gpu-compute__summary-td', - renderRelPercentBar( - Number(r.gridSize), - state.maxGridSize, - label(r.gridSize), + m( + 'td.pf-gpu-compute__summary-td', + renderRelPercentBar( + Number(r.memoryPct), + state.maxMemoryPct, + label(r.memoryPct), + ), ), - ), - ], + m( + 'td.pf-gpu-compute__summary-td', + renderRelPercentBar( + Number(r.registersPerThread), + state.maxRegisters, + label(r.registersPerThread), + ), + ), + m( + 'td.pf-gpu-compute__summary-td', + renderRelPercentBar( + Number(r.gridSize), + state.maxGridSize, + label(r.gridSize), + ), + ), + ], + ), ), - ), ), ]), + sortedRows.length > PAGE_SIZE && + m('.pf-gpu-compute__summary-pagination', [ + m(Button, { + icon: Icons.PrevPage, + disabled: state.pageOffset === 0, + onclick: () => { + state.pageOffset = Math.max(0, state.pageOffset - PAGE_SIZE); + state.dirty = true; + m.redraw(); + }, + }), + m( + 'span', + `${state.pageOffset + 1}–${Math.min(state.pageOffset + PAGE_SIZE, sortedRows.length)} of ${sortedRows.length}`, + ), + m(Button, { + icon: Icons.NextPage, + disabled: state.pageOffset + PAGE_SIZE >= sortedRows.length, + onclick: () => { + state.pageOffset = Math.min( + state.pageOffset + PAGE_SIZE, + sortedRows.length - PAGE_SIZE, + ); + state.dirty = true; + m.redraw(); + }, + }), + ]), ); }, };