Skip to content

Commit 193c1c8

Browse files
committed
feat(FR-2867): add unified memory accelerator UX in Resource Allocation
1 parent 0177ac9 commit 193c1c8

3 files changed

Lines changed: 65 additions & 2 deletions

File tree

react/src/components/SessionFormItems/ResourceAllocationFormItems.test.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,30 @@ import {
88
ResourcePreset,
99
} from '../../hooks/useResourceLimitAndRemaining';
1010
import { Image } from '../ImageEnvironmentSelectFormItems';
11-
import { getAllocatablePresetNames } from './ResourceAllocationFormItems';
11+
import {
12+
getAllocatablePresetNames,
13+
isUnifiedAcceleratorSlot,
14+
} from './ResourceAllocationFormItems';
15+
16+
describe('isUnifiedAcceleratorSlot', () => {
17+
it('returns true for slot names ending with .unified', () => {
18+
expect(isUnifiedAcceleratorSlot('cuda.unified')).toBe(true);
19+
expect(isUnifiedAcceleratorSlot('rocm.unified')).toBe(true);
20+
});
21+
22+
it('returns false for discrete accelerator slot names', () => {
23+
expect(isUnifiedAcceleratorSlot('cuda.shares')).toBe(false);
24+
expect(isUnifiedAcceleratorSlot('cuda.device')).toBe(false);
25+
expect(isUnifiedAcceleratorSlot('cuda.mem')).toBe(false);
26+
expect(isUnifiedAcceleratorSlot('rocm.device')).toBe(false);
27+
});
28+
29+
it('returns false for nullish or empty input', () => {
30+
expect(isUnifiedAcceleratorSlot(undefined)).toBe(false);
31+
expect(isUnifiedAcceleratorSlot(null)).toBe(false);
32+
expect(isUnifiedAcceleratorSlot('')).toBe(false);
33+
});
34+
});
1235

1336
describe('getAllocatablePresetNames', () => {
1437
const presets: Array<ResourcePreset> = [

react/src/components/SessionFormItems/ResourceAllocationFormItems.tsx

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,16 @@ export const isMinOversMaxValue = (min: number, max: number) => {
6262
return min >= max;
6363
};
6464

65+
/**
66+
* Returns true when the given accelerator slot name represents a unified
67+
* memory architecture, where the accelerator memory and the host memory
68+
* share a single physical pool. Identified by a `.unified` suffix on the
69+
* slot name (e.g. `cuda.unified`).
70+
*/
71+
export const isUnifiedAcceleratorSlot = (slotName?: string | null): boolean => {
72+
return !!slotName && _.endsWith(slotName, '.unified');
73+
};
74+
6575
export interface ResourceAllocationFormValue {
6676
resource: {
6777
cpu: number;
@@ -521,6 +531,24 @@ const ResourceAllocationFormItems: React.FC<
521531
}
522532
}, [currentImage, currentAllocationPreset, updateResourceFieldsBasedOnImage]);
523533

534+
// When the selected accelerator slot has a unified memory architecture
535+
// (slot name suffix `.unified`), accelerator memory shares a single
536+
// physical pool with host memory. Mirror the `mem` field value into the
537+
// accelerator field so the displayed allocation stays in lockstep with
538+
// the host memory slider.
539+
const currentAcceleratorTypeForSync = currentResourceValue?.acceleratorType;
540+
const currentMemForSync = currentResourceValue?.mem;
541+
useEffect(() => {
542+
if (!isUnifiedAcceleratorSlot(currentAcceleratorTypeForSync)) {
543+
return;
544+
}
545+
const memInG =
546+
convertToBinaryUnit(currentMemForSync || '0g', 'g')?.number ?? 0;
547+
if (form.getFieldValue(['resource', 'accelerator']) !== memInG) {
548+
form.setFieldValue(['resource', 'accelerator'], memInG);
549+
}
550+
}, [currentAcceleratorTypeForSync, currentMemForSync, form]);
551+
524552
return (
525553
<>
526554
<Form.Item
@@ -921,6 +949,10 @@ const ResourceAllocationFormItems: React.FC<
921949
currentAcceleratorType as keyof typeof resourceSlots
922950
] === 'unique';
923951

952+
const isUnifiedType = isUnifiedAcceleratorSlot(
953+
currentAcceleratorType,
954+
);
955+
924956
const isSingleCluster =
925957
form.getFieldValue('cluster_size') < 2;
926958
const hasQuantumSize = _.isNumber(
@@ -965,9 +997,15 @@ const ResourceAllocationFormItems: React.FC<
965997
/>
966998
),
967999
}}
1000+
extra={
1001+
isUnifiedType
1002+
? t('session.launcher.UnifiedAcceleratorMemoryNote')
1003+
: undefined
1004+
}
9681005
dependencies={[
9691006
['resource', 'acceleratorType'],
9701007
'cluster_size',
1008+
['resource', 'mem'],
9711009
]}
9721010
rules={[
9731011
{
@@ -1139,7 +1177,8 @@ const ResourceAllocationFormItems: React.FC<
11391177
},
11401178
}}
11411179
disabled={
1142-
supportedAcceleratorTypesInRGByImage?.length === 0
1180+
supportedAcceleratorTypesInRGByImage?.length ===
1181+
0 || isUnifiedType
11431182
}
11441183
min={0}
11451184
max={

resources/i18n/en.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2882,6 +2882,7 @@
28822882
"TensorBoardPrepared": "TensorBoard app prepared.",
28832883
"TitleSession": "Session (Backend.AI)",
28842884
"TotalAllocation": "Total Allocation",
2885+
"UnifiedAcceleratorMemoryNote": "Accelerator memory is shared with host memory on this device and cannot be set separately.",
28852886
"UserResourceLimit": "User Resource Limit",
28862887
"UsingBootstrapScriptInfo": "Bootstrap script is included.",
28872888
"Version": "Version",

0 commit comments

Comments
 (0)