Skip to content

Commit cc35f9b

Browse files
committed
DRA: Update quota calculations for Prioritized Alternatives in Device Requests
1 parent a716095 commit cc35f9b

File tree

2 files changed

+105
-0
lines changed

2 files changed

+105
-0
lines changed

pkg/quota/v1/evaluator/core/resource_claims.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,38 @@ func (p *claimEvaluator) Usage(item runtime.Object) (corev1.ResourceList, error)
114114
// charge for claim
115115
result[ClaimObjectCountName] = *(resource.NewQuantity(1, resource.DecimalSI))
116116
for _, request := range claim.Spec.Devices.Requests {
117+
if len(request.FirstAvailable) > 0 {
118+
// If there are subrequests, we want to use the worst case per device class
119+
// to quota. So for each device class, we need to find the max number of
120+
// devices that might be allocated.
121+
maxQuantityByDeviceClassClaim := make(map[corev1.ResourceName]resource.Quantity)
122+
for _, subrequest := range request.FirstAvailable {
123+
deviceClassClaim := V1ResourceByDeviceClass(subrequest.DeviceClassName)
124+
var numDevices int64
125+
switch subrequest.AllocationMode {
126+
case resourceapi.DeviceAllocationModeExactCount:
127+
numDevices = subrequest.Count
128+
case resourceapi.DeviceAllocationModeAll:
129+
// Worst case...
130+
numDevices = resourceapi.AllocationResultsMaxSize
131+
default:
132+
// Could happen after a downgrade. Unknown modes
133+
// don't count towards the quota and users shouldn't
134+
// expect that when downgrading.
135+
}
136+
137+
q := resource.NewQuantity(numDevices, resource.DecimalSI)
138+
if q.Cmp(maxQuantityByDeviceClassClaim[deviceClassClaim]) > 0 {
139+
maxQuantityByDeviceClassClaim[deviceClassClaim] = *q
140+
}
141+
}
142+
for deviceClassClaim, q := range maxQuantityByDeviceClassClaim {
143+
quantity := result[deviceClassClaim]
144+
quantity.Add(q)
145+
result[deviceClassClaim] = quantity
146+
}
147+
continue
148+
}
117149
deviceClassClaim := V1ResourceByDeviceClass(request.DeviceClassName)
118150
var numDevices int64
119151
switch request.AllocationMode {

pkg/quota/v1/evaluator/core/resource_claims_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,25 @@ func testResourceClaim(name string, namespace string, spec api.ResourceClaimSpec
3939

4040
func TestResourceClaimEvaluatorUsage(t *testing.T) {
4141
classGpu := "gpu"
42+
classTpu := "tpu"
4243
validClaim := testResourceClaim("foo", "ns", api.ResourceClaimSpec{Devices: api.DeviceClaim{Requests: []api.DeviceRequest{{Name: "req-0", DeviceClassName: classGpu, AllocationMode: api.DeviceAllocationModeExactCount, Count: 1}}}})
44+
validClaimWithPrioritizedList := testResourceClaim("foo", "ns", api.ResourceClaimSpec{
45+
Devices: api.DeviceClaim{
46+
Requests: []api.DeviceRequest{
47+
{
48+
Name: "req-0",
49+
FirstAvailable: []api.DeviceSubRequest{
50+
{
51+
Name: "subreq-0",
52+
DeviceClassName: classGpu,
53+
AllocationMode: api.DeviceAllocationModeExactCount,
54+
Count: 1,
55+
},
56+
},
57+
},
58+
},
59+
},
60+
})
4361

4462
evaluator := NewResourceClaimEvaluator(nil)
4563
testCases := map[string]struct {
@@ -112,6 +130,61 @@ func TestResourceClaimEvaluatorUsage(t *testing.T) {
112130
"gpu.deviceclass.resource.k8s.io/devices": resource.MustParse("1"),
113131
},
114132
},
133+
"prioritized-list": {
134+
claim: validClaimWithPrioritizedList,
135+
usage: corev1.ResourceList{
136+
"count/resourceclaims.resource.k8s.io": resource.MustParse("1"),
137+
"gpu.deviceclass.resource.k8s.io/devices": resource.MustParse("1"),
138+
},
139+
},
140+
"prioritized-list-multiple-subrequests": {
141+
claim: func() *api.ResourceClaim {
142+
claim := validClaimWithPrioritizedList.DeepCopy()
143+
claim.Spec.Devices.Requests[0].FirstAvailable[0].Count = 2
144+
claim.Spec.Devices.Requests[0].FirstAvailable = append(claim.Spec.Devices.Requests[0].FirstAvailable, api.DeviceSubRequest{
145+
Name: "subreq-1",
146+
DeviceClassName: classGpu,
147+
AllocationMode: api.DeviceAllocationModeExactCount,
148+
Count: 1,
149+
})
150+
return claim
151+
}(),
152+
usage: corev1.ResourceList{
153+
"count/resourceclaims.resource.k8s.io": resource.MustParse("1"),
154+
"gpu.deviceclass.resource.k8s.io/devices": resource.MustParse("2"),
155+
},
156+
},
157+
"prioritized-list-multiple-subrequests-allocation-mode-all": {
158+
claim: func() *api.ResourceClaim {
159+
claim := validClaimWithPrioritizedList.DeepCopy()
160+
claim.Spec.Devices.Requests[0].FirstAvailable = append(claim.Spec.Devices.Requests[0].FirstAvailable, api.DeviceSubRequest{
161+
Name: "subreq-1",
162+
DeviceClassName: classGpu,
163+
AllocationMode: api.DeviceAllocationModeAll,
164+
})
165+
return claim
166+
}(),
167+
usage: corev1.ResourceList{
168+
"count/resourceclaims.resource.k8s.io": resource.MustParse("1"),
169+
"gpu.deviceclass.resource.k8s.io/devices": resource.MustParse("32"),
170+
},
171+
},
172+
"prioritized-list-multiple-subrequests-different-device-classes": {
173+
claim: func() *api.ResourceClaim {
174+
claim := validClaimWithPrioritizedList.DeepCopy()
175+
claim.Spec.Devices.Requests[0].FirstAvailable = append(claim.Spec.Devices.Requests[0].FirstAvailable, api.DeviceSubRequest{
176+
Name: "subreq-1",
177+
DeviceClassName: classTpu,
178+
AllocationMode: api.DeviceAllocationModeAll,
179+
})
180+
return claim
181+
}(),
182+
usage: corev1.ResourceList{
183+
"count/resourceclaims.resource.k8s.io": resource.MustParse("1"),
184+
"gpu.deviceclass.resource.k8s.io/devices": resource.MustParse("1"),
185+
"tpu.deviceclass.resource.k8s.io/devices": resource.MustParse("32"),
186+
},
187+
},
115188
}
116189
for testName, testCase := range testCases {
117190
t.Run(testName, func(t *testing.T) {

0 commit comments

Comments
 (0)