diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000000..7a51262abc --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,14 @@ +{ + "permissions": { + "allow": [ + "Bash(curl -s \"https://api.github.com/repos/Project-HAMi/HAMi/issues/2712\")", + "Bash(curl -s \"https://api.github.com/search/issues?q=repo:Project-HAMi/HAMi+in:title+AWSNeuronAssignedIndex\")", + "Bash(curl -s \"https://api.github.com/repos/Project-HAMi/HAMi/issues/2463\")", + "Bash(curl -s \"https://api.github.com/repos/Project-HAMi/HAMi/issues/2738/comments\")", + "Bash(curl -s \"https://api.github.com/repos/Project-HAMi/HAMi/issues/2738\")" + ], + "additionalDirectories": [ + "/home/toqeer513/Opensource/Lfx" + ] + } +} diff --git a/.gitignore b/.gitignore index 1de20116f8..b1791d1892 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ vgpuvalidator _output/ coverage.out .DS_Store +CLAUDE.md diff --git a/docs/develop/amd-vgpu.md b/docs/develop/amd-vgpu.md index 76b4723afc..eb746e69f2 100644 --- a/docs/develop/amd-vgpu.md +++ b/docs/develop/amd-vgpu.md @@ -106,7 +106,7 @@ HSA_CU_MASK=0:0-75;1:0-75 Each `CU_list` uses HSA's CU ID-list grammar, for example `0-3,8,10-12`. Exclusivity of CU ranges across pods on a device is enforced under the AMD -node lock (`AMDDevices.LockNode` and `ReleaseNodeLock` which are unimplemented now). +node lock (`AMDDevices.LockNode` and `ReleaseNodeLock`). ## 5. Resource model and core_limit -> CU mask diff --git a/pkg/device/awsneuron/device.go b/pkg/device/awsneuron/device.go index 27c3023070..9d1cd3dafd 100644 --- a/pkg/device/awsneuron/device.go +++ b/pkg/device/awsneuron/device.go @@ -132,6 +132,9 @@ func (dev *AWSNeuronDevices) PatchAnnotations(pod *corev1.Pod, annoinput *map[st devlist, ok := pd[AWSNeuronDevice] if ok && len(devlist) > 0 { (*annoinput)[device.SupportDevices[AWSNeuronDevice]] = device.EncodePodSingleDevice(devlist) + // value is intentionally declared outside the loop and accumulates across + // containers (never reset per-container), so AWSNeuronAssignedIndex ends up + // holding every container's assigned indices, not just the last container's. value := "" for ctridx, dp := range devlist { if len(dp) > 0 { diff --git a/pkg/device/awsneuron/device_test.go b/pkg/device/awsneuron/device_test.go index 149fb25e73..632839348f 100644 --- a/pkg/device/awsneuron/device_test.go +++ b/pkg/device/awsneuron/device_test.go @@ -266,6 +266,72 @@ func Test_PatchAnnotations(t *testing.T) { AWSNeuronAssignedNode: "", }, }, + { + // Regression test for a pod with two containers, each requesting its own + // AWS Neuron device: AWSNeuronAssignedIndex must carry both containers' + // indices ("0,1"), not just the last container processed. + name: "multi-container neuron devices", + args: struct { + annoinput *map[string]string + pod corev1.Pod + pd device.PodDevices + }{ + annoinput: &map[string]string{}, + pod: corev1.Pod{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + "aws.amazon.com/neuron": resource.MustParse("1"), + }, + }, + }, + { + Resources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + "aws.amazon.com/neuron": resource.MustParse("1"), + }, + }, + }, + }, + }, + }, + pd: device.PodDevices{ + AWSNeuronDevice: device.PodSingleDevice{ + device.ContainerDevices{ + { + Idx: 0, + UUID: "test1", + Type: AWSNeuronDevice, + Usedmem: int32(0), + Usedcores: int32(3), + CustomInfo: map[string]any{ + AWSUsageInfo: 3, + }, + }, + }, + device.ContainerDevices{ + { + Idx: 1, + UUID: "test2", + Type: AWSNeuronDevice, + Usedmem: int32(0), + Usedcores: int32(3), + CustomInfo: map[string]any{ + AWSUsageInfo: 3, + }, + }, + }, + }, + }, + }, + want: map[string]string{ + device.SupportDevices[AWSNeuronDevice]: "test1,AWSNeuron,0,3:;test2,AWSNeuron,0,3:;", + AWSNeuronAssignedIndex: "0,1", + AWSNeuronAssignedNode: "", + }, + }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) {