@@ -19,6 +19,8 @@ package plugin
1919import (
2020 "errors"
2121 "fmt"
22+ "sort"
23+ "strings"
2224
2325 "k8s.io/klog/v2"
2426 pluginapi "k8s.io/kubelet/pkg/apis/deviceplugin/v1beta1"
@@ -71,7 +73,7 @@ func (m *mpsOptions) waitForDaemon() error {
7173 return nil
7274}
7375
74- func (m * mpsOptions ) updateReponse (response * pluginapi.ContainerAllocateResponse ) {
76+ func (m * mpsOptions ) updateReponse (response * pluginapi.ContainerAllocateResponse , grantedCount int ) {
7577 if m == nil || ! m .enabled {
7678 return
7779 }
@@ -88,4 +90,54 @@ func (m *mpsOptions) updateReponse(response *pluginapi.ContainerAllocateResponse
8890 HostPath : m .hostRoot .ShmDir (m .resourceName ),
8991 },
9092 )
93+
94+ // The MPS control daemon is configured with per-device defaults at full
95+ // hardware. When a container has been granted every replica the plugin
96+ // advertises on this node, kubelet's accounting guarantees no other pod
97+ // holds any replica concurrently, so it can use the full daemon defaults —
98+ // no client-side env vars are needed.
99+ //
100+ // For any other (non-full-node) grant, inject the 1/replicas per-device
101+ // caps via the client env vars. The MPS server clamps the per-client value
102+ // to no more than the daemon default; since the default is now full, these
103+ // env vars are the effective cap. This preserves the historical behavior
104+ // where every non-full grant got 1/replicas memory and thread percentage,
105+ // regardless of how many replicas were granted.
106+ devices := m .daemon .Devices ()
107+ total := len (devices )
108+ if total == 0 || grantedCount >= total {
109+ return
110+ }
111+
112+ replicasByIndex := make (map [string ]uint64 )
113+ totalMemoryByIndex := make (map [string ]uint64 )
114+ for _ , device := range devices {
115+ replicasByIndex [device .Index ]++
116+ totalMemoryByIndex [device .Index ] = device .TotalMemory
117+ }
118+
119+ // All physical GPUs managed by this daemon share the same replicas value
120+ // (it comes from a single config); pick any.
121+ var replicasPerGPU uint64
122+ for _ , n := range replicasByIndex {
123+ replicasPerGPU = n
124+ break
125+ }
126+ if replicasPerGPU == 0 {
127+ return
128+ }
129+
130+ response .Envs ["CUDA_MPS_ACTIVE_THREAD_PERCENTAGE" ] = fmt .Sprintf ("%d" , 100 / replicasPerGPU )
131+
132+ limits := make ([]string , 0 , len (totalMemoryByIndex ))
133+ for index , totalMemory := range totalMemoryByIndex {
134+ if totalMemory == 0 {
135+ continue
136+ }
137+ limits = append (limits , fmt .Sprintf ("%s=%dM" , index , totalMemory / replicasPerGPU / 1024 / 1024 ))
138+ }
139+ if len (limits ) > 0 {
140+ sort .Strings (limits )
141+ response .Envs ["CUDA_MPS_PINNED_DEVICE_MEM_LIMIT" ] = strings .Join (limits , "," )
142+ }
91143}
0 commit comments