diff mbox series

[1/1] support/testing: add numactl runtime test

Message ID 20240129203635.183112-1-ju.o@free.fr
State Accepted
Headers show
Series [1/1] support/testing: add numactl runtime test | expand

Commit Message

Julien Olivain Jan. 29, 2024, 8:36 p.m. UTC
Signed-off-by: Julien Olivain <ju.o@free.fr>
---
 DEVELOPERS                                    |   2 +
 support/testing/tests/package/test_numactl.py | 142 ++++++++++++++++++
 .../test_numactl/linux-numactl.fragment       |   1 +
 3 files changed, 145 insertions(+)
 create mode 100644 support/testing/tests/package/test_numactl.py
 create mode 100644 support/testing/tests/package/test_numactl/linux-numactl.fragment

Comments

Peter Korsgaard Feb. 6, 2024, 9:10 p.m. UTC | #1
>>>>> "Julien" == Julien Olivain <ju.o@free.fr> writes:

 > Signed-off-by: Julien Olivain <ju.o@free.fr>

Committed, thanks.
diff mbox series

Patch

diff --git a/DEVELOPERS b/DEVELOPERS
index 9528837dd0..9dd73b7a0d 100644
--- a/DEVELOPERS
+++ b/DEVELOPERS
@@ -1800,6 +1800,8 @@  F:	support/testing/tests/package/test_netcat.py
 F:	support/testing/tests/package/test_nftables.py
 F:	support/testing/tests/package/test_nftables/
 F:	support/testing/tests/package/test_ngrep.py
+F:	support/testing/tests/package/test_numactl.py
+F:	support/testing/tests/package/test_numactl/
 F:	support/testing/tests/package/test_octave.py
 F:	support/testing/tests/package/test_ola.py
 F:	support/testing/tests/package/test_ola/
diff --git a/support/testing/tests/package/test_numactl.py b/support/testing/tests/package/test_numactl.py
new file mode 100644
index 0000000000..2ef9eb3635
--- /dev/null
+++ b/support/testing/tests/package/test_numactl.py
@@ -0,0 +1,142 @@ 
+import os
+import re
+
+import infra.basetest
+
+
+class TestNumaCtl(infra.basetest.BRTest):
+    # A specific configuration is needed for testing numactl:
+    # - This test uses a x86_64 config, which has mature NUMA support.
+    # - A kernel need to compiled with a NUMA support.
+    kernel_fragment = \
+        infra.filepath("tests/package/test_numactl/linux-numactl.fragment")
+    config = \
+        f"""
+        BR2_x86_64=y
+        BR2_x86_corei7=y
+        BR2_TOOLCHAIN_EXTERNAL=y
+        BR2_LINUX_KERNEL=y
+        BR2_LINUX_KERNEL_CUSTOM_VERSION=y
+        BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.1.75"
+        BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
+        BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="board/qemu/x86_64/linux.config"
+        BR2_LINUX_KERNEL_CONFIG_FRAGMENT_FILES="{kernel_fragment}"
+        BR2_LINUX_KERNEL_NEEDS_HOST_OPENSSL=y
+        BR2_LINUX_KERNEL_NEEDS_HOST_LIBELF=y
+        BR2_PACKAGE_NUMACTL=y
+        BR2_TARGET_ROOTFS_CPIO=y
+        BR2_TARGET_ROOTFS_CPIO_GZIP=y
+        # BR2_TARGET_ROOTFS_TAR is not set
+        """
+
+    def check_numactl_preferred(self):
+        # Show the default NUMA policy settings. We check we have the
+        # 4 physical cpus on 2 nodes we configured the emulator
+        # command line.
+        out, ret = self.emulator.run("numactl --show")
+        self.assertEqual(ret, 0)
+        checks = [
+            "policy: default",
+            "preferred node: current",
+            "physcpubind: 0 1 2 3 ",
+            "nodebind: 0 1 ",
+            "membind: 0 1 "
+        ]
+        for pattern in checks:
+            self.assertIn(pattern, out)
+
+        # Check the preferred policy on different nodes. This command
+        # is taken from the numactl man page.
+        for pref_node in range(2):
+            cmd = f"numactl --preferred={pref_node} numactl --show"
+            out, ret = self.emulator.run(cmd)
+            self.assertEqual(ret, 0)
+            checks = [
+                "policy: preferred",
+                f"preferred node: {pref_node}"
+            ]
+            for pattern in checks:
+                self.assertIn(pattern, out)
+
+    def get_numa_node_free_mem(self):
+        out, ret = self.emulator.run("numactl --hardware")
+        self.assertEqual(ret, 0)
+        free_mem = {}
+        p = re.compile("^node ([0-9]+) free: ([0-9]+) MB")
+        for line in out:
+            m = p.match(line)
+            if m:
+                node = int(m.group(1))
+                mem = int(m.group(2))
+                free_mem[node] = mem
+        return free_mem
+
+    def check_numactl_membind(self):
+        # We get the current amount of free memory on each node, for
+        # later comparison.
+        initial_node_free_mem = self.get_numa_node_free_mem()
+
+        # We allocate a shared memory file with a restriction to be in
+        # node 1 memory only.
+        shm_file = "/dev/shm/file"
+        file_size = 100
+        cmd = f"numactl --membind=1 dd if=/dev/zero of={shm_file} bs=1M count={file_size}"
+        self.assertRunOk(cmd)
+
+        # We collect again the amount of free memory per node.
+        node_free_mem = self.get_numa_node_free_mem()
+
+        # Since we allocated 100M on node 1 only, we check the free
+        # space on node 0 did not significantly changed and on node 1
+        # approximately reduced of the file size.
+        diff = initial_node_free_mem[0] - node_free_mem[0]
+        self.assertAlmostEqual(diff, 0, delta=10)
+        diff = initial_node_free_mem[1] - node_free_mem[1]
+        self.assertAlmostEqual(diff, file_size, delta=10)
+
+        # Remove the file, to free the memory.
+        self.assertRunOk(f"rm -f {shm_file}")
+
+        # We allocate again a file in shared memory, but this time in
+        # two chunks. Each chunk is requested to be allocated in two
+        # different nodes. This example is taken from the numactl man
+        # page.
+        chunk_size = file_size // 2
+        cmd = "numactl --membind=0 "
+        cmd += f"dd if=/dev/zero of={shm_file} bs=1M count={chunk_size}"
+        self.assertRunOk(cmd)
+        cmd = "numactl --membind=1 "
+        cmd += f"dd if=/dev/zero of={shm_file} bs=1M count={chunk_size} seek={chunk_size}"
+        self.assertRunOk(cmd)
+
+        # We collect again the amount of free memory.
+        node_free_mem = self.get_numa_node_free_mem()
+
+        # We check the free memory space approximately reduced of each
+        # chunk size.
+        for node in range(2):
+            free_mem_diff = initial_node_free_mem[node] - node_free_mem[node]
+            self.assertAlmostEqual(free_mem_diff, chunk_size, delta=5)
+
+    def test_run(self):
+        img = os.path.join(self.builddir, "images", "rootfs.cpio.gz")
+        kern = os.path.join(self.builddir, "images", "bzImage")
+        # We start the Qemu emulator with 4 processors on 2 NUMA nodes.
+        self.emulator.boot(arch="x86_64",
+                           kernel=kern,
+                           kernel_cmdline=["console=ttyS0"],
+                           options=["-cpu", "Nehalem", "-m", "512M",
+                                    "-smp", "cpus=4,sockets=2,cores=2,maxcpus=4",
+                                    "-object", "memory-backend-ram,size=256M,id=m0",
+                                    "-object", "memory-backend-ram,size=256M,id=m1",
+                                    "-numa", "node,cpus=0-1,nodeid=0,memdev=m0",
+                                    "-numa", "node,cpus=2-3,nodeid=1,memdev=m1",
+                                    "-initrd", img])
+        self.emulator.login()
+
+        # Check a simple numactl invication:
+        # show the NUMA hardware inventory.
+        self.assertRunOk("numactl --hardware")
+
+        self.check_numactl_preferred()
+        self.check_numactl_membind()
diff --git a/support/testing/tests/package/test_numactl/linux-numactl.fragment b/support/testing/tests/package/test_numactl/linux-numactl.fragment
new file mode 100644
index 0000000000..e480f0c042
--- /dev/null
+++ b/support/testing/tests/package/test_numactl/linux-numactl.fragment
@@ -0,0 +1 @@ 
+CONFIG_NUMA=y