Skip to content

Commit dcc9f66

Browse files
committed
Add devicemanager tests for TopologyHint consumption
1 parent cc567af commit dcc9f66

File tree

1 file changed

+216
-0
lines changed

1 file changed

+216
-0
lines changed

pkg/kubelet/cm/devicemanager/topology_hints_test.go

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@ import (
2929
"k8s.io/kubernetes/pkg/kubelet/cm/topologymanager/socketmask"
3030
)
3131

32+
type mockAffinityStore struct {
33+
hint topologymanager.TopologyHint
34+
}
35+
36+
func (m *mockAffinityStore) GetAffinity(podUID string, containerName string) topologymanager.TopologyHint {
37+
return m.hint
38+
}
39+
3240
func makeNUMADevice(id string, numa int) pluginapi.Device {
3341
return pluginapi.Device{
3442
ID: id,
@@ -261,3 +269,211 @@ func TestGetTopologyHints(t *testing.T) {
261269
}
262270
}
263271
}
272+
273+
func TestTopologyAlignedAllocation(t *testing.T) {
274+
tcases := []struct {
275+
description string
276+
resource string
277+
request int
278+
devices []pluginapi.Device
279+
hint topologymanager.TopologyHint
280+
expectedAllocation int
281+
expectedAlignment map[int]int
282+
}{
283+
{
284+
description: "Single Request, no alignment",
285+
resource: "resource",
286+
request: 1,
287+
devices: []pluginapi.Device{
288+
{ID: "Dev1"},
289+
{ID: "Dev2"},
290+
},
291+
hint: topologymanager.TopologyHint{
292+
NUMANodeAffinity: makeSocketMask(0, 1),
293+
Preferred: true,
294+
},
295+
expectedAllocation: 1,
296+
expectedAlignment: map[int]int{},
297+
},
298+
{
299+
description: "Request for 1, partial alignment",
300+
resource: "resource",
301+
request: 1,
302+
devices: []pluginapi.Device{
303+
{ID: "Dev1"},
304+
makeNUMADevice("Dev2", 1),
305+
},
306+
hint: topologymanager.TopologyHint{
307+
NUMANodeAffinity: makeSocketMask(1),
308+
Preferred: true,
309+
},
310+
expectedAllocation: 1,
311+
expectedAlignment: map[int]int{1: 1},
312+
},
313+
{
314+
description: "Single Request, socket 0",
315+
resource: "resource",
316+
request: 1,
317+
devices: []pluginapi.Device{
318+
makeNUMADevice("Dev1", 0),
319+
makeNUMADevice("Dev2", 1),
320+
},
321+
hint: topologymanager.TopologyHint{
322+
NUMANodeAffinity: makeSocketMask(0),
323+
Preferred: true,
324+
},
325+
expectedAllocation: 1,
326+
expectedAlignment: map[int]int{0: 1},
327+
},
328+
{
329+
description: "Single Request, socket 1",
330+
resource: "resource",
331+
request: 1,
332+
devices: []pluginapi.Device{
333+
makeNUMADevice("Dev1", 0),
334+
makeNUMADevice("Dev2", 1),
335+
},
336+
hint: topologymanager.TopologyHint{
337+
NUMANodeAffinity: makeSocketMask(1),
338+
Preferred: true,
339+
},
340+
expectedAllocation: 1,
341+
expectedAlignment: map[int]int{1: 1},
342+
},
343+
{
344+
description: "Request for 2, socket 0",
345+
resource: "resource",
346+
request: 2,
347+
devices: []pluginapi.Device{
348+
makeNUMADevice("Dev1", 0),
349+
makeNUMADevice("Dev2", 1),
350+
makeNUMADevice("Dev3", 0),
351+
makeNUMADevice("Dev4", 1),
352+
},
353+
hint: topologymanager.TopologyHint{
354+
NUMANodeAffinity: makeSocketMask(0),
355+
Preferred: true,
356+
},
357+
expectedAllocation: 2,
358+
expectedAlignment: map[int]int{0: 2},
359+
},
360+
{
361+
description: "Request for 2, socket 1",
362+
resource: "resource",
363+
request: 2,
364+
devices: []pluginapi.Device{
365+
makeNUMADevice("Dev1", 0),
366+
makeNUMADevice("Dev2", 1),
367+
makeNUMADevice("Dev3", 0),
368+
makeNUMADevice("Dev4", 1),
369+
},
370+
hint: topologymanager.TopologyHint{
371+
NUMANodeAffinity: makeSocketMask(1),
372+
Preferred: true,
373+
},
374+
expectedAllocation: 2,
375+
expectedAlignment: map[int]int{1: 2},
376+
},
377+
{
378+
description: "Request for 4, unsatisfiable, prefer socket 0",
379+
resource: "resource",
380+
request: 4,
381+
devices: []pluginapi.Device{
382+
makeNUMADevice("Dev1", 0),
383+
makeNUMADevice("Dev2", 1),
384+
makeNUMADevice("Dev3", 0),
385+
makeNUMADevice("Dev4", 1),
386+
makeNUMADevice("Dev5", 0),
387+
makeNUMADevice("Dev6", 1),
388+
},
389+
hint: topologymanager.TopologyHint{
390+
NUMANodeAffinity: makeSocketMask(0),
391+
Preferred: true,
392+
},
393+
expectedAllocation: 4,
394+
expectedAlignment: map[int]int{0: 3, 1: 1},
395+
},
396+
{
397+
description: "Request for 4, unsatisfiable, prefer socket 1",
398+
resource: "resource",
399+
request: 4,
400+
devices: []pluginapi.Device{
401+
makeNUMADevice("Dev1", 0),
402+
makeNUMADevice("Dev2", 1),
403+
makeNUMADevice("Dev3", 0),
404+
makeNUMADevice("Dev4", 1),
405+
makeNUMADevice("Dev5", 0),
406+
makeNUMADevice("Dev6", 1),
407+
},
408+
hint: topologymanager.TopologyHint{
409+
NUMANodeAffinity: makeSocketMask(1),
410+
Preferred: true,
411+
},
412+
expectedAllocation: 4,
413+
expectedAlignment: map[int]int{0: 1, 1: 3},
414+
},
415+
{
416+
description: "Request for 4, multisocket",
417+
resource: "resource",
418+
request: 4,
419+
devices: []pluginapi.Device{
420+
makeNUMADevice("Dev1", 0),
421+
makeNUMADevice("Dev2", 1),
422+
makeNUMADevice("Dev3", 2),
423+
makeNUMADevice("Dev4", 3),
424+
makeNUMADevice("Dev5", 0),
425+
makeNUMADevice("Dev6", 1),
426+
makeNUMADevice("Dev7", 2),
427+
makeNUMADevice("Dev8", 3),
428+
},
429+
hint: topologymanager.TopologyHint{
430+
NUMANodeAffinity: makeSocketMask(1, 3),
431+
Preferred: true,
432+
},
433+
expectedAllocation: 4,
434+
expectedAlignment: map[int]int{1: 2, 3: 2},
435+
},
436+
}
437+
for _, tc := range tcases {
438+
m := ManagerImpl{
439+
allDevices: make(map[string]map[string]pluginapi.Device),
440+
healthyDevices: make(map[string]sets.String),
441+
allocatedDevices: make(map[string]sets.String),
442+
podDevices: make(podDevices),
443+
sourcesReady: &sourcesReadyStub{},
444+
activePods: func() []*v1.Pod { return []*v1.Pod{} },
445+
topologyAffinityStore: &mockAffinityStore{tc.hint},
446+
}
447+
448+
m.allDevices[tc.resource] = make(map[string]pluginapi.Device)
449+
m.healthyDevices[tc.resource] = sets.NewString()
450+
451+
for _, d := range tc.devices {
452+
m.allDevices[tc.resource][d.ID] = d
453+
m.healthyDevices[tc.resource].Insert(d.ID)
454+
}
455+
456+
allocated, err := m.devicesToAllocate("podUID", "containerName", tc.resource, tc.request, sets.NewString())
457+
if err != nil {
458+
t.Errorf("Unexpected error: %v", err)
459+
continue
460+
}
461+
462+
if len(allocated) != tc.expectedAllocation {
463+
t.Errorf("%v. expected allocation: %v but got: %v", tc.description, tc.expectedAllocation, len(allocated))
464+
}
465+
466+
alignment := make(map[int]int)
467+
if m.deviceHasTopologyAlignment(tc.resource) {
468+
for d := range allocated {
469+
if m.allDevices[tc.resource][d].Topology != nil {
470+
alignment[int(m.allDevices[tc.resource][d].Topology.Nodes[0].ID)]++
471+
}
472+
}
473+
}
474+
475+
if !reflect.DeepEqual(alignment, tc.expectedAlignment) {
476+
t.Errorf("%v. expected alignment: %v but got: %v", tc.description, tc.expectedAlignment, alignment)
477+
}
478+
}
479+
}

0 commit comments

Comments
 (0)