Skip to content

Commit

Permalink
Memory:Add memory mapping tool
Browse files Browse the repository at this point in the history
When referring to memory mapping, one is usually referring
to mmap(2). There are 2 categories for using mmap.
One category is SHARED vs PRIVATE mappings.
The other category is FILE vs ANONYMOUS mappings.
Mixed together you get the 4 following combinations:
1. PRIVATE FILE MAPPING
2. SHARED FILE MAPPING
3. PRIVATE ANONYMOUS MAPPING
4. SHARED ANONYMOUS MAPPING
Add a memory mapping tool to support the above four scenarios.
Updates numa_stress with mmap tool.

Signed-off-by: zhenyzha <[email protected]>
  • Loading branch information
zhenyzha committed Jul 26, 2023
1 parent 448acf0 commit b17c596
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 86 deletions.
Binary file added deps/mem_mapping/mem_mapping.tar.gz
Binary file not shown.
13 changes: 10 additions & 3 deletions qemu/tests/cfg/numa.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@
no ppc64 ppc64le
type = numa_stress
del stress_args
mem_ratio = 0.8
# Replace "count" in "dd commands" to avoid lack of disk space
#tmpfs_size = 1024
mem_ratio = 0.6
cmd_cp_mmap_tool = "/bin/cp -rf %s /var/tmp/ && cd /var/tmp/ && tar zxvf mem_mapping.tar.gz"
make_cmds_mem_mapping = "gcc mem_mapping.c -o mem_mapping"
cmd_mmap = "cd /var/tmp/ && ${make_cmds_mem_mapping} && numactl -m %s ./mem_mapping -a -p -l %dK &"
cmd_mmap_cleanup = "rm -rf /var/tmp/mem_*"
cmd_mmap_stop = "pkill -9 mem_mapping"
cmd_migrate_pages = "migratepages %s %s %s"
mem_map_tool = "mem_mapping.tar.gz"
stress_cmds_mem_mapping = "./mem_mapping"
uninstall_cmds_mem_mapping = "rm -rf /home/mem_*"
144 changes: 61 additions & 83 deletions qemu/tests/numa_stress.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import os
import re
import math

from avocado.utils import process

from virttest import error_context
from virttest import utils_misc
from virttest import funcatexit
from virttest import utils_test
from virttest import data_dir
from virttest.staging import utils_memory
Expand Down Expand Up @@ -34,34 +32,14 @@ def max_mem_map_node(host_numa_node, qemu_pid):
return (node_map_most, memory_sz_map_most)


def get_tmpfs_write_speed():
"""
Get the tmpfs write speed of the host
return: The write speed of tmpfs, the unit is kb/s.
"""
process.run("mkdir -p /tmp/test_speed && "
"mount -t tmpfs none /tmp/test_speed", shell=True)
output = process.run("dd if=/dev/urandom of=/tmp/test_speed/test "
"bs=1k count=1024")
try:
speed = re.search(r"\s([\w\s\.]+)/s", output.stderr, re.I).group(1)
return float(utils_misc.normalize_data_size(speed, 'K', 1024))
except Exception:
return 3072
finally:
process.run("umount /tmp/test_speed")
os.removedirs("/tmp/test_speed")


@error_context.context_aware
def run(test, params, env):
"""
Qemu numa stress test:
1) Boot up a guest and find the node it used
2) Try to allocate memory in that node
3) Run memory heavy stress inside guest
4) Check the vm is running well after stress,
no out of memory or qemu crash.
4) Check the memory use status of qemu process
5) Repeat step 2 ~ 4 several times
Expand All @@ -73,69 +51,69 @@ def run(test, params, env):
if len(host_numa_node.online_nodes) < 2:
test.cancel("Host only has one NUMA node, skipping test...")

mem_map_tool = params.get("mem_map_tool")
cmd_cp_mmap_tool = params.get("cmd_cp_mmap_tool")
cmd_mmap_cleanup = params.get("cmd_mmap_cleanup")
cmd_mmap_stop = params.get("cmd_mmap_stop")
cmd_migrate_pages = params.get("cmd_migrate_pages")
timeout = float(params.get("login_timeout", 240))
test_count = int(params.get("test_count", 4))
test_count = int(params.get("test_count", 2))

vm = env.get_vm(params["main_vm"])
vm.verify_alive()
session = vm.wait_for_login(timeout=timeout)

qemu_pid = vm.get_pid()

if test_count < len(host_numa_node.online_nodes):
test_count = len(host_numa_node.online_nodes)

tmpfs_path = params.get("tmpfs_path", "tmpfs_numa_test")
tmpfs_path = utils_misc.get_path(data_dir.get_tmp_dir(), tmpfs_path)
tmpfs_write_speed = get_tmpfs_write_speed()
memory_file = utils_misc.get_path(tmpfs_path, "test")

utils_memory.drop_caches()

if not os.path.isdir(tmpfs_path):
os.mkdir(tmpfs_path)

test_mem = float(params.get("mem"))*float(params.get("mem_ratio", 0.8))
stress_args = "--cpu 4 --io 4 --vm 2 --vm-bytes %sM" % int(test_mem / 2)

for test_round in range(test_count):
most_used_node, _ = max_mem_map_node(host_numa_node, qemu_pid)
if os.path.exists(memory_file):
os.remove(memory_file)
utils_memory.drop_caches()
error_context.context("Executing stress test round: %s" % test_round,
test.log.info)
numa_node_malloc = most_used_node
tmpfs_size = \
math.floor(float(host_numa_node.read_from_node_meminfo(numa_node_malloc,
'MemFree')) * 0.9)
dd_timeout = tmpfs_size / tmpfs_write_speed * 1.5
mount_fs_size = "size=%dK" % tmpfs_size
dd_cmd = "dd if=/dev/urandom of=%s bs=1k count=%s" % (memory_file,
tmpfs_size)
numa_dd_cmd = "numactl -m %s %s" % (numa_node_malloc, dd_cmd)
error_context.context("Try to allocate memory in node %s"
% numa_node_malloc, test.log.info)
try:
utils_misc.mount("none", tmpfs_path, "tmpfs", perm=mount_fs_size)
funcatexit.register(env, params.get("type"), utils_misc.umount,
"none", tmpfs_path, "tmpfs")
process.system(numa_dd_cmd, timeout=dd_timeout, shell=True)
except Exception as error_msg:
if "No space" in str(error_msg):
pass
else:
test.fail("Can not allocate memory in node %s."
" Error message:%s" % (numa_node_malloc,
str(error_msg)))
error_context.context("Run memory heavy stress in guest", test.log.info)
stress_test = utils_test.VMStress(vm, "stress", params, stress_args=stress_args)
stress_test.load_stress_tool()
stress_test.unload_stress()
stress_test.clean()
utils_misc.umount("none", tmpfs_path, "tmpfs")
funcatexit.unregister(env, params.get("type"), utils_misc.umount,
"none", tmpfs_path, "tmpfs")
session.cmd("sync; echo 3 > /proc/sys/vm/drop_caches")
node_list = host_numa_node.online_nodes
node_meminfo = host_numa_node.read_from_node_meminfo
if test_count < len(node_list):
test_count = len(node_list)
try:
test_mem = float(params.get("mem")) * float(params.get("mem_ratio", 0.6))
guest_stress_args = "-a -p -l %sM" % int(test_mem)
stress_path = os.path.join(data_dir.get_deps_dir('mem_mapping'), mem_map_tool)
test.log.info("Compile the mem_mapping tool")
cmd_cp_mmap_tool = cmd_cp_mmap_tool % stress_path
process.run(cmd_cp_mmap_tool, shell=True)
utils_memory.drop_caches()

session.close()
for test_round in range(test_count):
cmd_mmap = params.get("cmd_mmap")
error_context.context("Executing stress test round: %s" % test_round, test.log.info)
try:
error_context.context("Get the qemu process memory use status", test.log.info)
most_used_node, memory_used = max_mem_map_node(host_numa_node, qemu_pid)
numa_node_malloc = most_used_node
mmap_size = math.floor(float(node_meminfo(numa_node_malloc, 'MemTotal')) * 0.9)
cmd_mmap = cmd_mmap % (numa_node_malloc, mmap_size)
error_context.context("Run mem_mapping on host node "
"%s." % numa_node_malloc, test.log.info)
process.system_output(cmd_mmap, shell=True, ignore_bg_processes=True)
error_context.context("Run memory heavy stress in guest", test.log.info)
try:
guest_stress = utils_test.VMStress(vm, "mem_mapping", params,
download_url=stress_path,
stress_args=guest_stress_args)
guest_stress.load_stress_tool()
except utils_test.StressError as guest_info:
test.error(guest_info)
error_context.context("Get the qemu process memory use status", test.log.info)
node_after, memory_after = max_mem_map_node(host_numa_node, qemu_pid)
if node_after == most_used_node and memory_after >= memory_used:
idle_nodes = node_list.copy()
idle_nodes.remove(numa_node_malloc)
error_context.context("Run migratepages on host from node "
"%s to node %s." % (numa_node_malloc,
idle_nodes[0]), test.log.info)
migrate_pages = cmd_migrate_pages % (qemu_pid, numa_node_malloc, idle_nodes[0])
process.system_output(migrate_pages, shell=True)
error_context.context("Get the qemu process memory use status again", test.log.info)
node_after, memory_after = max_mem_map_node(host_numa_node, qemu_pid)
if node_after == most_used_node and memory_after >= memory_used:
test.fail("Memory still stick in node %s" % numa_node_malloc)
finally:
guest_stress.unload_stress()
guest_stress.clean()
process.system_output(cmd_mmap_stop, shell=True, ignore_status=True)
utils_memory.drop_caches()
finally:
process.run(cmd_mmap_cleanup, shell=True)
session.close()

0 comments on commit b17c596

Please sign in to comment.