refactor: env detail
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
import IconFont from '@/components/icon-font';
|
import IconFont from '@/components/icon-font';
|
||||||
import { RightOutlined } from '@ant-design/icons';
|
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Button, Checkbox } from 'antd';
|
import { Button, Checkbox } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
@@ -88,14 +87,34 @@ const HeaderPrefix: React.FC<HeaderPrefixProps> = (props) => {
|
|||||||
}
|
}
|
||||||
if (expandable) {
|
if (expandable) {
|
||||||
return (
|
return (
|
||||||
<div className="header-row-prefix-wrapper">
|
<div
|
||||||
{_.isBoolean(expandable) ? (
|
className="header-row-prefix-wrapper flex-center"
|
||||||
<Button type="text" size="small">
|
style={{ paddingLeft: 16 }}
|
||||||
<RightOutlined />
|
>
|
||||||
</Button>
|
<span style={{ marginRight: 5 }}>
|
||||||
) : (
|
{_.isBoolean(expandable) ? (
|
||||||
expandable
|
<Button
|
||||||
)}
|
type="text"
|
||||||
|
size="small"
|
||||||
|
onClick={handleToggleExpand}
|
||||||
|
style={{ paddingInline: 6 }}
|
||||||
|
>
|
||||||
|
{expandAll ? (
|
||||||
|
<IconFont
|
||||||
|
type="icon-collapse_all"
|
||||||
|
className="font-size-16"
|
||||||
|
></IconFont>
|
||||||
|
) : (
|
||||||
|
<IconFont
|
||||||
|
type="icon-uncollapse_all"
|
||||||
|
className="font-size-16"
|
||||||
|
></IconFont>
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
expandable
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ const Wrapper = styled.div<{ $token: any }>`
|
|||||||
props.$token.tableHeaderIconHoverColor};
|
props.$token.tableHeaderIconHoverColor};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const SealTable: React.FC<SealTableProps & { pagination: PaginationProps }> = (
|
const SealTable: React.FC<SealTableProps & { pagination?: PaginationProps }> = (
|
||||||
props
|
props
|
||||||
) => {
|
) => {
|
||||||
const {
|
const {
|
||||||
|
|||||||
@@ -84,11 +84,12 @@ export function useQueryDataList<ListItem, Params = any>(option: {
|
|||||||
|
|
||||||
export function useQueryData<Detail, Params = any>(option: {
|
export function useQueryData<Detail, Params = any>(option: {
|
||||||
key: string;
|
key: string;
|
||||||
|
delay?: number;
|
||||||
fetchDetail: (params: Params, options?: any) => Promise<Detail>;
|
fetchDetail: (params: Params, options?: any) => Promise<Detail>;
|
||||||
getData?: (response: Detail) => any;
|
getData?: (response: Detail) => any;
|
||||||
errorMsg?: string;
|
errorMsg?: string;
|
||||||
}) {
|
}) {
|
||||||
const { key, fetchDetail, getData, errorMsg } = option;
|
const { key, fetchDetail, getData, errorMsg, delay } = option;
|
||||||
const axiosTokenRef = useRef<CancelTokenSource | null>(null);
|
const axiosTokenRef = useRef<CancelTokenSource | null>(null);
|
||||||
const [detailData, setDetailData] = useState<Detail>({} as Detail);
|
const [detailData, setDetailData] = useState<Detail>({} as Detail);
|
||||||
|
|
||||||
@@ -105,6 +106,12 @@ export function useQueryData<Detail, Params = any>(option: {
|
|||||||
...(extra || {})
|
...(extra || {})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (delay) {
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
setTimeout(resolve, delay);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
setDetailData(getData ? getData(res) : res);
|
setDetailData(getData ? getData(res) : res);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ export default {
|
|||||||
'benchmark.table.dataset': 'Dataset',
|
'benchmark.table.dataset': 'Dataset',
|
||||||
'benchmark.table.requestRate': 'Request Rate',
|
'benchmark.table.requestRate': 'Request Rate',
|
||||||
'benchmark.table.gpu': 'GPU ',
|
'benchmark.table.gpu': 'GPU ',
|
||||||
'benchmark.table.tpot': 'TPOT (ms)',
|
'benchmark.table.tpot': 'TPOT',
|
||||||
'benchmark.table.itl': 'ITL (ms)',
|
'benchmark.table.itl': 'ITL',
|
||||||
'benchmark.table.ttft': 'TTFT (ms)',
|
'benchmark.table.ttft': 'TTFT',
|
||||||
'benchmark.table.rps': 'Requests/s',
|
'benchmark.table.rps': 'Requests/s',
|
||||||
'benchmark.table.tps': 'Tokens/s',
|
'benchmark.table.tps': 'Tokens/s',
|
||||||
'benchmark.table.inputLen': 'Input Length',
|
'benchmark.table.inputLen': 'Input Length',
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ export default {
|
|||||||
'benchmark.table.dataset': 'Dataset',
|
'benchmark.table.dataset': 'Dataset',
|
||||||
'benchmark.table.requestRate': 'Request Rate',
|
'benchmark.table.requestRate': 'Request Rate',
|
||||||
'benchmark.table.gpu': 'GPU ',
|
'benchmark.table.gpu': 'GPU ',
|
||||||
'benchmark.table.tpot': 'TPOT (ms)',
|
'benchmark.table.tpot': 'TPOT',
|
||||||
'benchmark.table.itl': 'ITL (ms)',
|
'benchmark.table.itl': 'ITL',
|
||||||
'benchmark.table.ttft': 'TTFT (ms)',
|
'benchmark.table.ttft': 'TTFT',
|
||||||
'benchmark.table.rps': 'Requests/s',
|
'benchmark.table.rps': 'Requests/s',
|
||||||
'benchmark.table.tps': 'Tokens/s',
|
'benchmark.table.tps': 'Tokens/s',
|
||||||
'benchmark.table.inputLen': 'Input Length',
|
'benchmark.table.inputLen': 'Input Length',
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ export default {
|
|||||||
'benchmark.table.dataset': 'Dataset',
|
'benchmark.table.dataset': 'Dataset',
|
||||||
'benchmark.table.requestRate': 'Request Rate',
|
'benchmark.table.requestRate': 'Request Rate',
|
||||||
'benchmark.table.gpu': 'GPU ',
|
'benchmark.table.gpu': 'GPU ',
|
||||||
'benchmark.table.tpot': 'TPOT (ms)',
|
'benchmark.table.tpot': 'TPOT',
|
||||||
'benchmark.table.itl': 'ITL (ms)',
|
'benchmark.table.itl': 'ITL',
|
||||||
'benchmark.table.ttft': 'TTFT (ms)',
|
'benchmark.table.ttft': 'TTFT',
|
||||||
'benchmark.table.rps': 'Requests/s',
|
'benchmark.table.rps': 'Requests/s',
|
||||||
'benchmark.table.tps': 'Tokens/s',
|
'benchmark.table.tps': 'Tokens/s',
|
||||||
'benchmark.table.inputLen': 'Input Length',
|
'benchmark.table.inputLen': 'Input Length',
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ export default {
|
|||||||
'benchmark.table.dataset': '数据集',
|
'benchmark.table.dataset': '数据集',
|
||||||
'benchmark.table.requestRate': '请求率',
|
'benchmark.table.requestRate': '请求率',
|
||||||
'benchmark.table.gpu': 'GPU ',
|
'benchmark.table.gpu': 'GPU ',
|
||||||
'benchmark.table.tpot': 'TPOT (ms)',
|
'benchmark.table.tpot': 'TPOT',
|
||||||
'benchmark.table.itl': 'ITL (ms)',
|
'benchmark.table.itl': 'ITL',
|
||||||
'benchmark.table.ttft': 'TTFT (ms)',
|
'benchmark.table.ttft': 'TTFT',
|
||||||
'benchmark.table.rps': '请求数/秒',
|
'benchmark.table.rps': '请求数/秒',
|
||||||
'benchmark.table.tps': 'Tokens/秒',
|
'benchmark.table.tps': 'Tokens/秒',
|
||||||
'benchmark.table.inputLen': '输入长度',
|
'benchmark.table.inputLen': '输入长度',
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
import { Tag } from 'antd';
|
import AutoTooltip from '@/components/auto-tooltip';
|
||||||
|
import RowChildren from '@/components/seal-table/components/row-children';
|
||||||
|
import SealTable from '@/components/seal-table/index';
|
||||||
|
import useExpandedRowKeys from '@/hooks/use-expanded-row-keys';
|
||||||
|
import { convertFileSize } from '@/utils';
|
||||||
|
import useMemoizedFn from 'ahooks/lib/useMemoizedFn';
|
||||||
|
import { Col, Row } from 'antd';
|
||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { useDetailContext } from '../../config/detail-context';
|
import { useDetailContext } from '../../config/detail-context';
|
||||||
import WorkerData from './worker-data';
|
|
||||||
|
|
||||||
const Container = styled.div`
|
const Container = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -14,74 +19,209 @@ const Environment: React.FC = () => {
|
|||||||
const { detailData } = useDetailContext();
|
const { detailData } = useDetailContext();
|
||||||
const { snapshot } = detailData;
|
const { snapshot } = detailData;
|
||||||
|
|
||||||
|
const { handleExpandChange, handleExpandAll, expandedRowKeys } =
|
||||||
|
useExpandedRowKeys();
|
||||||
|
|
||||||
const mainWorker = useMemo(() => {
|
const mainWorker = useMemo(() => {
|
||||||
// get workers data
|
// get workers data
|
||||||
|
|
||||||
const [[workerName, workerInfo]] = Object.entries(snapshot.workers);
|
const [[workerName, workerInfo]] = Object.entries(snapshot.workers);
|
||||||
const gpuData = Object.values(snapshot.gpus).filter(
|
const gpuData = Object.values(snapshot.gpus).filter(
|
||||||
(gpu) => gpu.worker_name === workerName
|
(gpu) => gpu.worker_name === workerName
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
workerData: workerInfo,
|
...workerInfo,
|
||||||
gpuData: [...gpuData, ...gpuData]
|
isMain: true,
|
||||||
|
children: gpuData
|
||||||
};
|
};
|
||||||
}, [snapshot]);
|
}, [snapshot]);
|
||||||
|
|
||||||
const subWorkers = useMemo(() => {
|
// const subWorkers = useMemo(() => {
|
||||||
const [[mainWorkerName, mainWorkerInfo]] = Object.entries(snapshot.workers);
|
// const [[mainWorkerName, mainWorkerInfo]] = Object.entries(snapshot.workers);
|
||||||
|
|
||||||
const subOrdinaryWorkers = Object.values(snapshot.instances).filter(
|
// const subOrdinaryWorkers = Object.values(snapshot.instances).filter(
|
||||||
(instance) => instance.worker_name === mainWorkerName
|
// (instance) => instance.worker_name === mainWorkerName
|
||||||
|
// );
|
||||||
|
|
||||||
|
// return subOrdinaryWorkers.map((worker) => {
|
||||||
|
// const gpuData = Object.values(snapshot.gpus).filter(
|
||||||
|
// (gpu) => gpu.worker_name === worker.worker_name
|
||||||
|
// );
|
||||||
|
|
||||||
|
// return {
|
||||||
|
// ...worker,
|
||||||
|
// isMain: false,
|
||||||
|
// children: gpuData
|
||||||
|
// };
|
||||||
|
// });
|
||||||
|
// }, [snapshot, mainWorker]);
|
||||||
|
|
||||||
|
const GPUColumns = [
|
||||||
|
{
|
||||||
|
title: 'GPU Name',
|
||||||
|
dataIndex: 'name',
|
||||||
|
key: 'name',
|
||||||
|
span: 6,
|
||||||
|
colStyle: { paddingLeft: 16 },
|
||||||
|
render: (value: string, record: any) => (
|
||||||
|
<AutoTooltip ghost>{value}</AutoTooltip>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Vendor',
|
||||||
|
dataIndex: 'vendor',
|
||||||
|
key: 'vendor',
|
||||||
|
span: 4,
|
||||||
|
colStyle: { paddingLeft: 46 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'VRAM',
|
||||||
|
dataIndex: 'memory_total',
|
||||||
|
key: 'memory_total',
|
||||||
|
label: 'VRAM',
|
||||||
|
span: 3,
|
||||||
|
render: (value: number, record: any) => convertFileSize(value)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Cores',
|
||||||
|
dataIndex: 'core_total',
|
||||||
|
key: 'core_total',
|
||||||
|
label: 'Cores',
|
||||||
|
span: 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Runtime Version',
|
||||||
|
dataIndex: 'runtime_version',
|
||||||
|
key: 'runtime_version',
|
||||||
|
span: 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Driver Version',
|
||||||
|
dataIndex: 'driver_version',
|
||||||
|
key: 'driver_version',
|
||||||
|
span: 4,
|
||||||
|
colStyle: { paddingLeft: 35 }
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: 'Worker Name',
|
||||||
|
dataIndex: 'name',
|
||||||
|
key: 'name',
|
||||||
|
span: 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'System',
|
||||||
|
dataIndex: 'os',
|
||||||
|
key: 'system',
|
||||||
|
span: 4,
|
||||||
|
render: (os: { name: string; version: string }, record: any) => {
|
||||||
|
return `${record.os.name}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Version',
|
||||||
|
dataIndex: 'version',
|
||||||
|
key: 'version',
|
||||||
|
span: 6,
|
||||||
|
render: (val: any, record: any) => {
|
||||||
|
return <AutoTooltip ghost>{record.os.version}</AutoTooltip>;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'CPU Count',
|
||||||
|
dataIndex: 'cpu_total',
|
||||||
|
key: 'cpu_total',
|
||||||
|
span: 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Memory',
|
||||||
|
dataIndex: 'memory_total',
|
||||||
|
key: 'memory_total',
|
||||||
|
span: 4,
|
||||||
|
render: (value: number) => convertFileSize(value)
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const dataList = useMemo(() => {
|
||||||
|
return [mainWorker];
|
||||||
|
}, [mainWorker]);
|
||||||
|
|
||||||
|
const handleToggleExpandAll = useMemoizedFn((expanded: boolean) => {
|
||||||
|
const keys = dataList?.map((item) => item.id);
|
||||||
|
handleExpandAll(expanded, keys);
|
||||||
|
});
|
||||||
|
|
||||||
|
const loadChildren = useMemoizedFn(async (record: any) => {
|
||||||
|
return record.children || [];
|
||||||
|
});
|
||||||
|
|
||||||
|
const renderChildren = useMemoizedFn((list: any[]) => {
|
||||||
|
return (
|
||||||
|
<div style={{ borderRadius: 'var(--ant-table-header-border-radius)' }}>
|
||||||
|
<RowChildren>
|
||||||
|
{list.map((gpu) => (
|
||||||
|
<Row key={gpu.id} style={{ width: '100%' }} align="middle">
|
||||||
|
{GPUColumns.map((col) => (
|
||||||
|
<Col key={col.key} span={col.span} style={{ ...col.colStyle }}>
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
gap: 4,
|
||||||
|
flexDirection: 'column'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
color: 'var(--ant-color-text-tertiary)',
|
||||||
|
fontSize: 12
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{col.title}
|
||||||
|
</span>
|
||||||
|
{col.render
|
||||||
|
? col.render((gpu as any)[col.dataIndex], gpu)
|
||||||
|
: (gpu as any)[col.dataIndex]}
|
||||||
|
</span>
|
||||||
|
</Col>
|
||||||
|
))}
|
||||||
|
</Row>
|
||||||
|
))}
|
||||||
|
</RowChildren>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
|
});
|
||||||
return subOrdinaryWorkers.map((worker) => {
|
|
||||||
const gpuData = Object.values(snapshot.gpus).filter(
|
|
||||||
(gpu) => gpu.worker_name === worker.worker_name
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
workerData: worker,
|
|
||||||
gpuData: gpuData
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}, [snapshot, mainWorker]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<WorkerData
|
{/* <WorkerData
|
||||||
workerData={mainWorker.workerData}
|
workerData={mainWorker.workerData}
|
||||||
gpuData={mainWorker.gpuData}
|
gpuData={mainWorker.children}
|
||||||
title={
|
title={
|
||||||
<div className="flex-center gap-8">
|
<div className="flex-center gap-8">
|
||||||
<Tag color="geekblue">Main</Tag>
|
<Tag color="geekblue">Main</Tag>
|
||||||
<span>{mainWorker?.workerData?.name}</span>
|
<span>{mainWorker?.workerData?.name}</span>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
></WorkerData>
|
></WorkerData> */}
|
||||||
<WorkerData
|
<SealTable
|
||||||
workerData={mainWorker.workerData}
|
rowKey="id"
|
||||||
gpuData={mainWorker.gpuData}
|
loadChildren={loadChildren}
|
||||||
title={
|
expandedRowKeys={expandedRowKeys}
|
||||||
<div className="flex-center gap-8">
|
onExpand={handleExpandChange}
|
||||||
<Tag
|
onExpandAll={handleToggleExpandAll}
|
||||||
style={{
|
renderChildren={renderChildren}
|
||||||
backgroundColor: 'var(--ant-color-fill-secondary)',
|
showSorterTooltip={false}
|
||||||
color: 'var(--ant-color-text-tertiary)'
|
dataSource={dataList}
|
||||||
}}
|
loading={false}
|
||||||
>
|
loadend={true}
|
||||||
Sub
|
columns={columns}
|
||||||
</Tag>
|
childParentKey="id"
|
||||||
<span>{mainWorker?.workerData?.name}</span>
|
expandable={true}
|
||||||
</div>
|
></SealTable>
|
||||||
}
|
|
||||||
></WorkerData>
|
|
||||||
{/* {subWorkers?.map?.((worker, index) => (
|
|
||||||
<WorkerData
|
|
||||||
key={index}
|
|
||||||
workerData={worker.workerData}
|
|
||||||
gpuData={worker.gpuData}
|
|
||||||
></WorkerData>
|
|
||||||
))} */}
|
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ const Benchmark: React.FC = () => {
|
|||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Section title="Benchmark Parameters">
|
<Section title="Benchmark Parameters" minHeight={132}>
|
||||||
<Descriptions
|
<Descriptions
|
||||||
items={items}
|
items={items}
|
||||||
colon={false}
|
colon={false}
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ const Instance: React.FC = () => {
|
|||||||
}, [detailData]);
|
}, [detailData]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Section title="Model Instance">
|
<Section title="Model Instance" minHeight={220}>
|
||||||
<Descriptions
|
<Descriptions
|
||||||
items={items}
|
items={items}
|
||||||
colon={false}
|
colon={false}
|
||||||
|
|||||||
@@ -12,18 +12,7 @@ const columns = [
|
|||||||
unit: 's',
|
unit: 's',
|
||||||
render: (value: number) => round(value, 2)
|
render: (value: number) => round(value, 2)
|
||||||
},
|
},
|
||||||
{
|
|
||||||
title: 'Concurrency',
|
|
||||||
dataIndex: 'request_concurrency',
|
|
||||||
path: ['raw_metrics', 'benchmarks', '0'],
|
|
||||||
unit: '',
|
|
||||||
render: (value: number) => {
|
|
||||||
return round(
|
|
||||||
_.get(value, 'metrics.request_concurrency.successful.mean'),
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: 'Total Requests',
|
title: 'Total Requests',
|
||||||
dataIndex: 'total_requests',
|
dataIndex: 'total_requests',
|
||||||
@@ -31,6 +20,13 @@ const columns = [
|
|||||||
unit: '',
|
unit: '',
|
||||||
render: (value: number) => round(value, 0)
|
render: (value: number) => round(value, 0)
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'Total token throughput',
|
||||||
|
dataIndex: 'tokens_per_second_mean',
|
||||||
|
path: 'tokens_per_second_mean',
|
||||||
|
unit: 'Tokens/s',
|
||||||
|
render: (value: number) => round(value, 2)
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: 'Success Requests',
|
title: 'Success Requests',
|
||||||
dataIndex: 'successful_requests',
|
dataIndex: 'successful_requests',
|
||||||
@@ -44,6 +40,17 @@ const columns = [
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
title: 'Output token throughput',
|
||||||
|
dataIndex: 'output_tokens_per_second_mean',
|
||||||
|
path: 'output_tokens_per_second_mean',
|
||||||
|
unit: 'Tokens/s',
|
||||||
|
render: (value: number) => round(value, 2)
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const columnsSub = [
|
||||||
{
|
{
|
||||||
title: 'Failed Requests',
|
title: 'Failed Requests',
|
||||||
dataIndex: 'failed_requests',
|
dataIndex: 'failed_requests',
|
||||||
@@ -58,27 +65,22 @@ const columns = [
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Output token throughput (t/s)',
|
title: 'Concurrency',
|
||||||
dataIndex: 'output_tokens_per_second_mean',
|
dataIndex: 'request_concurrency',
|
||||||
path: 'output_tokens_per_second_mean',
|
path: ['raw_metrics', 'benchmarks', '0'],
|
||||||
unit: 't/s',
|
unit: '',
|
||||||
render: (value: number) => round(value, 2)
|
render: (value: number) => {
|
||||||
}
|
return round(
|
||||||
];
|
_.get(value, 'metrics.request_concurrency.successful.mean'),
|
||||||
|
0
|
||||||
const columnsSub = [
|
);
|
||||||
{
|
}
|
||||||
title: 'Total token throughput (t/s)',
|
|
||||||
dataIndex: 'tokens_per_second_mean',
|
|
||||||
path: 'tokens_per_second_mean',
|
|
||||||
unit: 't/s',
|
|
||||||
render: (value: number) => round(value, 2)
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Request token throughput (t/s)',
|
title: 'Request token throughput ',
|
||||||
dataIndex: 'prompt_tokens_per_second_mean',
|
dataIndex: 'prompt_tokens_per_second_mean',
|
||||||
path: 'prompt_tokens_per_second_mean',
|
path: 'prompt_tokens_per_second_mean',
|
||||||
unit: 't/s',
|
unit: 'Tokens/s',
|
||||||
render: (value: number) => round(value, 2)
|
render: (value: number) => round(value, 2)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -135,14 +137,19 @@ const PercentileResult: React.FC = () => {
|
|||||||
({ title, dataIndex, path, render, unit }) => ({
|
({ title, dataIndex, path, render, unit }) => ({
|
||||||
key: dataIndex,
|
key: dataIndex,
|
||||||
label: title,
|
label: title,
|
||||||
children: unit
|
children: unit ? (
|
||||||
? render(_.get(detailData, path) ?? 0) + ` (${unit})`
|
<span className="flex-center">
|
||||||
: render(_.get(detailData, path) ?? 0)
|
{render(_.get(detailData, path) ?? 0)}{' '}
|
||||||
|
<span className="m-l-4">({unit})</span>
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
render(_.get(detailData, path) ?? 0)
|
||||||
|
)
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Section title="Metrics Result" minHeight={200}>
|
<Section title="Metrics Result" minHeight={210}>
|
||||||
{/* <Table
|
{/* <Table
|
||||||
size="small"
|
size="small"
|
||||||
columns={[
|
columns={[
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ const PercentileResult: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Section title="Percentiles Result">
|
<Section title="Percentiles Result" minHeight={240}>
|
||||||
<Table
|
<Table
|
||||||
size="small"
|
size="small"
|
||||||
columns={[
|
columns={[
|
||||||
@@ -90,6 +90,17 @@ const PercentileResult: React.FC = () => {
|
|||||||
rowKey="percentile"
|
rowKey="percentile"
|
||||||
pagination={false}
|
pagination={false}
|
||||||
styles={{
|
styles={{
|
||||||
|
// header: {
|
||||||
|
// row: {
|
||||||
|
// background: 'none',
|
||||||
|
// borderBottom: '1px solid var(--ant-color-split)'
|
||||||
|
// },
|
||||||
|
// cell: {
|
||||||
|
// background: 'none',
|
||||||
|
// paddingBottom: 0,
|
||||||
|
// borderBottom: '1px solid var(--ant-color-split)'
|
||||||
|
// }
|
||||||
|
// },
|
||||||
body: {
|
body: {
|
||||||
cell: {
|
cell: {
|
||||||
height: 54
|
height: 54
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ export interface FormData {
|
|||||||
dataset_output_tokens: number;
|
dataset_output_tokens: number;
|
||||||
total_requests: number;
|
total_requests: number;
|
||||||
request_rate: number;
|
request_rate: number;
|
||||||
seed: number;
|
dataset_seed: number;
|
||||||
model_instance?: string;
|
model_instance?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import AutoComplete from '@/components/seal-form/auto-complete';
|
|
||||||
import SealInput from '@/components/seal-form/seal-input';
|
import SealInput from '@/components/seal-form/seal-input';
|
||||||
import SealSelect from '@/components/seal-form/seal-select';
|
import SealSelect from '@/components/seal-form/seal-select';
|
||||||
import useAppUtils from '@/hooks/use-app-utils';
|
import useAppUtils from '@/hooks/use-app-utils';
|
||||||
@@ -32,30 +31,17 @@ const DatasetForm: React.FC = () => {
|
|||||||
} = useQueryProfiles();
|
} = useQueryProfiles();
|
||||||
|
|
||||||
const handleOnDataSetChange = (value: any, option: any) => {
|
const handleOnDataSetChange = (value: any, option: any) => {
|
||||||
if (value === 'Custom') {
|
form.setFieldsValue({
|
||||||
form.setFieldsValue({
|
dataset_id: option?.data?.id,
|
||||||
profile: ProfileValueMap.Custom,
|
dataset_prompt_tokens: option?.prompt_tokens,
|
||||||
dataset_id: null
|
dataset_output_tokens: option?.output_tokens,
|
||||||
});
|
request_rate: null,
|
||||||
} else {
|
total_requests: null
|
||||||
form.setFieldsValue({
|
});
|
||||||
profile: ProfileValueMap.Custom,
|
|
||||||
dataset_id: option?.data?.id,
|
|
||||||
dataset_prompt_tokens: option?.prompt_tokens,
|
|
||||||
dataset_output_tokens: option?.output_tokens,
|
|
||||||
request_rate: null,
|
|
||||||
total_requests: null
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleProfileChange = (value: string, option: any) => {
|
const handleProfileChange = (value: string, option: any) => {
|
||||||
if (value === ProfileValueMap.Custom) {
|
if (value !== ProfileValueMap.Custom) {
|
||||||
form.setFieldsValue({
|
|
||||||
dataset_name: 'Custom',
|
|
||||||
dataset_id: null
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
const dataset_id = datasetList.find(
|
const dataset_id = datasetList.find(
|
||||||
(item) => item.label === option.config?.dataset_name
|
(item) => item.label === option.config?.dataset_name
|
||||||
)?.value;
|
)?.value;
|
||||||
@@ -97,31 +83,17 @@ const DatasetForm: React.FC = () => {
|
|||||||
required
|
required
|
||||||
></SealSelect>
|
></SealSelect>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item<FormData>
|
|
||||||
name="dataset_name"
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: getRuleMessage('select', 'benchmark.table.dataset')
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<AutoComplete
|
|
||||||
options={datasetList.map((item) => ({
|
|
||||||
...item,
|
|
||||||
label: item.label,
|
|
||||||
value: item.label
|
|
||||||
}))}
|
|
||||||
loading={datasetLoading}
|
|
||||||
onChange={handleOnDataSetChange}
|
|
||||||
label={intl.formatMessage({ id: 'benchmark.table.dataset' })}
|
|
||||||
required
|
|
||||||
></AutoComplete>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item<FormData> hidden name="dataset_id">
|
<Form.Item<FormData> hidden name="dataset_id">
|
||||||
<SealInput.Input></SealInput.Input>
|
<SealInput.Input></SealInput.Input>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
{profile === 'Custom' && <RandomSettingsForm></RandomSettingsForm>}
|
{profile === 'Custom' && (
|
||||||
|
<RandomSettingsForm
|
||||||
|
datasetList={datasetList}
|
||||||
|
datasetLoading={datasetLoading}
|
||||||
|
handleOnDataSetChange={handleOnDataSetChange}
|
||||||
|
></RandomSettingsForm>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ const ProviderForm: React.FC<ProviderFormProps> = forwardRef((props, ref) => {
|
|||||||
dataset_output_tokens: null,
|
dataset_output_tokens: null,
|
||||||
total_requests: null,
|
total_requests: null,
|
||||||
request_rate: null,
|
request_rate: null,
|
||||||
seed: null
|
dataset_seed: null
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Basic />
|
<Basic />
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
import SealInputNumber from '@/components/seal-form/input-number';
|
import SealInputNumber from '@/components/seal-form/input-number';
|
||||||
|
import SealSelect from '@/components/seal-form/seal-select';
|
||||||
import useAppUtils from '@/hooks/use-app-utils';
|
import useAppUtils from '@/hooks/use-app-utils';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Form } from 'antd';
|
import { Form } from 'antd';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FormData } from '../config/types';
|
import { FormData } from '../config/types';
|
||||||
|
|
||||||
const RandomSettingsForm: React.FC = () => {
|
const RandomSettingsForm: React.FC<{
|
||||||
|
datasetList: Global.BaseOption<number | string>[];
|
||||||
|
datasetLoading: boolean;
|
||||||
|
handleOnDataSetChange: (value: any, option: any) => void;
|
||||||
|
}> = (props) => {
|
||||||
|
const { datasetList, datasetLoading, handleOnDataSetChange } = props;
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const form = Form.useFormInstance();
|
const form = Form.useFormInstance();
|
||||||
const profile = Form.useWatch('profile', form);
|
const profile = Form.useWatch('profile', form);
|
||||||
@@ -15,6 +21,28 @@ const RandomSettingsForm: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<Form.Item<FormData>
|
||||||
|
name="dataset_name"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: getRuleMessage('select', 'benchmark.table.dataset')
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<SealSelect
|
||||||
|
disabled={disabled}
|
||||||
|
options={datasetList?.map((item) => ({
|
||||||
|
...item,
|
||||||
|
label: item.label,
|
||||||
|
value: item.label
|
||||||
|
}))}
|
||||||
|
loading={datasetLoading}
|
||||||
|
onChange={handleOnDataSetChange}
|
||||||
|
label={intl.formatMessage({ id: 'benchmark.table.dataset' })}
|
||||||
|
required
|
||||||
|
></SealSelect>
|
||||||
|
</Form.Item>
|
||||||
<Form.Item<FormData>
|
<Form.Item<FormData>
|
||||||
name="dataset_prompt_tokens"
|
name="dataset_prompt_tokens"
|
||||||
rules={[
|
rules={[
|
||||||
@@ -53,7 +81,7 @@ const RandomSettingsForm: React.FC = () => {
|
|||||||
></SealInputNumber>
|
></SealInputNumber>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item<FormData>
|
<Form.Item<FormData>
|
||||||
name="seed"
|
name="dataset_seed"
|
||||||
getValueProps={(value) => ({ value: value || null })}
|
getValueProps={(value) => ({ value: value || null })}
|
||||||
>
|
>
|
||||||
<SealInputNumber
|
<SealInputNumber
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import { tableSorter } from '@/config/settings';
|
|||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Typography } from 'antd';
|
import { Typography } from 'antd';
|
||||||
import { ColumnsType } from 'antd/es/table';
|
import { ColumnsType } from 'antd/es/table';
|
||||||
import dayjs from 'dayjs';
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import RowActions from '../components/row-actions';
|
import RowActions from '../components/row-actions';
|
||||||
@@ -70,16 +69,16 @@ const useBenchmarkColumns = (
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
title: intl.formatMessage({ id: 'benchmark.table.requestRate' }),
|
// title: intl.formatMessage({ id: 'benchmark.table.requestRate' }),
|
||||||
dataIndex: 'request_rate',
|
// dataIndex: 'request_rate',
|
||||||
sorter: tableSorter(1),
|
// sorter: tableSorter(1),
|
||||||
render: (text: string) => (
|
// render: (text: string) => (
|
||||||
<AutoTooltip ghost minWidth={20}>
|
// <AutoTooltip ghost minWidth={20}>
|
||||||
{text}
|
// {text}
|
||||||
</AutoTooltip>
|
// </AutoTooltip>
|
||||||
)
|
// )
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
title: intl.formatMessage({ id: 'benchmark.table.gpu' }),
|
title: intl.formatMessage({ id: 'benchmark.table.gpu' }),
|
||||||
dataIndex: 'gpu_summary',
|
dataIndex: 'gpu_summary',
|
||||||
@@ -91,7 +90,12 @@ const useBenchmarkColumns = (
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: intl.formatMessage({ id: 'benchmark.table.itl' }),
|
title: (
|
||||||
|
<span className="flex-column">
|
||||||
|
<span>{intl.formatMessage({ id: 'benchmark.table.itl' })}</span>
|
||||||
|
<span>avg (ms)</span>
|
||||||
|
</span>
|
||||||
|
),
|
||||||
dataIndex: 'inter_token_latency_mean',
|
dataIndex: 'inter_token_latency_mean',
|
||||||
sorter: tableSorter(1),
|
sorter: tableSorter(1),
|
||||||
render: (text: string) => (
|
render: (text: string) => (
|
||||||
@@ -101,7 +105,12 @@ const useBenchmarkColumns = (
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: intl.formatMessage({ id: 'benchmark.table.tpot' }),
|
title: (
|
||||||
|
<span className="flex-column">
|
||||||
|
<span>{intl.formatMessage({ id: 'benchmark.table.tpot' })}</span>
|
||||||
|
<span>avg (ms)</span>
|
||||||
|
</span>
|
||||||
|
),
|
||||||
dataIndex: 'time_per_output_token_mean',
|
dataIndex: 'time_per_output_token_mean',
|
||||||
sorter: tableSorter(1),
|
sorter: tableSorter(1),
|
||||||
render: (text: string) => (
|
render: (text: string) => (
|
||||||
@@ -111,7 +120,12 @@ const useBenchmarkColumns = (
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: intl.formatMessage({ id: 'benchmark.table.ttft' }),
|
title: (
|
||||||
|
<span className="flex-column">
|
||||||
|
<span>{intl.formatMessage({ id: 'benchmark.table.ttft' })}</span>
|
||||||
|
<span>avg (ms)</span>
|
||||||
|
</span>
|
||||||
|
),
|
||||||
dataIndex: 'time_to_first_token_mean',
|
dataIndex: 'time_to_first_token_mean',
|
||||||
sorter: tableSorter(1),
|
sorter: tableSorter(1),
|
||||||
render: (text: string) => (
|
render: (text: string) => (
|
||||||
@@ -140,16 +154,16 @@ const useBenchmarkColumns = (
|
|||||||
</AutoTooltip>
|
</AutoTooltip>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
title: intl.formatMessage({ id: 'common.table.createTime' }),
|
// title: intl.formatMessage({ id: 'common.table.createTime' }),
|
||||||
dataIndex: 'created_at',
|
// dataIndex: 'created_at',
|
||||||
sorter: tableSorter(3),
|
// sorter: tableSorter(3),
|
||||||
render: (value: string) => (
|
// render: (value: string) => (
|
||||||
<AutoTooltip ghost>
|
// <AutoTooltip ghost>
|
||||||
{dayjs(value).format('YYYY-MM-DD HH:mm:ss')}
|
// {dayjs(value).format('YYYY-MM-DD HH:mm:ss')}
|
||||||
</AutoTooltip>
|
// </AutoTooltip>
|
||||||
)
|
// )
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
title: intl.formatMessage({ id: 'common.table.operation' }),
|
title: intl.formatMessage({ id: 'common.table.operation' }),
|
||||||
dataIndex: 'operations',
|
dataIndex: 'operations',
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
import { useQueryDataList } from '@/hooks/use-query-data-list';
|
import { useQueryDataList } from '@/hooks/use-query-data-list';
|
||||||
import { useIntl } from '@umijs/max';
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { queryDatasetList } from '../apis';
|
import { queryDatasetList } from '../apis';
|
||||||
import { DatasetListItem } from '../config/types';
|
import { DatasetListItem } from '../config/types';
|
||||||
|
|
||||||
const useQueryDataset = () => {
|
const useQueryDataset = () => {
|
||||||
const intl = useIntl();
|
|
||||||
const { dataList, loading, fetchData, cancelRequest } = useQueryDataList<
|
const { dataList, loading, fetchData, cancelRequest } = useQueryDataList<
|
||||||
DatasetListItem,
|
DatasetListItem,
|
||||||
Global.SearchParams
|
Global.SearchParams
|
||||||
@@ -29,13 +27,7 @@ const useQueryDataset = () => {
|
|||||||
value: item.id
|
value: item.id
|
||||||
})) || [];
|
})) || [];
|
||||||
|
|
||||||
setDatasetList([
|
setDatasetList([...list]);
|
||||||
...list,
|
|
||||||
{
|
|
||||||
label: intl.formatMessage({ id: 'backend.custom' }),
|
|
||||||
value: 'Custom'
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
Reference in New Issue
Block a user