Skip to content

Commit 2d313ab

Browse files
authored
Compiler dashboard feature (#7421)
# Overview Add Dashboard for compiler inductor non-aggreated data # Demo: you can access the new dashboard in list benchmark pages: https://torchci-git-compilerdashboard-fbopensource.vercel.app/benchmark/benchmark_list Or directly: https://torchci-git-compilerdashboard-fbopensource.vercel.app/benchmark/v3/dashboard/compiler_inductor # New features For Comparison Table : Compare Status in the comparison table, add another comparison policy that user define the statusComparison policy. By default, the UI assume all metric values are numeric, user need to add custom logics to display status properly status ``` export type BenchmarkStatusComparisonPolicy = { /** "good" (indicate desired value) */ goodValues?: string[]; goodValuePatterns?: string[]; /** "bad" (indicated failure) */ badValues?: string[]; badValuePatterns?: string[]; }; ``` Example use default, this will use default goodValuePatterns ['pass'],and default badValuePatterns: ['fail'] ``` comparisonPolicy: { accuracy: { target: "accuracy", type: "status", } } ``` user can also override it with their specific goodValues and badValues list or patterns. # Next step - Sync the link in regression page to dashboard detail page - A log component to provide logging info - Add CSV download for comparison table
1 parent 6abd688 commit 2d313ab

File tree

24 files changed

+612
-188
lines changed

24 files changed

+612
-188
lines changed

torchci/components/benchmark_v3/components/benchmarkSideBar/components/filters/DefaultSideBarMetricsDropdowns.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ export default function DefaultMetricsDropdowns() {
6969
const filters = {
7070
...stagedFilters,
7171
deviceName:
72-
stagedFilters.deviceName.length > 0
72+
stagedFilters?.deviceName?.length > 0
7373
? stagedFilters.deviceName
7474
: toDeviceName(stagedFilters.device, stagedFilters.arch),
7575
};

torchci/components/benchmark_v3/components/common/BackToMainButton.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,17 @@ import { useEffect, useRef } from "react";
99
export function BackToMainButton() {
1010
const router = useRouter();
1111
const renderGroupId = useDashboardSelector((s) => s.renderGroupId);
12+
1213
const { prevRef, currentRef } = useRouteHistory();
1314

1415
const handleClick = () => {
1516
if (prevRef.current) {
1617
router.back();
1718
} else {
19+
// if there is no history, push to main page with existing query params
1820
const { renderGroupId, ...rest } = router.query as Record<string, any>;
19-
const nextMainQuery = { ...rest, renderGroupId: "main" };
21+
22+
let nextMainQuery: any = { ...rest, renderGroupId: "main" };
2023

2124
// push the main page
2225
router.push(

torchci/components/benchmark_v3/components/common/RawContentDialog.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -149,15 +149,15 @@ export function RawContentDialog({
149149

150150
export function RenderRawContent({
151151
data,
152-
title,
153-
buttonName,
154-
type,
152+
title = "Raw Content",
153+
buttonName = "Raw Content",
154+
type = "json",
155155
component,
156156
}: {
157157
data: any;
158-
title: string;
159-
buttonName: string;
160-
type: "json" | "component";
158+
title?: string;
159+
buttonName?: string;
160+
type?: "json" | "component";
161161
component?: (data: any, title: string) => JSX.Element;
162162
}) {
163163
return (

torchci/components/benchmark_v3/components/common/SelectionDialog.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
} from "@mui/material";
88

99
import { Typography } from "@mui/material";
10-
import { resolveComponent } from "../../configs/configRegistration";
10+
import { resolveComponent } from "../../configs/helpers/configRegistration";
1111
import { RawTimeSeriesPoint } from "../dataRender/components/benchmarkTimeSeries/helper";
1212

1313
export interface TimeSeriesChartDialogContentProps {

torchci/components/benchmark_v3/components/dataRender/auto/autoComponents.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
import { UIRenderConfig } from "lib/benchmark/store/benchmark_config_book";
1010
import { useDashboardSelector } from "lib/benchmark/store/benchmark_dashboard_provider";
1111
import BenchmarkRawDataTable from "../components/benchmarkTimeSeries/components/BenchmarkRawDataTable";
12+
1213
import BenchmarkTimeSeriesChartGroup from "../components/benchmarkTimeSeries/components/BenchmarkTimeSeriesChart/BenchmarkTimeSeriesChartGroup";
1314
import { ComparisonTable } from "../components/benchmarkTimeSeries/components/BenchmarkTimeSeriesComparisonSection/BenchmarkTimeSeriesComparisonTable/ComparisonTable";
1415

torchci/components/benchmark_v3/components/dataRender/auto/defaultAutoRenderContent.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export function DefaultAutoRenderContent() {
2222
// if renderGroupId is not main, we try to find the subSectionRenders, auto fallback to main render if nothing is found
2323
if (renderGroupId != "main" && ctx.dataRender?.subSectionRenders) {
2424
autoUIConfigs =
25-
ctx.dataRender.subSectionRenders[renderGroupId].renders ?? [];
25+
ctx.dataRender.subSectionRenders[renderGroupId]?.renders ?? [];
2626
}
2727

2828
if (autoUIConfigs?.length === 0) {

torchci/components/benchmark_v3/components/dataRender/components/benchmarkTimeSeries/components/BenchmarkTimeSeriesChart/BenchmarkTimeSeriesChart.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,6 @@ const BenchmarkTimeSeriesChart: React.FC<Props> = ({
9595
displayName = rc?.displayName ?? meta.metric;
9696
}
9797

98-
console.log("p", p);
99-
10098
let legendKeyItems: string[] = [];
10199
if (renderOptions?.showLegendDetails) {
102100
legendKeys?.forEach((k) => {

torchci/components/benchmark_v3/components/dataRender/components/benchmarkTimeSeries/components/BenchmarkTimeSeriesComparisonSection/BenchmarkTimeSeriesComparisonTable/ComparisonTableColumnRendering.tsx

Lines changed: 62 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import {
2222
getBenchmarkTimeSeriesComparisonTableTarget,
2323
renderBasedOnUnitConifg,
2424
} from "../../../helper";
25-
import { asNumber, displayNameOf, valOf } from "./ComparisonTableHelpers";
25+
import { displayNameOf, valOf } from "./ComparisonTableHelpers";
2626

2727
/**
2828
*
@@ -122,6 +122,7 @@ export function getComparisionTableConlumnRendering(
122122
/** Colors */
123123
const VIOLATE_RULE_COLOR = "#ffebee"; // red[50]
124124
const IMPROVEMENT_COLOR = "#e8f5e9"; // green[50]
125+
const WARNING_COLOR = "#fff9c4"; // yellow[50]
125126

126127
export function ComparisonTablePrimaryFieldValueCell({
127128
params,
@@ -184,37 +185,22 @@ export function ComparisonTableColumnFieldValueCell({
184185
row.byWorkflow[rWorkflowId]?.[field]
185186
: undefined;
186187

187-
// get rabw value of left and right field
188+
// get raw value of left and right field
188189
const L = valOf(ldata);
189190
const R = valOf(rdata);
190191

191-
// assume l and r are numbers
192-
// todo(elainwy): support non-number values (e.g. string)
193-
const ln = asNumber(L);
194-
const rn = asNumber(R);
195-
196-
// get target field key name, for instance, metric
197-
// so we can get the comparison policy by get the value of target field
198192
const targetField = getBenchmarkTimeSeriesComparisonTableTarget();
199-
200193
const findFieldValueFromColData =
201194
ldata?.[targetField] ?? rdata?.[targetField];
202195
const targetVal = findFieldValueFromColData;
203196

204-
let comparisonPolicy: BenchmarkComparisonPolicyConfig | undefined = undefined;
205-
if (targetVal && config?.comparisonPolicy) {
206-
comparisonPolicy = targetVal
207-
? config?.comparisonPolicy[targetVal]
208-
: undefined;
209-
}
210-
211-
//console.log("ComparisonTableValueCell", ldata, rdata,targetField,row);
212-
// evaluate the value comparison result, return the comparison report for each field
213-
const result = evaluateComparison(
214-
comparisonPolicy?.target,
215-
ln,
216-
rn,
217-
comparisonPolicy
197+
const { result, text } = getComparisonResult(
198+
L,
199+
R,
200+
ldata,
201+
rdata,
202+
targetVal,
203+
config
218204
);
219205

220206
// pick background color based on result signals
@@ -226,14 +212,14 @@ export function ComparisonTableColumnFieldValueCell({
226212
case "regression":
227213
bgColor = VIOLATE_RULE_COLOR;
228214
break;
215+
case "warning":
216+
bgColor = WARNING_COLOR;
217+
break;
229218
case "neutral":
230219
default:
231220
break;
232221
}
233222

234-
const ldisplay = displayNameOf(ldata);
235-
const rdisplay = displayNameOf(rdata);
236-
const text = getFieldRender(targetVal, L, R, config, ldisplay, rdisplay);
237223
return (
238224
<Box sx={{ bgcolor: bgColor, borderRadius: 1, px: 0.5, py: 0.25 }}>
239225
<Tooltip title={renderComparisonResult(result)}>
@@ -268,12 +254,12 @@ export function getFieldRender(
268254
R: any,
269255
config?: ComparisonTableConfig,
270256
ldisplay?: string,
271-
rdisplay?: string
257+
rdisplay?: string,
258+
missingText: string = "N/A"
272259
) {
273260
if (ldisplay || rdisplay) {
274-
return `${ldisplay ?? "N/A"}${rdisplay ?? "N/A"}`;
261+
return `${ldisplay ?? missingText}${rdisplay ?? missingText}`;
275262
}
276-
277263
const rc = getBenchmarkTimeSeriesComparisionTableRenderingConfig(
278264
targetField,
279265
config
@@ -283,21 +269,61 @@ export function getFieldRender(
283269
export function formatTransitionWithUnit(
284270
L: any,
285271
R: any,
286-
table_unit?: BenchmarkUnitConfig
272+
table_unit?: BenchmarkUnitConfig,
273+
missingText: string = "N/A"
287274
): string {
288-
const formatValue = (v: any) =>
289-
v == null ? "N/A" : renderBasedOnUnitConifg(fmtFixed2(v), table_unit);
275+
const formatValue = (v: any) => {
276+
if (v == null || v == undefined) return missingText;
277+
const num = Number(v);
278+
const isNumeric = !isNaN(num) && v !== "";
279+
if (isNumeric) {
280+
return renderBasedOnUnitConifg(fmtFixed2(num), table_unit);
281+
}
282+
// non-numeric → render raw
283+
return String(v);
284+
};
285+
290286
if (L == null && R == null) {
291-
return "N/A";
287+
return missingText;
292288
}
289+
293290
if (L == null) {
294-
return `N/A${formatValue(R)}`;
291+
return `${missingText}${formatValue(R)}`;
295292
}
296293
if (R == null) {
297-
return `${formatValue(L)}N/A`;
294+
return `${formatValue(L)}${missingText}`;
298295
}
296+
299297
if (fmtFixed2(L) === fmtFixed2(R)) {
300298
return formatValue(L);
301299
}
302300
return `${formatValue(L)}${formatValue(R)}`;
303301
}
302+
303+
export function getComparisonResult(
304+
L: any,
305+
R: any,
306+
ldata: any,
307+
rdata: any,
308+
targetVal: string,
309+
config?: ComparisonTableConfig
310+
) {
311+
// get target field key name, for instance, metric
312+
// so we can get the comparison policy by get the value of target field
313+
314+
let policy: BenchmarkComparisonPolicyConfig | undefined = undefined;
315+
if (targetVal && config?.comparisonPolicy) {
316+
policy = targetVal ? config.comparisonPolicy[targetVal] : undefined;
317+
}
318+
// evaluate the value comparison result, return the comparison report for each field
319+
const result = evaluateComparison(policy?.target, L, R, policy);
320+
321+
const ldisplay = displayNameOf(ldata);
322+
const rdisplay = displayNameOf(rdata);
323+
const text = getFieldRender(targetVal, L, R, config, ldisplay, rdisplay);
324+
325+
return {
326+
result,
327+
text,
328+
};
329+
}

torchci/components/benchmark_v3/components/dataRender/components/benchmarkTimeSeries/components/BenchmarkTimeSeriesComparisonSection/BenchmarkTimeSeriesComparisonTable/ComparisonTableHelpers.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,14 @@ export type SnapshotRow = {
5252
};
5353

5454
/** Helpers */
55-
export const asNumber = (v: unknown) => (typeof v === "number" ? v : undefined);
55+
export const asNumber = (v: unknown): number | undefined => {
56+
if (typeof v === "number") return v;
57+
if (typeof v === "string" && v.trim() !== "") {
58+
const num = Number(v);
59+
return isNaN(num) ? undefined : num;
60+
}
61+
return undefined;
62+
};
5663
export const valOf = (cell?: RowCellObj) => (cell ? cell.value : undefined);
5764
export const displayNameOf = (cell?: RowCellObj) =>
5865
cell ? cell.displayName : undefined;

torchci/components/benchmark_v3/components/dataRender/components/benchmarkTimeSeries/helper.tsx

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -306,13 +306,12 @@ export function getBenchmarkTimeSeriesComparisonTableTarget(
306306
return config?.targetField ?? DEFAULT_TARGET_FILED;
307307
}
308308

309-
export const fmtFixed2 = (v: any) =>
310-
v == null
311-
? "—"
312-
: typeof v === "number"
313-
? Number(v).toFixed(2)
314-
: String(v.toFixed(2));
315-
309+
export const fmtFixed2 = (v: any) => {
310+
if (v == null) return "—";
311+
const num = Number(v);
312+
if (isNaN(num)) return String(v ?? ""); // not a valid number
313+
return num.toFixed(2);
314+
};
316315
/**
317316
* helper function to get the value from a nested object.
318317
* try to get the value from the keyPath, if not found, return the fallback value

0 commit comments

Comments
 (0)