Skip to content

Commit 39aa74d

Browse files
authored
Add AutoBenchmarkShortcutCardList (#7545)
# Overview torchao and pytorch mircro op have request to add a shortcuts for users to quickly click dtypes and operatorNames. Create general Card Slider for general use rename field dtype in torchao as quant type # Demo link ## Pytorch Op Microbench https://torchci-git-addsearchcardauto-fbopensource.vercel.app/benchmark/v3/dashboard/pytorch_operator_microbenchmark ## torchao micro api https://torchci-git-addsearchcardauto-fbopensource.vercel.app/benchmark/v3/dashboard/torchao_micro_api_benchmark # Demo ![cards](https://github.com/user-attachments/assets/193ceb46-a89f-4672-92e2-8d33cc5adf8d)
1 parent 2f5a065 commit 39aa74d

File tree

12 files changed

+337
-21
lines changed

12 files changed

+337
-21
lines changed
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
import ChevronLeftIcon from "@mui/icons-material/ChevronLeft";
2+
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
3+
import {
4+
Box,
5+
Card,
6+
CardActionArea,
7+
CardContent,
8+
IconButton,
9+
Typography,
10+
} from "@mui/material";
11+
import React, { useMemo, useRef } from "react";
12+
// import { useRouter } from "next/router";
13+
14+
export type BenchmarkShortcutItem = {
15+
displayName: string;
16+
fieldName: string;
17+
value: string;
18+
description?: string;
19+
url?: string;
20+
};
21+
22+
type BenchmarkShortcutCardListProps = {
23+
benchmarkId: string;
24+
// whatever your query params shape is
25+
data: any;
26+
title?: string;
27+
/**
28+
* Optional custom navigation (e.g. Next.js router.push).
29+
* If not provided, falls back to window.location.href.
30+
*/
31+
onNavigate?: (item: BenchmarkShortcutItem) => void;
32+
};
33+
34+
export const BenchmarkShortcutCardList: React.FC<
35+
BenchmarkShortcutCardListProps
36+
> = ({ benchmarkId, data, title = "Shortcuts", onNavigate }) => {
37+
const scrollContainerRef = useRef<HTMLDivElement | null>(null);
38+
// const router = useRouter();
39+
40+
// ---- map API response -> cardList ----
41+
const cardList: BenchmarkShortcutItem[] = useMemo(() => {
42+
if (!data) return [];
43+
return data;
44+
}, [data]);
45+
46+
// ---- scrolling helpers ----
47+
const handleScroll = (direction: "left" | "right") => {
48+
const node = scrollContainerRef.current;
49+
if (!node) return;
50+
const delta = direction === "left" ? -320 : 320;
51+
node.scrollBy({ left: delta, behavior: "smooth" });
52+
};
53+
54+
// ---- navigation ----
55+
const handleClickCard = (item: BenchmarkShortcutItem) => {
56+
if (onNavigate) {
57+
onNavigate(item);
58+
return;
59+
}
60+
// Fallback: normal navigation
61+
if (typeof window !== "undefined" && item.url) {
62+
window.location.href = item.url;
63+
}
64+
};
65+
66+
if (!cardList.length) {
67+
return null;
68+
}
69+
70+
// ---- main UI ----
71+
return (
72+
<Box sx={{ mx: 1 }}>
73+
<Box
74+
sx={{
75+
display: "flex",
76+
alignItems: "center",
77+
mb: 1,
78+
justifyContent: "flex-start",
79+
}}
80+
>
81+
<Typography variant="subtitle1" fontWeight={600}>
82+
{title}
83+
</Typography>
84+
<Box>
85+
<IconButton
86+
size="small"
87+
aria-label="Scroll left"
88+
onClick={() => handleScroll("left")}
89+
>
90+
<ChevronLeftIcon fontSize="small" />
91+
</IconButton>
92+
<IconButton
93+
size="small"
94+
aria-label="Scroll right"
95+
onClick={() => handleScroll("right")}
96+
>
97+
<ChevronRightIcon fontSize="small" />
98+
</IconButton>
99+
</Box>
100+
</Box>
101+
102+
<Box
103+
ref={scrollContainerRef}
104+
sx={{
105+
display: "flex",
106+
overflowX: "auto",
107+
width: "80%",
108+
border: "1px solid #ccc",
109+
borderRadius: 1,
110+
"::-webkit-scrollbar": { height: 6 },
111+
"::-webkit-scrollbar-thumb": {
112+
borderRadius: 3,
113+
},
114+
}}
115+
>
116+
{cardList.map((item) => (
117+
<Card
118+
key={item.fieldName}
119+
sx={{
120+
minWidth: 200,
121+
maxWidth: 260,
122+
flex: "0 0 auto",
123+
}}
124+
>
125+
<CardActionArea onClick={() => handleClickCard(item)}>
126+
<CardContent sx={{ py: 1.5 }}>
127+
<Typography
128+
variant="subtitle2"
129+
fontWeight={600}
130+
gutterBottom
131+
title={item.displayName}
132+
>
133+
{item.displayName}
134+
</Typography>
135+
{item.description && (
136+
<Typography
137+
variant="body2"
138+
color="text.secondary"
139+
sx={{
140+
display: "-webkit-box",
141+
WebkitBoxOrient: "vertical",
142+
WebkitLineClamp: 3,
143+
overflow: "hidden",
144+
}}
145+
>
146+
{item.description}
147+
</Typography>
148+
)}
149+
</CardContent>
150+
</CardActionArea>
151+
</Card>
152+
))}
153+
</Box>
154+
</Box>
155+
);
156+
};

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

Lines changed: 96 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { Alert, Typography } from "@mui/material";
2-
import { Grid, Stack } from "@mui/system";
2+
import { Box, Grid, Stack } from "@mui/system";
33
import { AutoComponentProps } from "components/benchmark_v3/configs/utils/autoRegistration";
44
import LoadingPage from "components/common/LoadingPage";
55
import {
66
useBenchmarkCommittedContext,
77
useBenchmarkTimeSeriesData,
8+
useListBenchmarkMetadata,
89
} from "lib/benchmark/api_helper/fe/hooks";
910
import { useDashboardSelector } from "lib/benchmark/store/benchmark_dashboard_provider";
1011
import BenchmarkRawDataTable from "../components/benchmarkTimeSeries/components/BenchmarkRawDataTable";
@@ -14,6 +15,10 @@ import { UIRenderConfig } from "components/benchmark_v3/configs/config_book_type
1415
import { useRouter } from "next/router";
1516
import { useEffect, useState } from "react";
1617
import { BenchmarkLogSidePanelWrapper } from "../../common/BenchmarkLogViewer/BenchmarkSidePanel";
18+
import {
19+
BenchmarkShortcutCardList,
20+
BenchmarkShortcutItem,
21+
} from "../../common/BenchmarkShortcutCardList";
1722
import BenchmarkSingleDataTable from "../components/benchmarkTimeSeries/components/BenchmarkSingleDataTable";
1823
import { BenchmarkSingleViewNavigation } from "../components/benchmarkTimeSeries/components/BenchmarkSingleViewNatigation";
1924
import BenchmarkTimeSeriesChartGroup from "../components/benchmarkTimeSeries/components/BenchmarkTimeSeriesChart/BenchmarkTimeSeriesChartGroup";
@@ -326,16 +331,18 @@ export function AutoBenchmarkComparisonGithubExternalLink({
326331
return <></>;
327332
}
328333
return (
329-
<BenchmarkComparisonGithubExternalLink
330-
benchmarkId={ctx.benchmarkId}
331-
lcommit={ctx.lcommit}
332-
rcommit={ctx.rcommit}
333-
repo={repo}
334-
title={{
335-
text: config?.title,
336-
description: config?.description,
337-
}}
338-
/>
334+
<Box sx={{ ml: 1 }}>
335+
<BenchmarkComparisonGithubExternalLink
336+
benchmarkId={ctx.benchmarkId}
337+
lcommit={ctx.lcommit}
338+
rcommit={ctx.rcommit}
339+
repo={repo}
340+
title={{
341+
text: config?.title,
342+
description: config?.description,
343+
}}
344+
/>
345+
</Box>
339346
);
340347
}
341348

@@ -675,6 +682,84 @@ export function AutoBenchmarkRawDataTable({ config }: AutoComponentProps) {
675682
);
676683
}
677684

685+
export function AutoBenchmarkShortcutCardList({ config }: AutoComponentProps) {
686+
const ctx = useBenchmarkCommittedContext();
687+
const update = useDashboardSelector((s) => s.update);
688+
689+
const ready = !!ctx && !!ctx.committedTime;
690+
const dataBinding = ctx?.configHandler.dataBinding;
691+
const uiRenderConfig = config as UIRenderConfig;
692+
const queryParams = ready
693+
? dataBinding.toQueryParams({
694+
repo: ctx.repo,
695+
benchmarkName: ctx.benchmarkName,
696+
timeRange: ctx.committedTime,
697+
filters: {}, // does not rerender when filter changes, since it fetches the filter optons
698+
})
699+
: null;
700+
701+
const {
702+
data: resp,
703+
isLoading,
704+
error,
705+
} = useListBenchmarkMetadata(ctx.benchmarkId, queryParams);
706+
707+
if (isLoading) {
708+
return (
709+
<LoadingPage
710+
height={300}
711+
content="loading data for AutoBenchmarkShortcutCardList..."
712+
/>
713+
);
714+
}
715+
716+
if (error) {
717+
return (
718+
<Alert severity="error">
719+
(AutoBenchmarkShortcutCardList){error.message}
720+
</Alert>
721+
);
722+
}
723+
724+
// ------------------ convert to the shortcut items ------------------
725+
const filters = uiRenderConfig.config?.filters;
726+
let data: BenchmarkShortcutItem[] = [];
727+
resp?.data?.forEach((item: any) => {
728+
const name = filters?.find((f: string) => f === item?.type);
729+
if (name) {
730+
const options = item?.options;
731+
options.forEach((option: any) => {
732+
data.push({
733+
displayName: option.displayName ?? "unkown",
734+
value: option.value,
735+
description: item?.labelName ?? "",
736+
fieldName: name,
737+
});
738+
});
739+
}
740+
});
741+
742+
return (
743+
<>
744+
<BenchmarkShortcutCardList
745+
benchmarkId={ctx.benchmarkId}
746+
data={data}
747+
title={uiRenderConfig?.title}
748+
onNavigate={(item: BenchmarkShortcutItem) => {
749+
const changed: Record<string, string> = {};
750+
changed[item.fieldName] = item.value;
751+
update({
752+
filters: {
753+
...ctx.committedFilters,
754+
...changed,
755+
},
756+
});
757+
}}
758+
/>
759+
</>
760+
);
761+
}
762+
678763
export function AutoBenchmarkSingleDataTable({ config }: AutoComponentProps) {
679764
const ctx = useBenchmarkCommittedContext();
680765
const isWorkflowsReady =

torchci/components/benchmark_v3/configs/teams/torchao/ao_micro_api_config.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ export const PYTORCH_AO_MICRO_API_BENCHMARK_ID = "torchao_micro_api_benchmark";
99

1010
const COMPARISON_TABLE_METADATA_COLUMNS = [
1111
...DEFAULT_COMPARISON_TABLE_METADATA_COLUMNS,
12+
{
13+
field: "dtype",
14+
displayName: "Quant Type",
15+
},
1216
{
1317
field: "extra_key.use_compile",
1418
displayName: "Use Compile",
@@ -96,8 +100,16 @@ export const PytorcAoMicroApiBenchmarkDashoboardConfig: BenchmarkUIConfig = {
96100
},
97101
},
98102
renders: [
103+
{
104+
type: "AutoBenchmarkShortcutCardList",
105+
title: "Dtype Lists",
106+
config: {
107+
filters: ["dtype"],
108+
},
109+
},
99110
{
100111
type: "AutoBenchmarkComparisonGithubExternalLink",
112+
title: "Github Runs",
101113
description: "See original github runs for left and right runs",
102114
config: {},
103115
},

torchci/components/benchmark_v3/configs/teams/torchao/config.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,16 @@ export const PytorchOperatorMicroBenchmarkDashoboardConfig: BenchmarkUIConfig =
150150
},
151151
},
152152
renders: [
153+
{
154+
type: "AutoBenchmarkShortcutCardList",
155+
title: "Operator Lists",
156+
config: {
157+
filters: ["operatorName"],
158+
},
159+
},
153160
{
154161
type: "AutoBenchmarkComparisonGithubExternalLink",
162+
title: "Github runs (external)",
155163
description: "See original github runs for left and right runs",
156164
config: {},
157165
},

torchci/components/benchmark_v3/configs/utils/autoRegistration.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
AutoBenchmarkLogs,
44
AutoBenchmarkPairwiseTable,
55
AutoBenchmarkRawDataTable,
6+
AutoBenchmarkShortcutCardList,
67
AutoBenchmarkSingleDataTable,
78
AutoBenchmarkSingleViewNavigation,
89
AutoBenchmarkTimeSeriesChartGroup,
@@ -70,7 +71,9 @@ export class AutoComponentRegistry {
7071
AutoBenchmarkLogs: {
7172
Component: AutoBenchmarkLogs,
7273
},
73-
74+
AutoBenchmarkShortcutCardList: {
75+
Component: AutoBenchmarkShortcutCardList,
76+
},
7477
// Add your auto components here
7578
};
7679
this.map = Object.freeze({ ...registry });

torchci/lib/benchmark/api_helper/backend/compilers/compiler_benchmark_data.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ export async function getCompilerBenchmarkTimeSeriesData(
2828
const queryParams = await getCompilerBenchmarkTimeRangeQueryParams(
2929
inputparams
3030
);
31+
if (!queryParams) {
32+
return emptyTimeSeriesResponse();
33+
}
3134
const rows = await fetchCompilerDataFromDb(queryParams);
3235
if (rows.length === 0) {
3336
return emptyTimeSeriesResponse();
@@ -106,7 +109,7 @@ export async function getCompilerBenchmarkTimeRangeQueryParams(
106109
queryParams["workflows"] = unique_workflows;
107110
} else {
108111
console.log(`no workflow found in clickhouse using ${queryParams}`);
109-
return [];
112+
return undefined;
110113
}
111114
} else {
112115
console.log(

torchci/lib/benchmark/api_helper/backend/dataFetchers/fetchers.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
import {
1313
BenchmarkMetadataQuery,
1414
PytorchOperatorMicrobenchmarkMetadataFetcher,
15+
TorchAoMicrobApienchmarkMetadataFetcher,
1516
} from "./queryBuilderUtils/listMetadataQueryBuilder";
1617
import {
1718
BenchmarkDataFetcher,
@@ -31,6 +32,7 @@ const dataCtors: Record<string, new () => BenchmarkDataFetcher> = {
3132
// Register benchmark metadata fetchers. this is mainly used in list_metadata api
3233
const metaCtors: Record<string, new () => BenchmarkMetadataFetcher> = {
3334
pytorch_operator_microbenchmark: PytorchOperatorMicrobenchmarkMetadataFetcher,
35+
torchao_micro_api_benchmark: TorchAoMicrobApienchmarkMetadataFetcher,
3436
default: BenchmarkMetadataQuery,
3537
};
3638

0 commit comments

Comments
 (0)