Skip to content

Commit d1b37de

Browse files
jessicaochenclaude
andauthored
fix(snapshot-agent): filter out 0-VRAM daemon processes during PID di… (#148)
* fix(snapshot-agent): filter out 0-VRAM daemon processes during PID discovery to prevent cuda-checkpoint initialization errors Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix lint: avoid uint64->int64 conversion flagged by gosec G115 Compare UsedGpuMemory against the NVML_VALUE_NOT_AVAILABLE sentinel in uint64 space instead of casting. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * chart(snapshot-agent): tolerate the timeslice.io/shared taint by default The snapshot-agent must run on the shared GPU nodes that the timeslice stack itself taints, so the chart's DaemonSet should tolerate the taint out of the box. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent 70ce9ae commit d1b37de

3 files changed

Lines changed: 54 additions & 4 deletions

File tree

deploy/snapshot-agent/values.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ tolerations:
2525
operator: "Equal"
2626
value: "present"
2727
effect: "NoSchedule"
28+
- key: "timeslice.io/shared"
29+
operator: "Exists"
30+
effect: "NoSchedule"
2831

2932
affinity: {}
3033

pkg/snapshot-agent/utils/pod-utils.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ var (
4141
IsPIDInPodCgroupFunc = isPIDInPodCgroup
4242
)
4343

44+
// nvmlValueNotAvailable is nvml.VALUE_NOT_AVAILABLE (-1) as it appears in
45+
// unsigned fields such as ProcessInfo.UsedGpuMemory.
46+
const nvmlValueNotAvailable = ^uint64(0)
47+
4448
type DeviceInterface interface {
4549
GetComputeRunningProcesses() ([]nvml.ProcessInfo, nvml.Return)
4650
GetGraphicsRunningProcesses() ([]nvml.ProcessInfo, nvml.Return)
@@ -150,6 +154,11 @@ func getPodPIDsInternal(ctx context.Context, podName, namespace string) ([]int,
150154
}
151155

152156
for _, proc := range procs {
157+
// Skip non-computing parent/daemon processes that hold 0 VRAM; they have no
158+
// active CUDA context, so cuda-checkpoint fails to lock them.
159+
if proc.UsedGpuMemory == 0 || proc.UsedGpuMemory == nvmlValueNotAvailable {
160+
continue
161+
}
153162
pid := int(proc.Pid)
154163
if seenPIDs[pid] {
155164
continue
@@ -170,6 +179,11 @@ func getPodPIDsInternal(ctx context.Context, podName, namespace string) ([]int,
170179
graphicsProcs, ret := device.GetGraphicsRunningProcesses()
171180
if ret == nvml.SUCCESS {
172181
for _, proc := range graphicsProcs {
182+
// Skip non-computing parent/daemon processes that hold 0 VRAM; they have no
183+
// active CUDA context, so cuda-checkpoint fails to lock them.
184+
if proc.UsedGpuMemory == 0 || proc.UsedGpuMemory == nvmlValueNotAvailable {
185+
continue
186+
}
173187
pid := int(proc.Pid)
174188
if seenPIDs[pid] {
175189
continue

pkg/snapshot-agent/utils/pod-utils_test.go

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@ func TestGetPodPIDs(t *testing.T) {
7777
snapshotutils.NvmlInit = func() nvml.Return { return nvml.SUCCESS }
7878
snapshotutils.NvmlDeviceGetCount = func() (int, nvml.Return) { return 1, nvml.SUCCESS }
7979
device := &mockDevice{
80-
computeProcs: []nvml.ProcessInfo{{Pid: 100}, {Pid: 200}},
81-
graphicsProcs: []nvml.ProcessInfo{{Pid: 200}, {Pid: 300}},
80+
computeProcs: []nvml.ProcessInfo{{Pid: 100, UsedGpuMemory: 1024}, {Pid: 200, UsedGpuMemory: 1024}},
81+
graphicsProcs: []nvml.ProcessInfo{{Pid: 200, UsedGpuMemory: 1024}, {Pid: 300, UsedGpuMemory: 1024}},
8282
}
8383
snapshotutils.NvmlDeviceGetHandleByIndex = func(index int) (snapshotutils.DeviceInterface, nvml.Return) {
8484
return device, nvml.SUCCESS
@@ -90,6 +90,39 @@ func TestGetPodPIDs(t *testing.T) {
9090
expectedPIDs: []int{100, 300},
9191
expectError: false,
9292
},
93+
{
94+
name: "Ignore Zero VRAM Processes",
95+
podName: "test-pod",
96+
namespace: "test-ns",
97+
setupMocks: func() {
98+
podUID := "test-uid"
99+
pod := &corev1.Pod{
100+
ObjectMeta: metav1.ObjectMeta{
101+
Name: "test-pod",
102+
Namespace: "test-ns",
103+
UID: types.UID(podUID),
104+
},
105+
}
106+
snapshotutils.GetK8sClient = func() (kubernetes.Interface, error) {
107+
return fake.NewSimpleClientset(pod), nil
108+
}
109+
snapshotutils.NvmlInit = func() nvml.Return { return nvml.SUCCESS }
110+
snapshotutils.NvmlDeviceGetCount = func() (int, nvml.Return) { return 1, nvml.SUCCESS }
111+
device := &mockDevice{
112+
computeProcs: []nvml.ProcessInfo{{Pid: 100, UsedGpuMemory: 1024}, {Pid: 200, UsedGpuMemory: 0}},
113+
// ^uint64(0) is NVML_VALUE_NOT_AVAILABLE (-1) as reported in the uint64 field.
114+
graphicsProcs: []nvml.ProcessInfo{{Pid: 300, UsedGpuMemory: ^uint64(0)}},
115+
}
116+
snapshotutils.NvmlDeviceGetHandleByIndex = func(index int) (snapshotutils.DeviceInterface, nvml.Return) {
117+
return device, nvml.SUCCESS
118+
}
119+
snapshotutils.IsPIDInPodCgroupFunc = func(pid int, uid string) (bool, error) {
120+
return true, nil
121+
}
122+
},
123+
expectedPIDs: []int{100},
124+
expectError: false,
125+
},
93126
{
94127
name: "GetPodUID Failure",
95128
podName: "pod",
@@ -149,7 +182,7 @@ func TestGetPodPIDs(t *testing.T) {
149182
snapshotutils.NvmlInit = func() nvml.Return { return nvml.SUCCESS }
150183
snapshotutils.NvmlDeviceGetCount = func() (int, nvml.Return) { return 1, nvml.SUCCESS }
151184
device := &mockDevice{
152-
computeProcs: []nvml.ProcessInfo{{Pid: 400}, {Pid: 500}},
185+
computeProcs: []nvml.ProcessInfo{{Pid: 400, UsedGpuMemory: 1024}, {Pid: 500, UsedGpuMemory: 1024}},
153186
}
154187
snapshotutils.NvmlDeviceGetHandleByIndex = func(index int) (snapshotutils.DeviceInterface, nvml.Return) {
155188
return device, nvml.SUCCESS
@@ -180,7 +213,7 @@ func TestGetPodPIDs(t *testing.T) {
180213
snapshotutils.NvmlInit = func() nvml.Return { return nvml.SUCCESS }
181214
snapshotutils.NvmlDeviceGetCount = func() (int, nvml.Return) { return 1, nvml.SUCCESS }
182215
device := &mockDevice{
183-
computeProcs: []nvml.ProcessInfo{{Pid: 600}},
216+
computeProcs: []nvml.ProcessInfo{{Pid: 600, UsedGpuMemory: 1024}},
184217
}
185218
snapshotutils.NvmlDeviceGetHandleByIndex = func(index int) (snapshotutils.DeviceInterface, nvml.Return) {
186219
return device, nvml.SUCCESS

0 commit comments

Comments
 (0)