Skip to content

Commit a6eb328

Browse files
committed
add e2e tests for prefer-closest-numa-nodes TopologyManagerPolicyOption suboptimal allocation
Signed-off-by: PiotrProkop <[email protected]>
1 parent 9bc3a2f commit a6eb328

File tree

1 file changed

+92
-5
lines changed

1 file changed

+92
-5
lines changed

test/e2e_node/topology_manager_test.go

Lines changed: 92 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,11 @@ func getMinRemoteDistanceForNode(nodeToDistances map[int][]int) int {
123123
}
124124

125125
func detectNUMADistances(numaNodes int) map[int][]int {
126+
ginkgo.GinkgoHelper()
127+
126128
nodeToDistances := make(map[int][]int)
127129
for i := 0; i < numaNodes; i++ {
128-
outData, err := exec.Command("/bin/sh", "-c", fmt.Sprintf("cat /sys/devices/system/node/node%d/distance", i)).Output()
130+
outData, err := os.ReadFile(fmt.Sprintf("/sys/devices/system/node/node%d/distance", i))
129131
framework.ExpectNoError(err)
130132

131133
nodeToDistances[i] = make([]int, 0, numaNodes)
@@ -905,8 +907,12 @@ func runTopologyManagerNodeAlignmentSuiteTests(ctx context.Context, f *framework
905907
}
906908

907909
func runPreferClosestNUMATestSuite(ctx context.Context, f *framework.Framework, numaNodes int, distances map[int][]int) {
908-
ginkgo.By("Admit two guaranteed pods. Both consist of 1 containers, each pod asks for cpus from 2 NUMA nodes. CPUs should be assigned from closest NUMA")
910+
runPreferClosestNUMAOptimalAllocationTest(ctx, f, numaNodes, distances)
911+
runPreferClosestNUMASubOptimalAllocationTest(ctx, f, numaNodes, distances)
912+
}
909913

914+
func runPreferClosestNUMAOptimalAllocationTest(ctx context.Context, f *framework.Framework, numaNodes int, distances map[int][]int) {
915+
ginkgo.By("Admit two guaranteed pods. Both consist of 1 containers, each pod asks for cpus from 2 NUMA nodes. CPUs should be assigned from closest NUMA")
910916
podMap := make(map[string]*v1.Pod)
911917
for podID := 0; podID < 2; podID++ {
912918
numCores := 0
@@ -916,7 +922,7 @@ func runPreferClosestNUMATestSuite(ctx context.Context, f *framework.Framework,
916922
// subtract one to accommodate reservedCPUs. It'll only work if more than 2 cpus per NUMA node.
917923
cpusPerNUMA := len(cpus)
918924
if cpusPerNUMA < 3 {
919-
e2eskipper.Skipf("Less than 2 cpus per NUMA node on this system. Skipping test.")
925+
e2eskipper.Skipf("Less than 3 cpus per NUMA node on this system. Skipping test.")
920926
}
921927
numCores += cpusPerNUMA - 1
922928
}
@@ -936,6 +942,89 @@ func runPreferClosestNUMATestSuite(ctx context.Context, f *framework.Framework,
936942
podMap[podName] = pod
937943
}
938944

945+
valiidatePreferClosestNUMAOptimalAllocation(ctx, f, podMap, numaNodes, distances)
946+
947+
deletePodsAsync(ctx, f, podMap)
948+
}
949+
950+
func runPreferClosestNUMASubOptimalAllocationTest(ctx context.Context, f *framework.Framework, numaNodes int, distances map[int][]int) {
951+
ginkgo.By("Admit two guaranteed pods. Both consist of 1 containers, each pod asks for cpus from 2 NUMA nodes. CPUs should be assigned from closest NUMA")
952+
cntName := "ps-container-0"
953+
954+
// expect same amount of cpus per NUMA
955+
cpusPerNUMA, err := getCPUsPerNUMANode(0)
956+
framework.ExpectNoError(err)
957+
if len(cpusPerNUMA) < 5 {
958+
e2eskipper.Skipf("Less than 5 cpus per NUMA node on this system. Skipping test.")
959+
}
960+
podMap := make(map[string]*v1.Pod)
961+
for podID := 0; podID < 2; podID++ {
962+
// asks for all but one cpus from one less than half NUMA nodes, and half from the other
963+
// plus add one less than half NUMA nodes, to accommodate for reserved cpus
964+
numCores := ((numaNodes/2)-1)*(len(cpusPerNUMA)-1) + (len(cpusPerNUMA) / 2) + (numaNodes/2 - 1)
965+
framework.ExpectNoError(err)
966+
967+
coresReq := fmt.Sprintf("%dm", numCores*1000)
968+
ctnAttrs := []tmCtnAttribute{
969+
{
970+
ctnName: "ps-container-0",
971+
cpuRequest: coresReq,
972+
cpuLimit: coresReq,
973+
},
974+
}
975+
podName := fmt.Sprintf("gu-pod-%d", podID)
976+
framework.Logf("creating pod %s", podName)
977+
pod := makeTopologyManagerTestPod(podName, ctnAttrs, nil)
978+
pod = e2epod.NewPodClient(f).CreateSync(ctx, pod)
979+
framework.Logf("created pod %s", podName)
980+
podMap[podName] = pod
981+
}
982+
983+
valiidatePreferClosestNUMAOptimalAllocation(ctx, f, podMap, numaNodes, distances)
984+
985+
ginkgo.By("Admit one guaranteed pod. Asks for cpus from 2 NUMA nodes. CPUs should be assigned from non closest NUMA")
986+
// ask for remaining cpus, it should only fit on sub-optimal NUMA placement.
987+
coresReq := fmt.Sprintf("%dm", 2*(len(cpusPerNUMA)/2)*1000)
988+
ctnAttrs := []tmCtnAttribute{
989+
{
990+
ctnName: cntName,
991+
cpuRequest: coresReq,
992+
cpuLimit: coresReq,
993+
},
994+
}
995+
podName := "gu-pod-2"
996+
framework.Logf("creating pod %s attrs %v", podName, nil)
997+
pod := makeTopologyManagerTestPod(podName, ctnAttrs, nil)
998+
pod = e2epod.NewPodClient(f).CreateSync(ctx, pod)
999+
framework.Logf("created pod %s", podName)
1000+
1001+
ginkgo.By(fmt.Sprintf("validating the container %s on Gu pod %s", cntName, pod.Name))
1002+
1003+
logs, err := e2epod.GetPodLogs(ctx, f.ClientSet, f.Namespace.Name, pod.Name, cntName)
1004+
framework.ExpectNoError(err, "expected log not found in container [%s] of pod [%s]", cntName, pod.Name)
1005+
1006+
framework.Logf("got pod logs: %v", logs)
1007+
podEnv, err := makeEnvMap(logs)
1008+
framework.ExpectNoError(err, "expected log not found in container [%s] of pod [%s]", cntName, pod.Name)
1009+
1010+
CPUToNUMANode, err := getCPUToNUMANodeMapFromEnv(f, pod, &pod.Spec.Containers[0], podEnv, numaNodes)
1011+
framework.ExpectNoError(err, "expected log not found in container [%s] of pod [%s]", cntName, pod.Name)
1012+
1013+
numaUsed := sets.New[int]()
1014+
for _, numa := range CPUToNUMANode {
1015+
numaUsed.Insert(numa)
1016+
}
1017+
1018+
numaList := numaUsed.UnsortedList()
1019+
gomega.Expect(numaList).To(gomega.HaveLen(2))
1020+
1021+
distance := getMinRemoteDistanceForNode(distances)
1022+
gomega.Expect(distance).NotTo(gomega.Equal(distances[numaList[0]][numaList[1]]))
1023+
1024+
deletePodsAsync(ctx, f, podMap)
1025+
}
1026+
1027+
func valiidatePreferClosestNUMAOptimalAllocation(ctx context.Context, f *framework.Framework, podMap map[string]*v1.Pod, numaNodes int, distances map[int][]int) {
9391028
for _, pod := range podMap {
9401029
for _, cnt := range pod.Spec.Containers {
9411030
ginkgo.By(fmt.Sprintf("validating the container %s on Gu pod %s", cnt.Name, pod.Name))
@@ -962,8 +1051,6 @@ func runPreferClosestNUMATestSuite(ctx context.Context, f *framework.Framework,
9621051
gomega.Expect(distance).To(gomega.Equal(distances[numaList[0]][numaList[1]]))
9631052
}
9641053
}
965-
966-
deletePodsAsync(ctx, f, podMap)
9671054
}
9681055

9691056
func runTopologyManagerTests(f *framework.Framework, topologyOptions map[string]string) {

0 commit comments

Comments
 (0)