From a2fcc9716658be2f6d654358c6784ba89492dc38 Mon Sep 17 00:00:00 2001 From: Oseltamivir <58582368+Oseltamivir@users.noreply.github.com> Date: Sun, 9 Aug 2026 20:37:10 +0800 Subject: [PATCH] fix(inference): retain clipped rows in table view MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restore cost- and latency-clipped points when rendering inference tables while preserving chart display limits. Include clipped official and unofficial rows in visibility scopes and add component regression coverage. 中文:修复推理表格遗漏超出图表显示上限的数据行。表格恢复成本和延迟裁剪点,同时保留图表显示限制;官方与 unofficial overlay 路径均纳入可见范围并补充组件回归测试。 --- .../cypress/component/scatter-graph.cy.tsx | 104 ++++++++++++++++++ .../components/inference/ui/ChartDisplay.tsx | 34 +++++- 2 files changed, 133 insertions(+), 5 deletions(-) diff --git a/packages/app/cypress/component/scatter-graph.cy.tsx b/packages/app/cypress/component/scatter-graph.cy.tsx index d041b9a8..a4b6c380 100644 --- a/packages/app/cypress/component/scatter-graph.cy.tsx +++ b/packages/app/cypress/component/scatter-graph.cy.tsx @@ -938,6 +938,110 @@ describe('ScatterGraph', () => { }); describe('ChartDisplay engine comparison guard', () => { + it('includes cost-clipped official and unofficial points in table mode', () => { + const chartDefinition = createMockChartDefinition({ + chartType: 'interactivity', + x: 'median_intvty', + x_label: 'Interactivity (tok/s/user)', + y_costhOutput: 'costhOutput.y', + y_costhOutput_label: 'Cost per Million Output Tokens ($)', + y_costhOutput_roofline: 'lower_right', + y_cost_limit: 5, + }); + const officialVisible = createMockInferenceData({ + hwKey: 'b200_sglang', + precision: Precision.FP4, + tp: 4, + median_intvty: 134.7, + costhOutput: { y: 4, roof: true }, + }); + const officialClipped = createMockInferenceData({ + hwKey: 'b200_sglang', + precision: Precision.FP4, + tp: 8, + median_intvty: 142.1, + costhOutput: { y: 7.016, roof: true }, + }); + const runUrl = 'https://github.com/x/y/actions/runs/707'; + const overlayVisible = createMockInferenceData({ + hwKey: 'h100_vllm', + precision: Precision.FP4, + tp: 4, + median_intvty: 130, + costhOutput: { y: 4.5, roof: true }, + run_url: runUrl, + }); + const overlayClipped = createMockInferenceData({ + hwKey: 'h100_vllm', + precision: Precision.FP4, + tp: 8, + median_intvty: 145, + costhOutput: { y: 7.5, roof: true }, + run_url: runUrl, + }); + const runInfo = { + id: 707, + name: 'clipped-table-overlay', + branch: 'clipped-table-overlay', + sha: 'abc707', + createdAt: '2026-08-09T00:00:00Z', + url: runUrl, + conclusion: 'success', + status: 'completed', + isNonMainBranch: true, + }; + + mountWithProviders(, { + inference: { + graphs: [ + { + model: Model.DeepSeek_R1, + sequence: Sequence.EightK_OneK, + chartDefinition, + data: [officialVisible], + clippedData: [{ point: officialClipped, reasons: ['cost'] }], + }, + ], + selectedYAxisMetric: 'y_costhOutput', + selectedXAxisMode: 'interactivity', + activeHwTypes: new Set(['b200_sglang']), + hwTypesWithData: new Set(['b200_sglang']), + }, + globalFilters: { + selectedModel: Model.DeepSeek_R1, + selectedSequence: Sequence.EightK_OneK, + effectiveSequence: Sequence.EightK_OneK, + }, + unofficial: { + isUnofficialRun: true, + unofficialRunInfo: runInfo, + unofficialRunInfos: [runInfo], + runIndexByUrl: { [runUrl]: 0, '707': 0 }, + getOverlayData: () => ({ + data: [overlayVisible, overlayClipped], + hardwareConfig: hwConfig, + }), + activeOverlayHwTypes: new Set(['h100_vllm']), + allOverlayHwTypes: new Set(['h100_vllm']), + }, + }); + + cy.get('[data-testid="inference-table-view-btn"]').click(); + cy.get('[data-testid="inference-results-table"] tbody tr').should('have.length', 4); + cy.get('[data-testid="inference-results-table"] tbody') + .contains('tr', '7.0') + .should('contain.text', 'SGLang') + .find('td') + .eq(2) + .should('have.text', '8'); + cy.get('[data-testid="inference-results-table"] tbody') + .contains('tr', '7.5') + .should('contain.text', 'vLLM') + .find('td') + .eq(2) + .should('have.text', '8'); + }); + it('keeps official table rows synchronized with legend state after a scope change', () => { const chartDefinition = createMockChartDefinition({ chartType: 'interactivity' }); const baseInference = createMockInferenceContext(); diff --git a/packages/app/src/components/inference/ui/ChartDisplay.tsx b/packages/app/src/components/inference/ui/ChartDisplay.tsx index 4de9bfe2..84df1055 100644 --- a/packages/app/src/components/inference/ui/ChartDisplay.tsx +++ b/packages/app/src/components/inference/ui/ChartDisplay.tsx @@ -415,7 +415,11 @@ export default function ChartDisplay() { const overlayScope = useMemo(() => { const eligibleKeys = new Set(); for (const overlay of [overlayDataByChartType.e2e, overlayDataByChartType.interactivity]) { - for (const point of overlay?.data ?? []) { + const points = [ + ...(overlay?.data ?? []), + ...(overlay?.clippedData ?? []).map((entry) => entry.point), + ]; + for (const point of points) { const key = String(point.hwKey); if ( selectedPrecisions.includes(point.precision) && @@ -430,7 +434,8 @@ export default function ChartDisplay() { const officialScope = useMemo(() => { const eligibleKeys = new Set(); for (const graph of graphs) { - for (const point of graph.data) { + const points = [...graph.data, ...(graph.clippedData ?? []).map((entry) => entry.point)]; + for (const point of points) { if ( selectedPrecisions.includes(point.precision) && matchesQuickFilters(point, quickFilters) @@ -538,7 +543,9 @@ export default function ChartDisplay() { if (graphs.length > 0) return graphs; const hasOverlay = (overlayDataByChartType.e2e?.data.length ?? 0) > 0 || - (overlayDataByChartType.interactivity?.data.length ?? 0) > 0; + (overlayDataByChartType.e2e?.clippedData?.length ?? 0) > 0 || + (overlayDataByChartType.interactivity?.data.length ?? 0) > 0 || + (overlayDataByChartType.interactivity?.clippedData?.length ?? 0) > 0; if (!hasOverlay) return graphs; return (chartDefinitions as ChartDefinition[]).map((chartDefinition) => ({ model: selectedModel, @@ -835,9 +842,26 @@ export default function ChartDisplay() { graph.chartDefinition.chartType, overlayDataByChartType, ); + // Display limits keep outliers off the plotted domain but + // must not silently remove measured rows from the table. + // Restore both official and unofficial clipped points before + // applying the shared precision, quick-filter, and legend gates. + const tableOfficialData = [ + ...graph.data, + ...(graph.clippedData ?? []).map((entry) => entry.point), + ]; + const tableOverlay = overlay + ? { + ...overlay, + data: [ + ...overlay.data, + ...(overlay.clippedData ?? []).map((entry) => entry.point), + ], + } + : overlay; const { officialRows, overlayRows } = visibleComparisonRows( - graph.data, - overlay, + tableOfficialData, + tableOverlay, ); return ( <>