Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 31 additions & 3 deletions packages/app/src/components/inference/ui/ChartDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import { ChartShareActions, MetricAssumptionNotes } from '@/components/ui/chart-
import { UnofficialDomainNotice } from '@/components/ui/unofficial-domain-notice';
import { exportToCsv } from '@/lib/csv-export';
import { inferenceChartToCsv } from '@/lib/csv-export-helpers';
import { knownIssueCsvNote, matchKnownConfigIssues } from '@/lib/known-issues';
import { getDisplayLabel } from '@/lib/utils';
import {
Dialog,
DialogContent,
Expand All @@ -43,7 +45,7 @@ import {
} from '@/lib/data-mappings';
import { useComparisonChangelogs } from '@/hooks/api/use-comparison-changelogs';
import { useTrendData } from '@/components/inference/hooks/useTrendData';
import { hardwareKeyMatchesAnyBase } from '@/lib/constants';
import { getHardwareConfig, hardwareKeyMatchesAnyBase } from '@/lib/constants';

import ChartControls from './ChartControls';
import ComparisonChangelog from './ComparisonChangelog';
Expand Down Expand Up @@ -171,8 +173,14 @@ export default function ChartDisplay() {
track('inference_view_changed', { view: value, chartIndex: index });
};

const { unofficialRunInfo, unofficialRunInfos, runIndexByUrl, getOverlayData, isUnofficialRun } =
useUnofficialRun();
const {
unofficialRunInfo,
unofficialRunInfos,
runIndexByUrl,
getOverlayData,
isUnofficialRun,
activeOverlayHwTypes,
} = useUnofficialRun();

// Compute overlay data for each chart type — must match useChartData processing
const overlayDataByChartType = useMemo(() => {
Expand Down Expand Up @@ -383,10 +391,30 @@ export default function ChartDisplay() {
graph.model,
graph.sequence,
);
// Match warnings against the same series the chart annotates,
// including visible unofficial-run overlay series.
const overlay =
graph.chartDefinition.chartType === 'e2e'
? overlayDataByChartType.e2e
: overlayDataByChartType.interactivity;
const visibleOverlayRows = isTimelineMode
? []
: (overlay?.data ?? []).filter(
(p) =>
activeOverlayHwTypes.has(p.hwKey as string) &&
selectedPrecisions.includes(p.precision),
);
const issueNotes = matchKnownConfigIssues(graph.model, [
...visibleData,
...visibleOverlayRows,
]).map((issue) =>
knownIssueCsvNote(issue, getDisplayLabel(getHardwareConfig(issue.hwKey))),
);
exportToCsv(
`InferenceX_${selectedModel}_${graph.chartDefinition.chartType}`,
headers,
rows,
issueNotes,
Comment thread
adibarra marked this conversation as resolved.
Comment thread
adibarra marked this conversation as resolved.
);
}}
/>
Expand Down
73 changes: 72 additions & 1 deletion packages/app/src/components/inference/ui/GPUGraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ import {
generateGPUGraphTooltipContent,
getPointLabel,
} from '@/components/inference/utils/tooltipUtils';
import {
type KnownIssueAnnotation,
measureLegendRightInset,
renderKnownIssueAnnotations,
} from '@/components/inference/utils/knownIssueAnnotations';
import { matchKnownConfigIssues } from '@/lib/known-issues';

const CHART_MARGIN = { top: 24, right: 10, bottom: 60, left: 60 };

Expand All @@ -58,7 +64,7 @@ function labelTextFor(pts: InferenceData[]): string {
}

const GPUGraph = React.memo(
({ chartId, data, xLabel, yLabel, chartDefinition, caption }: ScatterGraphProps) => {
({ chartId, modelLabel, data, xLabel, yLabel, chartDefinition, caption }: ScatterGraphProps) => {
const {
hardwareConfig,
selectedPrecisions,
Expand Down Expand Up @@ -211,6 +217,70 @@ const GPUGraph = React.memo(
return pts;
}, [groupedData, activeDates, hideNonOptimal, optimalPointKeys]);

// Warning annotations for visible series with known upstream issues —
// same treatment the scatter view gets, applied to the date-comparison view.
// Lines here are colored per (gpu, date) pair, so take the first active
// pair's color as the series swatch.
const knownIssueAnnotations = useMemo(
(): KnownIssueAnnotation[] =>
matchKnownConfigIssues(modelLabel, filteredData).map((issue) => {
const cfg = getHardwareConfig(issue.hwKey);
const colorEntry = allGraphs.find(
(entry) => entry.hwKey === issue.hwKey && activeDates.has(entry.id),
);
return {
issue,
label: cfg ? getDisplayLabel(cfg) : issue.hwKey,
color: getCssColor(colorEntry?.color ?? resolveColor(issue.hwKey)),
points: filteredData
.filter(
(p) =>
String(p.hwKey) === issue.hwKey &&
(!issue.precisions || issue.precisions.includes(p.precision)),
)
.map((p) => ({ x: p.x, y: p.y })),
};
}),
[modelLabel, filteredData, allGraphs, activeDates, resolveColor, getCssColor],
);

const drawKnownIssues = (
ctx: RenderContext,
xScale: ContinuousScale,
yScale: ContinuousScale,
) => {
renderKnownIssueAnnotations(ctx.layout.g, ctx.layout.defs, {
chartId,
width: ctx.width,
height: ctx.height,
xScale,
yScale,
annotations: knownIssueAnnotations,
rightInset: measureLegendRightInset(
chartId,
ctx.layout.svg.node(),
ctx.layout.margin.left,
ctx.width,
),
background: getCssColor('--background'),
foreground: getCssColor('--foreground'),
mutedForeground: getCssColor('--muted-foreground'),
onLinkClick: (a) =>
track('inference_known_issue_clicked', {
hwKey: a.issue.hwKey,
issue: a.issue.issueRef,
}),
});
};
const knownIssueLayer: CustomLayerConfig = {
type: 'custom',
key: 'known-issues',
render: (_zoomGroup, ctx) =>
drawKnownIssues(ctx, ctx.xScale as ContinuousScale, ctx.yScale as ContinuousScale),
onZoom: (_zoomGroup, ctx) =>
drawKnownIssues(ctx, ctx.newXScale as ContinuousScale, ctx.newYScale as ContinuousScale),
};

// Compute scale domains
const xExtent = useMemo(() => {
if (filteredData.length === 0) return [0, 100] as [number, number];
Expand Down Expand Up @@ -649,6 +719,7 @@ const GPUGraph = React.memo(
},
},
lineLabelLayer,
knownIssueLayer,
]}
zoom={{
enabled: true,
Expand Down
76 changes: 76 additions & 0 deletions packages/app/src/components/inference/ui/ScatterGraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { useUnofficialRun } from '@/components/unofficial-run-provider';
import { computeToggle } from '@/hooks/useTogglableSet';
import { getHardwareConfig, getModelSortIndex } from '@/lib/constants';
import { getChartWatermark, getPrecisionLabel, type Precision } from '@/lib/data-mappings';
import { matchKnownConfigIssues } from '@/lib/known-issues';
import { formatNumber, getDisplayLabel, updateRepoUrl } from '@/lib/utils';
import { D3Chart } from '@/lib/d3-chart/D3Chart';
import type {
Expand Down Expand Up @@ -62,6 +63,11 @@ import {
PARETO_LABEL_COLORS,
buildGradientColorMap,
} from '@/components/inference/utils/paretoLabels';
import {
type KnownIssueAnnotation,
measureLegendRightInset,
renderKnownIssueAnnotations,
} from '@/components/inference/utils/knownIssueAnnotations';

// X-shape path for overlay (unofficial) data points
const X_SIZE = 5;
Expand Down Expand Up @@ -112,6 +118,7 @@ const lineLabelText = (hwKey: string, precision: string, includePrecision: boole
const ScatterGraph = React.memo(
({
chartId,
modelLabel,
data,
xLabel,
yLabel,
Expand Down Expand Up @@ -340,6 +347,35 @@ const ScatterGraph = React.memo(
return overlayData.data.filter((p) => selectedPrecisions.includes(p.precision));
}, [overlayData, selectedPrecisions]);

// Warning annotations for visible series (official + unofficial overlay)
// with known upstream issues. Drawn as an SVG layer (box + arrow to the
// affected line) so PNG exports carry the warning.
const knownIssueAnnotations = useMemo((): KnownIssueAnnotation[] => {
const visibleOverlayPoints = processedOverlayData.filter((p) =>
activeOverlayHwTypes.has(p.hwKey as string),
);
const visiblePoints = [...filteredData, ...visibleOverlayPoints];
return matchKnownConfigIssues(modelLabel, visiblePoints).map((issue) => ({
issue,
label: parseHwKeyToLabel(issue.hwKey).label,
color: getCssColor(resolveColor(issue.hwKey)),
points: visiblePoints
.filter(
(p) =>
String(p.hwKey) === issue.hwKey &&
(!issue.precisions || issue.precisions.includes(p.precision)),
)
.map((p) => ({ x: p.x, y: p.y })),
}));
}, [
modelLabel,
filteredData,
processedOverlayData,
activeOverlayHwTypes,
resolveColor,
getCssColor,
]);

// Combined data for D3 scale domain (includes overlay so scales fit both datasets)
const chartScaleData = useMemo(() => {
if (processedOverlayData.length === 0) return filteredData;
Expand Down Expand Up @@ -1760,11 +1796,51 @@ const ScatterGraph = React.memo(
},
};

// ── Known-issue annotations: warning box + arrow to the affected line ──
const drawKnownIssues = (
ctx: RenderContext,
xScale: ContinuousScale,
yScale: ContinuousScale,
) => {
renderKnownIssueAnnotations(ctx.layout.g, ctx.layout.defs, {
chartId,
width: ctx.width,
height: ctx.height,
xScale,
yScale,
annotations: knownIssueAnnotations,
rightInset: measureLegendRightInset(
chartId,
ctx.layout.svg.node(),
ctx.layout.margin.left,
ctx.width,
),
background: getCssColor('--background'),
foreground: getCssColor('--foreground'),
mutedForeground: getCssColor('--muted-foreground'),
onLinkClick: (a) =>
track('inference_known_issue_clicked', {
hwKey: a.issue.hwKey,
issue: a.issue.issueRef,
}),
});
};
const knownIssueLayer: CustomLayerConfig = {
type: 'custom',
key: 'known-issues',
render: (_zoomGroup, ctx) =>
drawKnownIssues(ctx, ctx.xScale as ContinuousScale, ctx.yScale as ContinuousScale),
onZoom: (_zoomGroup, ctx) =>
drawKnownIssues(ctx, ctx.newXScale as ContinuousScale, ctx.newYScale as ContinuousScale),
};

const result: LayerConfig<InferenceData>[] = [rooflineLayer, scatterLayer];
if (overlayLayer) result.push(overlayLayer);
result.push(speedOverlayLayer);
result.push(knownIssueLayer);
return result;
}, [
knownIssueAnnotations,
rooflines,
allPointLabelsByKey,
showGradientLabels,
Expand Down
Loading
Loading