fix: only keep the max count cpu instance type

This commit is contained in:
jialin
2026-06-12 16:02:22 +08:00
committed by jialin
parent ddf723525a
commit 01f66085ab
5 changed files with 683 additions and 88 deletions
+1
View File
@@ -31,5 +31,6 @@ export default function createProxyTable(target?: string) {
},
{}
);
return proxyTable;
}
@@ -8,11 +8,10 @@ import {
AlertBlockInfo,
ColumnWrapper,
GSDrawer,
IconFont,
ModalFooter
} from '@gpustack/core-ui';
import { useIntl } from '@umijs/max';
import { Empty, Flex, Input, Segmented, Typography } from 'antd';
import { Empty, Input, Typography } from 'antd';
import _ from 'lodash';
import { useEffect, useMemo, useRef, useState } from 'react';
import { ListItem as TemplateItem } from '../../templates/config/types';
@@ -90,7 +89,6 @@ const AddModal: React.FC<AddModalProps> = ({
manufacturer: undefined
});
const [templateId, setTemplateId] = useState<number | undefined>();
const [resourceType, setResourceType] = useState<'gpu' | 'cpu'>('gpu');
const [instanceKeyword, setInstanceKeyword] = useState('');
const [templateKeyword, setTemplateKeyword] = useState('');
const { loading, guard, run, release } = useSubmitLock();
@@ -189,14 +187,6 @@ const AddModal: React.FC<AddModalProps> = ({
const manufacturerOf = (instanceType: InstanceTypeItem) =>
instanceType.spec.acceleratable ? instanceType.spec?.manufacturer : 'cpu';
const matchesResourceType = (
instanceType: InstanceTypeItem,
type: 'gpu' | 'cpu'
) =>
type === 'gpu'
? !!instanceType.spec.acceleratable
: !instanceType.spec.acceleratable;
// apply the selection of instance type and template
const applySelection = (
instanceType: InstanceTypeItem,
@@ -300,8 +290,6 @@ const AddModal: React.FC<AddModalProps> = ({
instanceType: aggregate.name,
manufacturer: manufacturerOf(aggregate)
});
// Surface the persisted pick under the matching segment.
setResourceType(aggregate.spec.acceleratable ? 'gpu' : 'cpu');
}
return;
}
@@ -309,23 +297,9 @@ const AddModal: React.FC<AddModalProps> = ({
// Scope to clusters the chosen org owns (admin "All" view).
const owned = filterTypesByOwner(instanceTypes, clusters || [], orgId);
// Prefer the active segment, but fall back to the other kind when it has
// no enabled candidate so the drawer never opens on an empty list.
const hasEnabled = (type: 'gpu' | 'cpu') =>
owned.some((it) => matchesResourceType(it, type) && !it.disabled);
const other = resourceType === 'gpu' ? 'cpu' : 'gpu';
const nextType = hasEnabled(resourceType)
? resourceType
: hasEnabled(other)
? other
: resourceType;
setResourceType(nextType);
// On create, auto-select the first instance type of the chosen kind.
autoSelectFirst(
owned.filter((it) => matchesResourceType(it, nextType)),
templates
);
// On create, auto-select the first available instance type (clears the
// selection when the chosen org has none).
autoSelectFirst(owned, templates);
};
// Fetch the (tenant-scoped) instance types + templates and auto-select.
@@ -383,7 +357,6 @@ const AddModal: React.FC<AddModalProps> = ({
manufacturer: undefined
});
setTemplateId(undefined);
setResourceType('gpu');
setInstanceKeyword('');
setTemplateKeyword('');
setScopeOrgId(undefined);
@@ -395,20 +368,10 @@ const AddModal: React.FC<AddModalProps> = ({
}
}, [open, shouldAutoSelectResource, action]);
// Which kinds the chosen org actually offers — drives the GPU/CPU segment
// availability so a user can't switch to an empty list.
const hasGPUTypes = ownedInstanceTypes.some(
(item) => item.spec.acceleratable
// filter instance types (already scoped to the chosen org's clusters)
const filteredInstanceTypes = ownedInstanceTypes.filter((item) =>
matchKeyword([item.name], instanceKeyword)
);
const hasCPUTypes = ownedInstanceTypes.some(
(item) => !item.spec.acceleratable
);
// filter instance types (already scoped to the chosen org's clusters) by the
// active GPU/CPU segment, then by the search keyword.
const filteredInstanceTypes = ownedInstanceTypes
.filter((item) => matchesResourceType(item, resourceType))
.filter((item) => matchKeyword([item.name], instanceKeyword));
// No instance types for the chosen org (e.g. it owns no clusters), and not
// mid-fetch — drives the "no available instance type" message in the form.
@@ -477,14 +440,6 @@ const AddModal: React.FC<AddModalProps> = ({
});
};
const handleOnTypeChange = (next: 'gpu' | 'cpu') => {
setResourceType(next);
autoSelectFirst(
ownedInstanceTypes.filter((item) => matchesResourceType(item, next)),
templateList
);
};
return (
<GSDrawer
title={title}
@@ -520,34 +475,9 @@ const AddModal: React.FC<AddModalProps> = ({
}}
>
<ColTitle style={{ paddingBottom: 0 }}>
<Flex justify="space-between" align="center">
<span>
{intl.formatMessage({
id: 'gpuservice.instance.types'
})}
</span>
<Segmented
size="small"
shape="round"
className={styles.segmented}
value={resourceType}
onChange={handleOnTypeChange}
options={[
{
label: 'GPU',
value: 'gpu',
icon: <IconFont type="icon-gpu1" />,
disabled: !hasGPUTypes
},
{
label: 'CPU',
value: 'cpu',
icon: <IconFont type="icon-cpu" />,
disabled: !hasCPUTypes
}
]}
></Segmented>
</Flex>
{intl.formatMessage({
id: 'gpuservice.instance.types'
})}
</ColTitle>
<Input
allowClear
@@ -112,7 +112,7 @@ function getInstanceDerived(item: InstanceTypeItemModel) {
acceleratable,
isGPU: acceleratable,
manufacturer: acceleratable ? spec.manufacturer || '' : 'cpu', // GPU manufacturer or 'cpu' for non-acceleratable types
displayName: spec.product || item.name,
displayName: acceleratable ? spec.product || item.name : 'CPU',
ramUnit: spec.unitResourcesParsed?.ram?.value,
os: _.capitalize(spec.os) || '',
arch: spec.arch,
@@ -231,7 +231,6 @@ const InstanceTypeItem: React.FC<InstanceTypeItemProps> = ({ item }) => {
const manufacturerColor = manufactureColorMap[manufacturer] ?? 'purple';
const showManufacturerTag = acceleratable && !!manufacturer;
const showCPUManufacturerTag = !acceleratable && !!cpuManufacturer;
return (
<Flex
@@ -262,11 +261,6 @@ const InstanceTypeItem: React.FC<InstanceTypeItemProps> = ({ item }) => {
{manufacturer?.toUpperCase()}
</ThemeTag>
)}
{showCPUManufacturerTag && (
<CPUManufacturerTag
manufacturer={`${cpuManufacturer}`}
></CPUManufacturerTag>
)}
</Flex>
</Title>
<InstanceMetadataSection spec={specData}></InstanceMetadataSection>
@@ -0,0 +1,648 @@
export default {
items: [
{
name: 'gpustack--amd-epyc-7r32-ln-x64-4c-16g--nvidia-a10g-1d',
spec: {
memory: '22Gi',
cores: '10240',
computeCapability: '8.6',
sliced: null,
cpu: {
physicalCores: '2',
threadsPerPhysicalCore: '2',
logicalCores: '4',
stepping: null,
clockSpeed: null,
maxClockSpeed: null,
cacheLine: '64',
cache: {
l1i: '32768',
l1d: '32768',
l2: '524288',
l3: '8388608'
},
manufacturer: 'amd',
product: 'AMD EPYC 7R32',
family: '23'
},
physicalCores: null,
threadsPerPhysicalCore: null,
logicalCores: null,
stepping: null,
clockSpeed: null,
maxClockSpeed: null,
cacheLine: null,
cache: {
l1i: null,
l1d: null,
l2: null,
l3: null
},
group: 'gpustack--amd-epyc-7r32-ln-x64-4c-16g--nvidia-a10g-1d',
acceleratable: true,
manufacturer: 'nvidia',
product: 'NVIDIA-A10G',
family: 'Ampere',
os: 'linux',
arch: 'amd64',
unitResources: {
cpu: '4',
ram: '16Gi'
}
},
status: {
onceMaxRequest: {
accelerator: '1',
cpu: '4',
ram: '16Gi',
localStorage: '98Gi'
},
remaining: {
accelerator: '1',
cpu: '4',
ram: '16Gi',
localStorage: '98Gi'
},
tiers: [
{
onceMaxRequest: {
accelerator: '1',
cpu: '4',
ram: '16Gi',
localStorage: '98Gi'
},
remaining: {
accelerator: '1',
cpu: '4',
ram: '16Gi',
localStorage: '98Gi'
},
candidates: [
{
cluster: '1',
name: 'gpustack--amd-epyc-7r32-ln-x64-4c-16g--nvidia-a10g-1d',
accelerator: {
onceMaxRequest: '1',
remaining: '1',
capacity: '1'
},
cpu: {
onceMaxRequest: '4',
remaining: '4',
capacity: '4'
},
ram: {
onceMaxRequest: '16Gi',
remaining: '16Gi',
capacity: '16Gi'
},
localStorage: {
onceMaxRequest: '98Gi',
remaining: '98Gi',
capacity: '98Gi'
}
}
]
}
]
}
},
{
name: 'gpustack--intel-xeon-platinum-8259cl-ln-x64-12c-46g--nvidia-tesla-t4-1d',
spec: {
memory: '15Gi',
cores: '2560',
computeCapability: '7.5',
sliced: null,
cpu: {
physicalCores: '24',
threadsPerPhysicalCore: '2',
logicalCores: '48',
stepping: '7',
clockSpeed: '2500000000',
maxClockSpeed: null,
cacheLine: '64',
cache: {
l1i: '32768',
l1d: '32768',
l2: '1048576',
l3: '37486592'
},
manufacturer: 'intel',
product: 'Intel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHz',
family: '6'
},
physicalCores: null,
threadsPerPhysicalCore: null,
logicalCores: null,
stepping: null,
clockSpeed: null,
maxClockSpeed: null,
cacheLine: null,
cache: {
l1i: null,
l1d: null,
l2: null,
l3: null
},
group:
'gpustack--intel-xeon-platinum-8259cl-ln-x64-12c-46g--nvidia-tesla-t4-1d',
acceleratable: true,
manufacturer: 'nvidia',
product: 'Tesla-T4',
family: 'Turing',
os: 'linux',
arch: 'amd64',
unitResources: {
cpu: '12',
ram: '46Gi'
}
},
status: {
onceMaxRequest: {
accelerator: '4',
cpu: '48',
ram: '186Gi',
localStorage: '98Gi'
},
remaining: {
accelerator: '4',
cpu: '48',
ram: '186Gi',
localStorage: '98Gi'
},
tiers: [
{
onceMaxRequest: {
accelerator: '4',
cpu: '48',
ram: '186Gi',
localStorage: '98Gi'
},
remaining: {
accelerator: '4',
cpu: '48',
ram: '186Gi',
localStorage: '98Gi'
},
candidates: [
{
cluster: '1',
name: 'gpustack--intel-xeon-platinum-8259cl-ln-x64-12c-46g--nvidia-tesla-t4-1d',
accelerator: {
onceMaxRequest: '4',
remaining: '4',
capacity: '4'
},
cpu: {
onceMaxRequest: '48',
remaining: '48',
capacity: '48'
},
ram: {
onceMaxRequest: '186Gi',
remaining: '186Gi',
capacity: '186Gi'
},
localStorage: {
onceMaxRequest: '98Gi',
remaining: '98Gi',
capacity: '98Gi'
}
}
]
}
]
}
},
{
name: 'gpustack--intel-xeon-platinum-8259cl-ln-x64-4c-16g--nvidia-tesla-t4-1d',
spec: {
memory: '15Gi',
cores: '2560',
computeCapability: '7.5',
sliced: null,
cpu: {
physicalCores: '2',
threadsPerPhysicalCore: '2',
logicalCores: '4',
stepping: '7',
clockSpeed: '2500000000',
maxClockSpeed: null,
cacheLine: '64',
cache: {
l1i: '32768',
l1d: '32768',
l2: '1048576',
l3: '37486592'
},
manufacturer: 'intel',
product: 'Intel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHz',
family: '6'
},
physicalCores: null,
threadsPerPhysicalCore: null,
logicalCores: null,
stepping: null,
clockSpeed: null,
maxClockSpeed: null,
cacheLine: null,
cache: {
l1i: null,
l1d: null,
l2: null,
l3: null
},
group:
'gpustack--intel-xeon-platinum-8259cl-ln-x64-4c-16g--nvidia-tesla-t4-1d',
acceleratable: true,
manufacturer: 'nvidia',
product: 'Tesla-T4',
family: 'Turing',
os: 'linux',
arch: 'amd64',
unitResources: {
cpu: '4',
ram: '16Gi'
}
},
status: {
onceMaxRequest: {
accelerator: '1',
cpu: '4',
ram: '16Gi',
localStorage: '98Gi'
},
remaining: {
accelerator: '1',
cpu: '4',
ram: '16Gi',
localStorage: '98Gi'
},
tiers: [
{
onceMaxRequest: {
accelerator: '1',
cpu: '4',
ram: '16Gi',
localStorage: '98Gi'
},
remaining: {
accelerator: '1',
cpu: '4',
ram: '16Gi',
localStorage: '98Gi'
},
candidates: [
{
cluster: '1',
name: 'gpustack--intel-xeon-platinum-8259cl-ln-x64-4c-16g--nvidia-tesla-t4-1d',
accelerator: {
onceMaxRequest: '1',
remaining: '1',
capacity: '1'
},
cpu: {
onceMaxRequest: '4',
remaining: '4',
capacity: '4'
},
ram: {
onceMaxRequest: '16Gi',
remaining: '16Gi',
capacity: '16Gi'
},
localStorage: {
onceMaxRequest: '98Gi',
remaining: '98Gi',
capacity: '98Gi'
}
}
]
}
]
}
},
{
name: 'gpustack--amd-epyc-7r13-processor-ln-x64-1c-2g',
spec: {
memory: null,
cores: null,
computeCapability: null,
sliced: null,
cpu: {
physicalCores: null,
threadsPerPhysicalCore: null,
logicalCores: null,
stepping: null,
clockSpeed: null,
maxClockSpeed: null,
cacheLine: null,
cache: {
l1i: null,
l1d: null,
l2: null,
l3: null
},
manufacturer: null,
product: null,
family: null
},
physicalCores: '8',
threadsPerPhysicalCore: '2',
logicalCores: '16',
stepping: '1',
clockSpeed: null,
maxClockSpeed: null,
cacheLine: '64',
cache: {
l1i: '32768',
l1d: '32768',
l2: '524288',
l3: '33554432'
},
group: 'gpustack--amd-epyc-7r13-processor-ln-x64-1c-2g',
acceleratable: false,
manufacturer: 'amd',
product: 'AMD EPYC 7R13 Processor',
family: '25',
os: 'linux',
arch: 'amd64',
unitResources: {
cpu: '1',
ram: '2Gi'
}
},
status: {
onceMaxRequest: {
accelerator: '0',
cpu: '16',
ram: '32Gi',
localStorage: '98Gi'
},
remaining: {
accelerator: '0',
cpu: '16',
ram: '32Gi',
localStorage: '98Gi'
},
tiers: [
{
onceMaxRequest: {
accelerator: '0',
cpu: '16',
ram: '32Gi',
localStorage: '98Gi'
},
remaining: {
accelerator: '0',
cpu: '16',
ram: '32Gi',
localStorage: '98Gi'
},
candidates: [
{
cluster: '1',
name: 'gpustack--amd-epyc-7r13-processor-ln-x64-1c-2g',
accelerator: {
onceMaxRequest: '0',
remaining: '0',
capacity: '0'
},
cpu: {
onceMaxRequest: '16',
remaining: '16',
capacity: '16'
},
ram: {
onceMaxRequest: '32Gi',
remaining: '32Gi',
capacity: '32Gi'
},
localStorage: {
onceMaxRequest: '98Gi',
remaining: '98Gi',
capacity: '98Gi'
}
}
]
}
]
}
},
{
name: 'gpustack--amd-epyc-7r32-ln-x64-1c-2g',
spec: {
memory: null,
cores: null,
computeCapability: null,
sliced: null,
cpu: {
physicalCores: null,
threadsPerPhysicalCore: null,
logicalCores: null,
stepping: null,
clockSpeed: null,
maxClockSpeed: null,
cacheLine: null,
cache: {
l1i: null,
l1d: null,
l2: null,
l3: null
},
manufacturer: null,
product: null,
family: null
},
physicalCores: '2',
threadsPerPhysicalCore: '2',
logicalCores: '4',
stepping: null,
clockSpeed: null,
maxClockSpeed: null,
cacheLine: '64',
cache: {
l1i: '32768',
l1d: '32768',
l2: '524288',
l3: '8388608'
},
group: 'gpustack--amd-epyc-7r32-ln-x64-1c-2g',
acceleratable: false,
manufacturer: 'amd',
product: 'AMD EPYC 7R32',
family: '23',
os: 'linux',
arch: 'amd64',
unitResources: {
cpu: '1',
ram: '2Gi'
}
},
status: {
onceMaxRequest: {
accelerator: '0',
cpu: '4',
ram: '8Gi',
localStorage: '98Gi'
},
remaining: {
accelerator: '0',
cpu: '4',
ram: '8Gi',
localStorage: '98Gi'
},
tiers: [
{
onceMaxRequest: {
accelerator: '0',
cpu: '4',
ram: '8Gi',
localStorage: '98Gi'
},
remaining: {
accelerator: '0',
cpu: '4',
ram: '8Gi',
localStorage: '98Gi'
},
candidates: [
{
cluster: '1',
name: 'gpustack--amd-epyc-7r32-ln-x64-1c-2g',
accelerator: {
onceMaxRequest: '0',
remaining: '0',
capacity: '0'
},
cpu: {
onceMaxRequest: '4',
remaining: '4',
capacity: '4'
},
ram: {
onceMaxRequest: '8Gi',
remaining: '8Gi',
capacity: '8Gi'
},
localStorage: {
onceMaxRequest: '98Gi',
remaining: '98Gi',
capacity: '98Gi'
}
}
]
}
]
}
},
{
name: 'gpustack--intel-xeon-platinum-8259cl-ln-x64-1c-2g',
spec: {
memory: null,
cores: null,
computeCapability: null,
sliced: null,
cpu: {
physicalCores: null,
threadsPerPhysicalCore: null,
logicalCores: null,
stepping: null,
clockSpeed: null,
maxClockSpeed: null,
cacheLine: null,
cache: {
l1i: null,
l1d: null,
l2: null,
l3: null
},
manufacturer: null,
product: null,
family: null
},
physicalCores: '24',
threadsPerPhysicalCore: '2',
logicalCores: '48',
stepping: '7',
clockSpeed: '2500000000',
maxClockSpeed: null,
cacheLine: '64',
cache: {
l1i: '32768',
l1d: '32768',
l2: '1048576',
l3: '37486592'
},
group: 'gpustack--intel-xeon-platinum-8259cl-ln-x64-1c-2g',
acceleratable: false,
manufacturer: 'intel',
product: 'Intel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHz',
family: '6',
os: 'linux',
arch: 'amd64',
unitResources: {
cpu: '1',
ram: '2Gi'
}
},
status: {
onceMaxRequest: {
accelerator: '0',
cpu: '48',
ram: '96Gi',
localStorage: '98Gi'
},
remaining: {
accelerator: '0',
cpu: '52',
ram: '104Gi',
localStorage: '196Gi'
},
tiers: [
{
onceMaxRequest: {
accelerator: '0',
cpu: '48',
ram: '96Gi',
localStorage: '98Gi'
},
remaining: {
accelerator: '0',
cpu: '52',
ram: '104Gi',
localStorage: '196Gi'
},
candidates: [
{
cluster: '1',
name: 'gpustack--intel-xeon-platinum-8259cl-ln-x64-1c-2g',
accelerator: {
onceMaxRequest: '0',
remaining: '0',
capacity: '0'
},
cpu: {
onceMaxRequest: '48',
remaining: '52',
capacity: '52'
},
ram: {
onceMaxRequest: '96Gi',
remaining: '104Gi',
capacity: '104Gi'
},
localStorage: {
onceMaxRequest: '98Gi',
remaining: '196Gi',
capacity: '196Gi'
}
}
]
}
]
}
}
]
};
@@ -47,7 +47,7 @@ export default function useQueryInstanceTypes() {
) => {
const res = await fetchData(params);
const list = (res?.items || []).map((item) => {
const mappedList = (res?.items || []).map((item) => {
const remainingData = isAvailable(item);
const rawMax = item.status?.onceMaxRequest;
@@ -81,6 +81,28 @@ export default function useQueryInstanceTypes() {
};
});
// Keep all acceleratable instance types directly; for the
// non-acceleratable (CPU) ones only keep the entry with the largest
// spec.maxComputeUnitCount.
let maxCpuItem: (typeof mappedList)[number] | undefined;
const list = mappedList.filter((item) => {
if (item.spec.acceleratable) {
return true;
}
if (
!maxCpuItem ||
(item.spec.maxComputeUnitCount || 0) >
(maxCpuItem.spec.maxComputeUnitCount || 0)
) {
maxCpuItem = item;
}
return false;
});
if (maxCpuItem) {
list.push(maxCpuItem);
}
setDataList(list);
return list;
};