Skip to content

Commit 3c4a036

Browse files
authored
Singleview (#7453)
# Single View Add single view page for benchmark. It is the team's choice wether have the single page view or not to expose to dashboard, but by default it will be shown as long as the benchmark name is registered. ## Demo Helion Customized single view https://torchci-git-singleview-fbopensource.vercel.app/benchmark/v3/single/pytorch_helion User can navigate to the dashboard comparison view from single view <img width="836" height="314" alt="image" src="https://github.com/user-attachments/assets/3ff72bd4-b3e7-4e93-b362-a9b77252c5e7" /> if enabled, user can navigate from dashboard view to single workflow view: <img width="724" height="261" alt="image" src="https://github.com/user-attachments/assets/414d77ec-c274-495d-8a7e-cc925d34c1f5" /> Pytorch OP microbench (powered by default config) https://torchci-git-singleview-fbopensource.vercel.app/benchmark/v3/single/pytorch_operator_microbenchmark # Other fix do not show maxsampling settings by default, this is enable only setting for pages
1 parent bc9276b commit 3c4a036

File tree

22 files changed

+1136
-45
lines changed

22 files changed

+1136
-45
lines changed

torchci/components/benchmark_v3/components/benchmarkSideBar/BenchmarkTopBar.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@ import { BenchmarkUIConfigHandler } from "components/benchmark_v3/configs/benchm
44
import { BenchmarkReportFeatureNotification } from "../benchmarkRegressionReport/BenchmarkReportFeatureNotification";
55
import { BenchmarkReportFeatureSidePanel } from "../benchmarkRegressionReport/BenchmarkReportFeatureSidePanel";
66
import { CommitWorflowSelectSection } from "./components/commits/CommitWorkfowSelectSection";
7+
import { SingleCommitSelectSelection } from "./components/commits/SingleCommitSelectSelection";
78

89
export function BenchmarkTopBar({
910
config,
1011
title = "",
12+
mode = "default",
1113
}: {
1214
config: BenchmarkUIConfigHandler;
1315
title?: string;
16+
mode?: string;
1417
}) {
1518
const reportFeature =
1619
config.raw.dataRender?.sideRender?.RegressionReportFeature;
@@ -41,9 +44,12 @@ export function BenchmarkTopBar({
4144
<Divider orientation="vertical" flexItem sx={{ mx: 1 }} />
4245
</>
4346
)}
44-
<ReportFeature reportFeature={reportFeature} />
45-
<Divider orientation="vertical" flexItem sx={{ mx: 1 }} />
46-
<CommitWorflowSelectSection />
47+
{reportFeature && <ReportFeature reportFeature={reportFeature} />}
48+
{reportFeature && (
49+
<Divider orientation="vertical" flexItem sx={{ mx: 1 }} />
50+
)}
51+
{mode == "default" && <CommitWorflowSelectSection />}
52+
{mode == "single" && <SingleCommitSelectSelection />}
4753
</Stack>
4854
</Paper>
4955
);

torchci/components/benchmark_v3/components/benchmarkSideBar/components/SideBarMainSection.tsx

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ export function SideBarMainSection() {
107107
branchOptionType,
108108
enableMultiBranchOption,
109109
enableSamplingSetting,
110+
enableSamplingFeature,
110111
commitMainOptions,
111112
revertMainOptions,
112113
} = useDashboardSelector((s) => ({
@@ -115,6 +116,7 @@ export function SideBarMainSection() {
115116
stagedLbranch: s.stagedLbranch,
116117
stagedRbranch: s.stagedRbranch,
117118
stagedMaxSampling: s.stagedMaxSampling,
119+
enableSamplingFeature: s.enableSamplingFeature,
118120
enableMultiBranchOption: s.enableMultiBranchOption,
119121
branchOptionType: s.branchOptionType,
120122

@@ -253,15 +255,19 @@ export function SideBarMainSection() {
253255
end={stagedTime.end}
254256
gap={0}
255257
/>
256-
{/* Fetch Settings */}
257-
<Divider />
258-
<Typography variant="subtitle2">Fetch Settings</Typography>
259-
<SamplingSetting
260-
enableSamplingSetting={enableSamplingSetting ?? false}
261-
setEnableSamplingSetting={setEnableSamplingSetting}
262-
setMaxSampling={setStagedMaxSampling}
263-
maxSamplingValue={stagedMaxSampling ?? 0}
264-
/>
258+
{enableSamplingFeature && (
259+
<>
260+
{/* Fetch Settings */}
261+
<Divider />
262+
<Typography variant="subtitle2">Fetch Settings</Typography>{" "}
263+
<SamplingSetting
264+
enableSamplingSetting={enableSamplingSetting ?? false}
265+
setEnableSamplingSetting={setEnableSamplingSetting}
266+
setMaxSampling={setStagedMaxSampling}
267+
maxSamplingValue={stagedMaxSampling ?? 0}
268+
/>
269+
</>
270+
)}
265271
{showSamplinginfo && (
266272
<DenseAlert severity="info">
267273
{`Data Sampling: subsample from ${sampling_info?.origin ?? 0} to ${

torchci/components/benchmark_v3/components/benchmarkSideBar/components/commits/BranchDropdown.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ export function BranchDropdowns({
4949

5050
return (
5151
<SectionShell>
52-
<Box>{type}</Box>
5352
{empty ? (
5453
<DenseAlert severity="warning">
5554
No branch is found, please select other features.
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
import OpenInNewIcon from "@mui/icons-material/OpenInNew";
2+
import { Typography } from "@mui/material";
3+
import { Box, Stack } from "@mui/system";
4+
import { useBenchmarkBook } from "components/benchmark_v3/configs/benchmark_config_book";
5+
import { QueryParameterConverterInputs } from "components/benchmark_v3/configs/utils/dataBindingRegistration";
6+
import { CenteredLoader } from "components/common/LoadingIcon";
7+
import {
8+
UMDenseCommitDropdown,
9+
UMDenseSingleButton,
10+
} from "components/uiModules/UMDenseComponents";
11+
import { useBenchmarkCommitsData } from "lib/benchmark/api_helper/fe/hooks";
12+
import { useDashboardSelector } from "lib/benchmark/store/benchmark_dashboard_provider";
13+
import { BenchmarkCommitMeta } from "lib/benchmark/store/benchmark_regression_store";
14+
import { stateToQuery } from "lib/helpers/urlQuery";
15+
import { NextRouter, useRouter } from "next/router";
16+
import { useEffect, useState } from "react";
17+
18+
export function SingleCommitSelectSelection() {
19+
const {
20+
repo,
21+
type,
22+
benchmarkName,
23+
benchmarkId,
24+
committedTime,
25+
committedFilters,
26+
lcommit,
27+
committedLBranch,
28+
committedMaxSampling,
29+
enableSamplingSetting,
30+
setLcommit,
31+
} = useDashboardSelector((s) => ({
32+
type: s.type,
33+
benchmarkId: s.benchmarkId,
34+
committedTime: s.committedTime,
35+
committedFilters: s.committedFilters,
36+
committedMaxSampling: s.committedMaxSampling,
37+
enableSamplingSetting: s.enableSamplingSetting,
38+
repo: s.repo,
39+
benchmarkName: s.benchmarkName,
40+
lcommit: s.lcommit,
41+
rcommit: s.rcommit,
42+
committedLBranch: s.committedLbranch,
43+
setLcommit: s.setLcommit,
44+
}));
45+
46+
const [leftList, setLeftList] = useState<BenchmarkCommitMeta[]>([]);
47+
const getConfig = useBenchmarkBook((s) => s.getConfig);
48+
const config = getConfig(benchmarkId, type);
49+
const dataBinding = config.dataBinding;
50+
const required_filter_fields = config.raw?.required_filter_fields ?? [];
51+
52+
const ready =
53+
!!committedTime?.start &&
54+
!!committedTime?.end &&
55+
!!committedLBranch &&
56+
committedLBranch.length > 0 &&
57+
(enableSamplingSetting ? committedMaxSampling : true) &&
58+
required_filter_fields.every((k) => !!committedFilters[k]);
59+
60+
// Fetch data
61+
const branches = [...new Set([committedLBranch].filter((b) => b.length > 0))];
62+
63+
// Convert to query params
64+
const params = dataBinding.toQueryParams({
65+
repo: repo,
66+
benchmarkName: benchmarkName,
67+
branches,
68+
timeRange: committedTime,
69+
filters: committedFilters,
70+
maxSampling: enableSamplingSetting ? committedMaxSampling : undefined,
71+
} as QueryParameterConverterInputs);
72+
if (!params) {
73+
throw new Error(`Failed to convert to query params for ${benchmarkId}`);
74+
}
75+
76+
const queryParams: any | null = ready ? params : null;
77+
78+
// Fetch data
79+
const { data, isLoading, error } = useBenchmarkCommitsData(
80+
benchmarkId,
81+
queryParams
82+
);
83+
84+
useEffect(() => {
85+
if (isLoading || !data) return;
86+
87+
const groups = data?.data?.branch ?? [];
88+
const branchMap = convertToBranchMap(groups);
89+
90+
const L: BenchmarkCommitMeta[] = branchMap[committedLBranch] ?? [];
91+
92+
// update list
93+
setLeftList(L);
94+
95+
if (L.length === 0) return;
96+
97+
// check if user has selected a commit that is not in the list
98+
const lSelected = lcommit?.workflow_id ?? null;
99+
100+
const lHas = !!lSelected && L.some((c) => c.workflow_id === lSelected);
101+
102+
// rule left and right both pick left option
103+
const nextAutoL = lHas ? lSelected : L[0]?.workflow_id ?? null;
104+
105+
if (!lHas) {
106+
setLcommit(
107+
nextAutoL ? L.find((c) => c.workflow_id === nextAutoL) ?? null : null
108+
);
109+
}
110+
}, [isLoading, data, committedLBranch, lcommit?.workflow_id, setLcommit]);
111+
112+
if (error) return <div>Error: {error.message}</div>;
113+
if (isLoading || !data) return <CenteredLoader />;
114+
115+
return (
116+
<Stack spacing={1.5} direction={"row"} alignItems={"center"}>
117+
<Typography variant="subtitle2" sx={{ minWidth: 50 }}>
118+
Commit:
119+
</Typography>
120+
<Box
121+
sx={{
122+
whiteSpace: "nowrap",
123+
}}
124+
>
125+
{lcommit?.branch}:
126+
</Box>
127+
<UMDenseCommitDropdown
128+
label={"run"}
129+
branchName={committedLBranch}
130+
disable={!ready || leftList.length === 0 || isLoading}
131+
selectedCommit={lcommit}
132+
commitList={leftList}
133+
setCommit={(c) => {
134+
setLcommit(c);
135+
}}
136+
/>
137+
<NavigateToDashboardButton benchmarkId={benchmarkId} commit={lcommit} />
138+
</Stack>
139+
);
140+
}
141+
142+
export const convertToBranchMap = (
143+
raw: any[]
144+
): Record<string, BenchmarkCommitMeta[]> => {
145+
return raw.reduce((acc, g) => {
146+
const branch = g?.group_info?.branch ?? "unknown";
147+
acc[branch] = g.rows.map((r: any) => ({
148+
commit: r.commit,
149+
workflow_id: String(r.workflow_id),
150+
date: r.date,
151+
branch,
152+
}));
153+
return acc;
154+
}, {} as Record<string, BenchmarkCommitMeta[]>);
155+
};
156+
157+
export function NavigateToDashboardButton({
158+
benchmarkId,
159+
commit,
160+
}: {
161+
benchmarkId: string;
162+
commit: BenchmarkCommitMeta | null;
163+
}) {
164+
const router = useRouter();
165+
if (!commit) {
166+
return <></>;
167+
}
168+
return (
169+
<UMDenseSingleButton
170+
component="a"
171+
href={toDashboardUrl(benchmarkId, commit, router)}
172+
size="small"
173+
variant="outlined"
174+
color="primary"
175+
endIcon={<OpenInNewIcon fontSize="small" />}
176+
sx={{
177+
whiteSpace: "nowrap",
178+
}}
179+
>
180+
View {commit.workflow_id} ({commit.commit.slice(0, 7)}) in Dashboard
181+
</UMDenseSingleButton>
182+
);
183+
}
184+
185+
export function toDashboardUrl(
186+
benchmarkId: string,
187+
commit: BenchmarkCommitMeta,
188+
router: NextRouter
189+
) {
190+
const pathname = `/benchmark/v3/dashboard/${benchmarkId}`;
191+
const lcommit: BenchmarkCommitMeta = commit;
192+
const rcommit: BenchmarkCommitMeta = commit;
193+
const reformattedPrams = stateToQuery({
194+
lcommit,
195+
rcommit,
196+
});
197+
198+
const nextDashboardMainQuery = {
199+
...router.query, // keep existing params
200+
...reformattedPrams,
201+
renderGroupId: "main",
202+
};
203+
const params = new URLSearchParams(
204+
Object.entries(nextDashboardMainQuery)
205+
.filter(([_, v]) => v != null && v !== "")
206+
.map(([k, v]) => [k, String(v)])
207+
);
208+
const url = `${pathname}?${params.toString()}`;
209+
return url;
210+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import type { ButtonProps } from "@mui/material/Button";
2+
import Button from "@mui/material/Button";
3+
import { styled } from "@mui/material/styles";
4+
import * as React from "react";
5+
6+
/** Anchor-style MUI Button with proper typing for href/target/rel. */
7+
export interface BenchmarkLinkButtonProps
8+
extends Omit<ButtonProps<"a">, "component"> {
9+
href: string;
10+
/** Default: "_self". Use "_blank" for new tab. */
11+
target?: "_self" | "_blank" | "_parent" | "_top";
12+
/** Default: added automatically for _blank */
13+
rel?: string;
14+
}
15+
16+
export const LinkButton = React.forwardRef<
17+
HTMLAnchorElement,
18+
BenchmarkLinkButtonProps
19+
>(({ href, target = "_self", rel, ...props }, ref) => {
20+
// Security for new-tab links
21+
const finalRel = target === "_blank" ? rel ?? "noopener noreferrer" : rel;
22+
return (
23+
<Button
24+
ref={ref}
25+
component="a"
26+
href={href}
27+
target={target}
28+
rel={finalRel}
29+
{...props}
30+
/>
31+
);
32+
});
33+
LinkButton.displayName = "LinkButton";
34+
35+
export const BenchmarkLinkButton = styled(LinkButton)(({ theme }) => ({
36+
px: 0.5,
37+
py: 0,
38+
mx: 1,
39+
minWidth: "auto",
40+
lineHeight: 2,
41+
fontSize: "0.75rem",
42+
textTransform: "none",
43+
}));

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
Tooltip,
1212
Typography,
1313
} from "@mui/material";
14+
import { UMDenseSingleButton } from "components/uiModules/UMDenseComponents";
1415
import React, { useState } from "react";
1516
import { StaticRenderViewOnlyContent } from "./StaticRenderViewOnlyContent";
1617

@@ -66,9 +67,9 @@ export function RawContentDialog({
6667

6768
return (
6869
<>
69-
<Button
70-
size="small"
70+
<UMDenseSingleButton
7171
variant="outlined"
72+
size="small"
7273
onClick={() => setOpen(true)}
7374
sx={{
7475
px: 0.5,
@@ -81,7 +82,7 @@ export function RawContentDialog({
8182
}}
8283
>
8384
{buttonName}
84-
</Button>
85+
</UMDenseSingleButton>
8586

8687
<Dialog
8788
open={open}
@@ -152,11 +153,13 @@ export function RenderRawContent({
152153
title = "Raw Content",
153154
buttonName = "Raw Content",
154155
type = "json",
156+
buttonSx,
155157
component,
156158
}: {
157159
data: any;
158160
title?: string;
159161
buttonName?: string;
162+
buttonSx?: any;
160163
type?: "json" | "component";
161164
component?: (data: any, title: string) => JSX.Element;
162165
}) {
@@ -167,6 +170,7 @@ export function RenderRawContent({
167170
type={type}
168171
component={component}
169172
buttonName={buttonName}
173+
sx={buttonSx}
170174
/>
171175
);
172176
}

0 commit comments

Comments
 (0)