test_numactl.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. import os
  2. import re
  3. import infra.basetest
  4. class TestNumaCtl(infra.basetest.BRTest):
  5. # A specific configuration is needed for testing numactl:
  6. # - This test uses a x86_64 config, which has mature NUMA support.
  7. # - A kernel need to compiled with a NUMA support.
  8. kernel_fragment = \
  9. infra.filepath("tests/package/test_numactl/linux-numactl.fragment")
  10. config = \
  11. f"""
  12. BR2_x86_64=y
  13. BR2_x86_corei7=y
  14. BR2_TOOLCHAIN_EXTERNAL=y
  15. BR2_LINUX_KERNEL=y
  16. BR2_LINUX_KERNEL_CUSTOM_VERSION=y
  17. BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="6.1.75"
  18. BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
  19. BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="board/qemu/x86_64/linux.config"
  20. BR2_LINUX_KERNEL_CONFIG_FRAGMENT_FILES="{kernel_fragment}"
  21. BR2_LINUX_KERNEL_NEEDS_HOST_OPENSSL=y
  22. BR2_LINUX_KERNEL_NEEDS_HOST_LIBELF=y
  23. BR2_PACKAGE_NUMACTL=y
  24. BR2_TARGET_ROOTFS_CPIO=y
  25. BR2_TARGET_ROOTFS_CPIO_GZIP=y
  26. # BR2_TARGET_ROOTFS_TAR is not set
  27. """
  28. def check_numactl_preferred(self):
  29. # Show the default NUMA policy settings. We check we have the
  30. # 4 physical cpus on 2 nodes we configured the emulator
  31. # command line.
  32. out, ret = self.emulator.run("numactl --show")
  33. self.assertEqual(ret, 0)
  34. checks = [
  35. "policy: default",
  36. "preferred node: current",
  37. "physcpubind: 0 1 2 3 ",
  38. "nodebind: 0 1 ",
  39. "membind: 0 1 "
  40. ]
  41. for pattern in checks:
  42. self.assertIn(pattern, out)
  43. # Check the preferred policy on different nodes. This command
  44. # is taken from the numactl man page.
  45. for pref_node in range(2):
  46. cmd = f"numactl --preferred={pref_node} numactl --show"
  47. out, ret = self.emulator.run(cmd)
  48. self.assertEqual(ret, 0)
  49. checks = [
  50. "policy: preferred",
  51. f"preferred node: {pref_node}"
  52. ]
  53. for pattern in checks:
  54. self.assertIn(pattern, out)
  55. def get_numa_node_free_mem(self):
  56. out, ret = self.emulator.run("numactl --hardware")
  57. self.assertEqual(ret, 0)
  58. free_mem = {}
  59. p = re.compile("^node ([0-9]+) free: ([0-9]+) MB")
  60. for line in out:
  61. m = p.match(line)
  62. if m:
  63. node = int(m.group(1))
  64. mem = int(m.group(2))
  65. free_mem[node] = mem
  66. return free_mem
  67. def check_numactl_membind(self):
  68. # We get the current amount of free memory on each node, for
  69. # later comparison.
  70. initial_node_free_mem = self.get_numa_node_free_mem()
  71. # We allocate a shared memory file with a restriction to be in
  72. # node 1 memory only.
  73. shm_file = "/dev/shm/file"
  74. file_size = 100
  75. cmd = f"numactl --membind=1 dd if=/dev/zero of={shm_file} bs=1M count={file_size}"
  76. self.assertRunOk(cmd)
  77. # We collect again the amount of free memory per node.
  78. node_free_mem = self.get_numa_node_free_mem()
  79. # Since we allocated 100M on node 1 only, we check the free
  80. # space on node 0 did not significantly changed and on node 1
  81. # approximately reduced of the file size.
  82. diff = initial_node_free_mem[0] - node_free_mem[0]
  83. self.assertAlmostEqual(diff, 0, delta=10)
  84. diff = initial_node_free_mem[1] - node_free_mem[1]
  85. self.assertAlmostEqual(diff, file_size, delta=10)
  86. # Remove the file, to free the memory.
  87. self.assertRunOk(f"rm -f {shm_file}")
  88. # We allocate again a file in shared memory, but this time in
  89. # two chunks. Each chunk is requested to be allocated in two
  90. # different nodes. This example is taken from the numactl man
  91. # page.
  92. chunk_size = file_size // 2
  93. cmd = "numactl --membind=0 "
  94. cmd += f"dd if=/dev/zero of={shm_file} bs=1M count={chunk_size}"
  95. self.assertRunOk(cmd)
  96. cmd = "numactl --membind=1 "
  97. cmd += f"dd if=/dev/zero of={shm_file} bs=1M count={chunk_size} seek={chunk_size}"
  98. self.assertRunOk(cmd)
  99. # We collect again the amount of free memory.
  100. node_free_mem = self.get_numa_node_free_mem()
  101. # We check the free memory space approximately reduced of each
  102. # chunk size.
  103. for node in range(2):
  104. free_mem_diff = initial_node_free_mem[node] - node_free_mem[node]
  105. self.assertAlmostEqual(free_mem_diff, chunk_size, delta=5)
  106. def test_run(self):
  107. img = os.path.join(self.builddir, "images", "rootfs.cpio.gz")
  108. kern = os.path.join(self.builddir, "images", "bzImage")
  109. # We start the Qemu emulator with 4 processors on 2 NUMA nodes.
  110. self.emulator.boot(arch="x86_64",
  111. kernel=kern,
  112. kernel_cmdline=["console=ttyS0"],
  113. options=["-cpu", "Nehalem", "-m", "512M",
  114. "-smp", "cpus=4,sockets=2,cores=2,maxcpus=4",
  115. "-object", "memory-backend-ram,size=256M,id=m0",
  116. "-object", "memory-backend-ram,size=256M,id=m1",
  117. "-numa", "node,cpus=0-1,nodeid=0,memdev=m0",
  118. "-numa", "node,cpus=2-3,nodeid=1,memdev=m1",
  119. "-initrd", img])
  120. self.emulator.login()
  121. # Check a simple numactl invication:
  122. # show the NUMA hardware inventory.
  123. self.assertRunOk("numactl --hardware")
  124. self.check_numactl_preferred()
  125. self.check_numactl_membind()