Skip to content

Commit acb8d0f

Browse files
authored
New Operator Microbench With Auto Component Dashboard (#7363)
# Overview Set up Pytorch Operateor Microbench And auto-style dashabord ## Auto vs Fanout - auto: Each component in auto calls api to fetch data - fanout: data are passed from the center parent ## Details 1. fix bug in TimeSeriesTable 2. add default metrics filter option based on listMetadata api 3. set up customzied config for Pytorch Operateor Microbench 4. configure a default auto style configuration ## Next step 1. add pairwise table ( only render two workflows) 2. set up model detail view 3. support navigation to details view from the dashboard Demo Link https://torchci-git-newbenchmicro2-fbopensource.vercel.app/benchmark/v3/dashboard/pytorch_operator_microbenchmark
1 parent 1d94bdf commit acb8d0f

File tree

30 files changed

+795
-128
lines changed

30 files changed

+795
-128
lines changed

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,13 @@ export function SideBarMainSection() {
6666
// pushUrlFromStore();
6767

6868
// 1) Read benchmarkId (low-churn) to fetch config
69-
const benchmarkId = useDashboardSelector((s) => s.benchmarkId);
69+
const { benchmarkId, type } = useDashboardSelector((s) => ({
70+
benchmarkId: s.benchmarkId,
71+
type: s.type,
72+
}));
7073

7174
const getConfig = useBenchmarkBook((s) => s.getConfig);
72-
const config = getConfig(benchmarkId);
75+
const config = getConfig(benchmarkId, type);
7376
const dataBinding = config.dataBinding;
7477

7578
const required_filter_fields = config.raw?.required_filter_fields ?? [];

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Typography } from "@mui/material";
22
import { Stack } from "@mui/system";
33
import { QueryParameterConverterInputs } from "components/benchmark_v3/configs/utils/dataBindingRegistration";
4+
import { CenteredLoader } from "components/common/LoadingIcon";
45
import { UMDenseCommitDropdown } from "components/uiModules/UMDenseComponents";
56
import { useBenchmarkCommitsData } from "lib/benchmark/api_helper/fe/hooks";
67
import { useBenchmarkBook } from "lib/benchmark/store/benchmark_config_book";
@@ -16,6 +17,7 @@ import { useEffect, useState } from "react";
1617
export function CommitWorflowSelectSection() {
1718
const {
1819
repo,
20+
type,
1921
benchmarkName,
2022
benchmarkId,
2123
committedTime,
@@ -29,6 +31,7 @@ export function CommitWorflowSelectSection() {
2931
setLcommit,
3032
setRcommit,
3133
} = useDashboardSelector((s) => ({
34+
type: s.type,
3235
benchmarkId: s.benchmarkId,
3336
committedTime: s.committedTime,
3437
committedFilters: s.committedFilters,
@@ -48,7 +51,7 @@ export function CommitWorflowSelectSection() {
4851
const [rightList, setRightList] = useState<BenchmarkCommitMeta[]>([]);
4952

5053
const getConfig = useBenchmarkBook((s) => s.getConfig);
51-
const config = getConfig(benchmarkId);
54+
const config = getConfig(benchmarkId, type);
5255
const dataBinding = config.dataBinding;
5356
const required_filter_fields = config.raw?.required_filter_fields ?? [];
5457

@@ -137,7 +140,7 @@ export function CommitWorflowSelectSection() {
137140
]);
138141

139142
if (error) return <div>Error: {error.message}</div>;
140-
if (isLoading || !data) return null;
143+
if (isLoading || !data) return <CenteredLoader />;
141144

142145
return (
143146
<Stack spacing={1.5} direction={"row"} alignItems={"center"}>
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { Stack } from "@mui/system";
2+
import {
3+
UMDenseDropdown,
4+
UMDenseDropdownOption,
5+
} from "components/uiModules/UMDenseComponents";
6+
7+
/**
8+
* The enum type of benchmark dashboard dropgroup item
9+
* this is used to render dropdowns dynamically in the LLMs Benchmark page.
10+
* the field value must match the fields in LLMsBenchmarkProps
11+
*/
12+
export enum BenchmarkDropdownGroupItemType {
13+
ModelName = "model",
14+
BackendName = "backend",
15+
ModeName = "modeN",
16+
DtypeName = "dtype",
17+
DeviceName = "deviceName",
18+
ArchName = "arch",
19+
Qps = "qps",
20+
}
21+
22+
/**
23+
* The input item for benchmark dashboard dropdown
24+
* @property DropdownGroupItemType enum type
25+
* @property options the list of options in the dropdown
26+
* @property labelName the label name of the dropdown
27+
*/
28+
export interface BenchmarkDropdownGroupItem {
29+
type: BenchmarkDropdownGroupItemType;
30+
options: (string | UMDenseDropdownOption)[];
31+
labelName: string;
32+
}
33+
34+
export default function BenchmarkDropdownGroup({
35+
onChange,
36+
props,
37+
optionListMap,
38+
}: {
39+
onChange: (_key: string, _value: any) => void;
40+
props: any;
41+
optionListMap: BenchmarkDropdownGroupItem[];
42+
}) {
43+
return (
44+
<Stack spacing={1}>
45+
{optionListMap.length > 1 &&
46+
optionListMap.map((option, index) => {
47+
const type = option.type;
48+
const olist = option.options;
49+
if (!olist || olist.length <= 1) {
50+
return null;
51+
}
52+
return (
53+
<UMDenseDropdown
54+
key={index}
55+
dtype={props[type]}
56+
setDType={(val: any) => {
57+
onChange(type, val);
58+
}}
59+
dtypes={olist}
60+
label={option.labelName}
61+
/>
62+
);
63+
})}
64+
</Stack>
65+
);
66+
}
Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,79 @@
1+
import { Alert } from "@mui/material";
2+
import { Box } from "@mui/system";
3+
import LoadingPage from "components/common/LoadingPage";
4+
import {
5+
useBenchmarkConfigBook,
6+
useListBenchmarkMetadata,
7+
} from "lib/benchmark/api_helper/fe/hooks";
8+
import { useDashboardSelector } from "lib/benchmark/store/benchmark_dashboard_provider";
9+
import BenchmarkDropdownGroup from "./BenchmarkFilterDropdownGroup";
10+
111
export default function DefaultMetricsDropdowns() {
2-
return <div>Not supported yet: comming soon</div>;
12+
const {
13+
setStagedFilter,
14+
repo,
15+
type,
16+
benchmarkId,
17+
benchmarkName,
18+
stagedTime,
19+
stagedFilters,
20+
} = useDashboardSelector((s) => ({
21+
setStagedFilter: s.setStagedFilter,
22+
repo: s.repo,
23+
type: s.type,
24+
benchmarkName: s.benchmarkName,
25+
benchmarkId: s.benchmarkId,
26+
stagedTime: s.stagedTime,
27+
stagedFilters: s.stagedFilters,
28+
}));
29+
30+
const configHandler = useBenchmarkConfigBook(benchmarkId, type);
31+
const ready = !!configHandler && !!stagedTime?.start && !!stagedTime?.end;
32+
33+
// convert to the query params
34+
const queryParams = ready
35+
? configHandler.dataBinding.toQueryParams({
36+
repo: repo,
37+
benchmarkName: benchmarkName,
38+
timeRange: stagedTime,
39+
filters: {}, // the dropdown does not rerender when filter changes, since it manages the filter optons
40+
})
41+
: null;
42+
43+
const {
44+
data: resp,
45+
isLoading: isLoading,
46+
error: error,
47+
} = useListBenchmarkMetadata(benchmarkId, queryParams);
48+
49+
if (isLoading) {
50+
return <LoadingPage />;
51+
}
52+
53+
if (error) {
54+
return (
55+
<Alert severity="error"> DefaultMetricsDropdowns {error.message}</Alert>
56+
);
57+
}
58+
59+
const metadataList = resp?.data || [];
60+
61+
return (
62+
<Box>
63+
<BenchmarkDropdownGroup
64+
optionListMap={metadataList}
65+
onChange={(_key: string, _value: any) => {
66+
if (_key == "deviceName") {
67+
const v = _value.split("||");
68+
if (v.length === 2) {
69+
setStagedFilter("device", v[0]);
70+
setStagedFilter("arch", v[1]);
71+
}
72+
}
73+
setStagedFilter(_key, _value);
74+
}}
75+
props={stagedFilters}
76+
/>
77+
</Box>
78+
);
379
}

torchci/components/benchmark_v3/components/benchmarkSideBar/components/useUrlSync.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,11 @@ export function useUrlStoreSync<T extends Record<string, any>>(
5757
// prevent no-op replace and re-pushing the same thing
5858
if (nextSig === currSig || nextSig === lastPushedSigRef.current) return;
5959

60+
const [pathname] = router.asPath.split("?"); // strip query
6061
// briefly mark as syncing to avoid URL->store echo
6162
isApplyingUrlRef.current = true;
6263
router
63-
.replace({ pathname: router.pathname, query: nextQueryObj }, undefined, {
64+
.replace({ pathname: pathname, query: nextQueryObj }, undefined, {
6465
shallow: true,
6566
})
6667
.finally(() => {
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { Alert } from "@mui/material";
2+
3+
export function BenchmarkIdNotRegisterError({
4+
benchmarkId,
5+
content,
6+
}: {
7+
benchmarkId: string;
8+
content: string;
9+
}) {
10+
return (
11+
<Alert severity="error">
12+
{content}BenchmarkId `{benchmarkId}` is not registered in the repo, please
13+
register it as BenchmarkIdMappingItem in BENCHMARK_ID_MAPPING in the store
14+
</Alert>
15+
);
16+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import { Alert } from "@mui/material";
2+
import { Grid } from "@mui/system";
3+
import { AutoComponentProps } from "components/benchmark_v3/configs/utils/autoRegistration";
4+
import LoadingPage from "components/common/LoadingPage";
5+
import {
6+
useBenchmarkCommittedContext,
7+
useBenchmarkTimeSeriesData,
8+
} from "lib/benchmark/api_helper/fe/hooks";
9+
import { UIRenderConfig } from "lib/benchmark/store/benchmark_config_book";
10+
import { ComparisonTable } from "../components/benchmarkTimeSeries/components/BenchmarkTimeSeriesComparisonSection/BenchmarkTimeSeriesComparisonTable/ComparisonTable";
11+
12+
export function AutoBenchmarkTimeSeriesTable({ config }: AutoComponentProps) {
13+
const ctx = useBenchmarkCommittedContext();
14+
15+
const ready =
16+
!!ctx &&
17+
!!ctx.committedTime?.start &&
18+
!!ctx.committedTime?.end &&
19+
!!ctx.committedLbranch &&
20+
!!ctx.committedRbranch &&
21+
ctx.requiredFilters.every((k: string) => !!ctx.committedFilters[k]);
22+
23+
const dataBinding = ctx?.configHandler.dataBinding;
24+
const uiRenderConfig = config as UIRenderConfig;
25+
26+
const branches = [
27+
...new Set(
28+
[ctx.committedLbranch, ctx.committedRbranch].filter((b) => b.length > 0)
29+
),
30+
];
31+
32+
// convert to the query params
33+
const params = dataBinding.toQueryParams({
34+
repo: ctx.repo,
35+
branches: branches,
36+
benchmarkName: ctx.benchmarkName,
37+
timeRange: ctx.committedTime,
38+
filters: ctx.committedFilters,
39+
maxSampling: ctx.committedMaxSampling,
40+
});
41+
42+
const queryParams: any | null = ready ? params : null;
43+
// fetch the bechmark data
44+
const {
45+
data: resp,
46+
isLoading,
47+
error,
48+
} = useBenchmarkTimeSeriesData(ctx.benchmarkId, queryParams, ["table"]);
49+
50+
if (isLoading) {
51+
return <LoadingPage />;
52+
}
53+
54+
if (error) {
55+
return (
56+
<Alert severity="error">
57+
(AutoBenchmarkTimeSeriesTable){error.message}
58+
</Alert>
59+
);
60+
}
61+
if (!ctx.dataRender?.renders) {
62+
return <div>no data render</div>;
63+
}
64+
if (!resp?.data?.data) {
65+
return <div>no data</div>;
66+
}
67+
const data = resp?.data?.data;
68+
return (
69+
<Grid container sx={{ m: 1 }}>
70+
<Grid size={{ xs: 12 }}>
71+
<ComparisonTable
72+
data={data["table"]}
73+
config={uiRenderConfig.config}
74+
lWorkflowId={ctx.lcommit?.workflow_id ?? null}
75+
rWorkflowId={ctx.rcommit?.workflow_id ?? null}
76+
title={{
77+
text: "Comparison Table",
78+
}}
79+
onSelect={() => {}}
80+
/>
81+
</Grid>
82+
</Grid>
83+
);
84+
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export function DefaultAutoRenderContent() {
2727
const { Component } = getAutoRenderComponent(autoUIConfig);
2828
return (
2929
<Box key={index}>
30-
<Component />
30+
<Component config={autoUIConfig} />
3131
</Box>
3232
);
3333
})}

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import { Typography } from "@mui/material";
2-
import { DataGrid, GridColDef, GridRowModel } from "@mui/x-data-grid";
2+
import {
3+
DataGrid,
4+
GridColDef,
5+
GridRowModel,
6+
useGridApiRef,
7+
} from "@mui/x-data-grid";
38
import { SelectionDialog } from "components/benchmark_v3/components/common/SelectionDialog";
49
import { useMemo, useState } from "react";
510
import { ComparisonTableConfig } from "../../../helper";
@@ -28,6 +33,7 @@ export function ComparisonTable({
2833
};
2934
onSelect?: (payload: any) => void;
3035
}) {
36+
const apiRef = useGridApiRef();
3137
// group raw data into rows, each row contains all values across workflowIds
3238
const rows: GridRowModel[] = useMemo(() => {
3339
return ToComparisonTableRow(config, data);
@@ -59,6 +65,7 @@ export function ComparisonTable({
5965
const tail = auto.filter((c) => !head.includes(c));
6066
return [...head, ...tail];
6167
}, [rows, columnOrder]);
68+
6269
// Form the columns
6370
const columns: GridColDef[] = useMemo(
6471
() =>
@@ -82,8 +89,8 @@ export function ComparisonTable({
8289
{lWorkflowId} - {rWorkflowId}
8390
</Typography>
8491
<DataGrid
92+
apiRef={apiRef}
8593
density="compact"
86-
disableRowSelectionOnClick
8794
rows={rows}
8895
columns={columns}
8996
initialState={{

0 commit comments

Comments
 (0)