Skip to content

Commit c5db0d8

Browse files
authored
Build dynamic rendering with compiler regression page (#7163)
## Overview Build dynamic rendering with compiler regression page set up benchmark compiler page to render dynamically based on the request, most of the component will be reused as we migrate our ui to dynamic rendering. ## Data management use zustand as context provider to track global data state within the page. ## Customized support Currently we support customized data bridges, the main way to adjust customized fields and metrics 1. initial queryParams 2. queryParamsConverter 3. dataRenderSection for timeserids display and dropdownList in side bar ## Sticky Search Side Bar with dynamic changes Set up a sticky search side bar that only applies changes if timerange, metrics and branches are changed. ### Logics: The branch list is dynamically rendered when timeRange or metric filters are changed. the apply will disable if user changes the timerange and metrics, but no branch data exist ### Why do this way Benchmark data fetching can be expensive (> 6 ~ 10 secs),it should only apply changes when user tuned the query params in an ideal stage ## Demo https://torchci-git-newcompileruiclean-fbopensource.vercel.app/benchmark/compilers_regression <img width="315" height="829" alt="image" src="https://github.com/user-attachments/assets/f2dc091e-6102-4743-8275-9bb9a7798e11" /> ## Nexstep - Add hyperlink to the page - Dynamically Render compiler time series charts and comparison table
1 parent 9ae4838 commit c5db0d8

33 files changed

+2608
-74
lines changed

torchci/components/benchmark/compilers/common.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,6 @@ export const DISPLAY_KEYS_TO_HIGHLIGHT: { [k: string]: string } = {
9595
None: DEFAULT_HIGHLIGHT_KEY,
9696
Max_autotune: "max_autotune",
9797
};
98+
99+
export const COMPILERS_DTYPES_V2 = ["amp", "float16", "bfloat16", "none"];
100+
export const COMPILERS_MODES_V2 = ["training", "inference", "none"];
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import dayjs from "dayjs";
2+
import utc from "dayjs/plugin/utc";
3+
import { BenchmarkDashboardStoreProvider } from "lib/benchmark/store/benchmark_dashboard_provider";
4+
import BenchmarkSideBar from "./components/benchmarkSideBar/BenchmarkSideBar";
5+
import { getConfig } from "./configs/configBook";
6+
dayjs.extend(utc);
7+
8+
export default function BenchmarkRegressionPage({
9+
benchmarkId,
10+
initial,
11+
}: {
12+
benchmarkId: string;
13+
initial: any;
14+
}) {
15+
const config = getConfig(benchmarkId);
16+
17+
// get dynamic componenet if any registered, otherwise use default
18+
const Comp = config.getDataRenderComponent();
19+
20+
return (
21+
<BenchmarkDashboardStoreProvider key={benchmarkId} initial={initial}>
22+
<div style={{ display: "flex" }}>
23+
<BenchmarkSideBar />
24+
<main style={{ flex: 1 }}>
25+
<Comp />
26+
</main>
27+
</div>
28+
</BenchmarkDashboardStoreProvider>
29+
);
30+
}
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
import ChevronLeftIcon from "@mui/icons-material/ChevronLeft";
2+
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
3+
import { Box, Divider, IconButton, Typography } from "@mui/material";
4+
import { useEffect, useRef, useState } from "react";
5+
import { CommitWorflowSelectSection } from "./components/CommitWorkfowSelectSection";
6+
import { SideBarMainSection } from "./components/SideBarMainSection";
7+
8+
const SIDEBAR_WIDTH = 300; // expanded width
9+
const RAIL_WIDTH = 44; // collapsed width
10+
const WIDTH_MS = 300;
11+
const FADE_MS = 200;
12+
13+
const styles = {
14+
container: (open: boolean) => (theme: any) => ({
15+
width: open
16+
? {
17+
sm: "250px",
18+
md: "300px",
19+
lg: "350px",
20+
}
21+
: RAIL_WIDTH,
22+
transition: theme.transitions.create("width", {
23+
duration: WIDTH_MS,
24+
}),
25+
flexShrink: 0,
26+
}),
27+
28+
inner: {
29+
position: "sticky",
30+
top: 0,
31+
height: "100dvh",
32+
borderRight: 1,
33+
borderColor: "divider",
34+
bgcolor: "background.paper",
35+
display: "flex",
36+
flexDirection: "column",
37+
overflow: "hidden",
38+
p: 1, // keep padding constant to avoid layout shift
39+
},
40+
41+
headerRow: {
42+
display: "flex",
43+
alignItems: "center",
44+
marginBottom: 2,
45+
},
46+
47+
title: { whiteSpace: "nowrap" },
48+
toggleBox: { marginLeft: "auto" },
49+
content: (visible: boolean) => ({
50+
opacity: visible ? 1 : 0,
51+
transform: visible ? "translateX(0)" : "translateX(-6px)",
52+
transition: `opacity ${FADE_MS}ms ease, transform ${FADE_MS}ms ease`,
53+
pointerEvents: visible ? "auto" : "none",
54+
}),
55+
56+
collapsedPlaceholder: {
57+
flex: 1,
58+
display: "flex",
59+
alignItems: "center",
60+
justifyContent: "center",
61+
},
62+
};
63+
64+
/**
65+
* Benchmark sidebar (left rail)
66+
* can be collapsed to a rail with a toggle button
67+
*/
68+
export default function BenchmarkSideBar() {
69+
const [open, setOpen] = useState(true);
70+
71+
// initial = open → first paint shows content when open
72+
const [contentMounted, setContentMounted] = useState(open);
73+
const [contentVisible, setContentVisible] = useState(open);
74+
75+
const prevOpenRef = useRef(open);
76+
const toggle = () => setOpen((o) => !o);
77+
78+
useEffect(() => {
79+
// Only run this logic when open actually changes (not on first render)
80+
if (prevOpenRef.current === open) return;
81+
82+
if (open) {
83+
// Opening: mount first, keep hidden; will show after width transition ends
84+
setContentMounted(true);
85+
setContentVisible(false);
86+
} else {
87+
// Closing: hide immediately (no flash), keep mounted until width transition ends
88+
setContentVisible(false);
89+
}
90+
91+
prevOpenRef.current = open;
92+
}, [open]);
93+
94+
const handleTransitionEnd = (e: React.TransitionEvent<HTMLDivElement>) => {
95+
if (e.propertyName !== "width") return;
96+
97+
if (open) {
98+
// Finished expanding → reveal
99+
setContentVisible(true);
100+
} else {
101+
// Finished collapsing → unmount
102+
setContentMounted(false);
103+
}
104+
};
105+
106+
const SidebarTitleAndToggle = () => (
107+
<Box sx={styles.headerRow}>
108+
{open && (
109+
<Typography variant="h6" sx={styles.title}>
110+
Search
111+
</Typography>
112+
)}
113+
<Box sx={styles.toggleBox}>
114+
<IconButton
115+
size="small"
116+
onClick={toggle}
117+
aria-label={open ? "Collapse sidebar" : "Expand sidebar"}
118+
>
119+
{open ? <ChevronLeftIcon /> : <ChevronRightIcon />}
120+
</IconButton>
121+
</Box>
122+
</Box>
123+
);
124+
125+
return (
126+
<Box
127+
component="aside"
128+
sx={styles.container(open)}
129+
onTransitionEnd={handleTransitionEnd}
130+
>
131+
<Box sx={styles.inner}>
132+
{/* Top bar (always visible) */}
133+
<SidebarTitleAndToggle />
134+
{/* Content: visible immediately on first open; deferred on toggled open; faded on close */}
135+
{contentMounted ? (
136+
<Box sx={styles.content(contentVisible)}>
137+
<SideBarMainSection />
138+
<Divider />
139+
<CommitWorflowSelectSection />
140+
</Box>
141+
) : (
142+
<Box sx={styles.collapsedPlaceholder} />
143+
)}
144+
</Box>
145+
</Box>
146+
);
147+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import { Alert } from "@mui/material";
2+
import { Box } from "@mui/system";
3+
import { UMDenseDropdown } from "components/uiModules/UMDenseComponents";
4+
5+
type BranchDropdownsProps = {
6+
type: string;
7+
lBranch: string;
8+
rBranch: string;
9+
setLBranch: (val: string) => void;
10+
setRBranch: (val: string) => void;
11+
branchOptions?: string[];
12+
};
13+
14+
const styles = {
15+
missingBranch: {
16+
width: 1,
17+
wordBreak: "break-word",
18+
whiteSpace: "normal",
19+
padding: 0.2,
20+
// ↓ shrink the text inside the Alert
21+
"& .MuiAlert-message": {
22+
fontSize: "0.7rem", // ~13px
23+
lineHeight: 1.4,
24+
},
25+
26+
// (optional) shrink the icon to match the smaller text
27+
"& .MuiAlert-icon": {
28+
padding: 0.8, // tighten spacing
29+
"& svg": { fontSize: 20 },
30+
},
31+
},
32+
};
33+
34+
/**
35+
*
36+
* BranchDropdown UI component
37+
* @param {string} type - type of the dropdown, can be "comparison" or "single".
38+
* @param {string} lBranch - left branch
39+
* @param {string} rBranch - right branch
40+
* @param {function} setLBranch - set left branch
41+
* @param {function} setRBranch - set right branch
42+
*
43+
* @returns
44+
*/
45+
const SectionShell: React.FC<{ children: React.ReactNode }> = ({
46+
children,
47+
}) => (
48+
<Box
49+
sx={{
50+
width: 1, // fill parent width
51+
minWidth: 0, // IMPORTANT in flex layouts to allow wrapping
52+
display: "grid", // keeps children from affecting width
53+
gap: 1,
54+
}}
55+
>
56+
{children}
57+
</Box>
58+
);
59+
60+
export function BranchDropdowns({
61+
type,
62+
lBranch,
63+
rBranch,
64+
setLBranch,
65+
setRBranch,
66+
branchOptions,
67+
}: BranchDropdownsProps) {
68+
const empty = !branchOptions || branchOptions.length === 0;
69+
70+
return (
71+
<SectionShell>
72+
{empty ? (
73+
<Alert severity="warning" sx={styles.missingBranch}>
74+
No branch is found, please select other features.
75+
</Alert>
76+
) : type === "comparison" ? (
77+
<>
78+
<UMDenseDropdown
79+
dtype={lBranch}
80+
setDType={setLBranch}
81+
dtypes={branchOptions}
82+
label="Left Branch"
83+
/>
84+
<UMDenseDropdown
85+
dtype={rBranch}
86+
setDType={setRBranch}
87+
dtypes={branchOptions}
88+
label="Right Branch"
89+
/>
90+
</>
91+
) : (
92+
<UMDenseDropdown
93+
dtype={lBranch}
94+
setDType={(val: string) => {
95+
setLBranch(val);
96+
setRBranch(val);
97+
}}
98+
dtypes={branchOptions}
99+
label="Branch"
100+
/>
101+
)}
102+
</SectionShell>
103+
);
104+
}

0 commit comments

Comments
 (0)