scx-upstream/meson-scripts/run_stress_tests
likewhatevs bf68679d35
Setup "debugging" and misc cleanup (#695)
* Fix a couple of misc errors in build scripts.
* Tweak scripts/kconfigs to make bpftrace work.
* Update how CI caching works to make builds faster (6 minute turnaround
  time)
* Update CI config to generate per-scheduler debug archives w/ guest
  dmesg/scheduler stdout, guest stdout, bpftrace script output,
  veristat output.

* Update build scripts to accept the following:
** VNG RW -- write to host filesystem (better caching, logging).
* For stress tests in particular (via ini config):
** QEMU Opts -- to facilitate reproducing bugs (i.e. high core count).
** bpftrace scripts -- specify bpftrace scripts to run during stress
tests.
2024-09-26 11:11:10 -04:00

145 lines
4.9 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Small wrapper for running stress tests. Do not make this more complicated and
assume any libraries besides Python3 stdlib.
"""
import logging
import os
import subprocess
import sys
import time
from pathlib import PurePath
from typing import List
from argparse import ArgumentParser, Namespace
from configparser import ConfigParser
logger = logging.getLogger(__name__)
SCRIPT_DIR: str = os.path.dirname(os.path.realpath(__file__))
def get_exe_path(exe: str) -> str:
path = subprocess.check_output(["which", exe])
return path.decode("utf-8").replace("\n", "")
def sched_path(path: str, sched: str) -> str:
rel_path = subprocess.check_output(
["find", path, "-type", "f", "-executable", "-name", sched]).decode("utf-8").replace("\n", "")
full_path = subprocess.check_output(["readlink", "-f", rel_path]).decode("utf-8").replace("\n", "")
logger.debug(f"found scheduler {sched} in path: {full_path}")
return full_path
def load_config(path: str) -> ConfigParser:
config = ConfigParser()
config.read(path)
return config
def run_stress_test(
config,
build_dir: str,
output: str,
vng_path: str,
kernel: str,
verbose: bool,
rw: bool,
headers: str,
) -> int:
scheduler_args = config.get('scheduler_args')
stress_cmd = config.get('stress_cmd')
s_path = sched_path(build_dir, config.get('sched'))
sched_cmd = s_path + " " + config.get('sched_args')
timeout_sec = int(config.get("timeout_sec"))
if vng_path:
cmd = [vng_path, "--user", "root", "-v", "-r", kernel]
if config.get("qemu_opts"):
cmd += ['--qemu-opts']
cmd += [f"'{config.get("qemu_opts")}'"]
vm_input = f"{stress_cmd} & timeout --foreground --preserve-status {timeout_sec} {sched_cmd}"
if bpftrace_scripts := config.get('bpftrace_scripts'):
vm_input = f"\"{build_dir}/bpftrace_stress_wrapper.sh\" '{stress_cmd}' '{sched_cmd}' '{timeout_sec}' '{bpftrace_scripts}'"
if headers:
vm_input += f" '{headers}'"
if rw and os.getenv('CI'):
print('mounting VNG as RW because CI')
cmd += ["--rw"]
elif rw:
print('not mounting VNG as RW because not CI')
cmd += ["--"]
cmd += [vm_input]
err = sys.stderr if output == "-" else open(output, "w")
out = sys.stdout if output == "-" else err
print(f"vng cmd is {cmd}")
proc = subprocess.Popen(
cmd, env=os.environ, shell=False, stdout=out,
stderr=err, stdin=subprocess.PIPE, text=True)
proc.wait()
return proc.returncode
def stress_tests(args: Namespace) -> None:
configs = load_config(args.config)
vng_path = ""
if args.vng:
try:
vng_path = get_exe_path("vng")
except Exception:
raise OSError(
"Please install `vng` to run, see:\n"
"https://github.com/arighi/virtme-ng?tab=readme-ov-file#installation")
return_codes = {}
for test_name in configs.sections():
if args.stress_test and test_name != args.stress_test:
continue
if args.sched and configs[test_name].get('sched') != args.sched:
continue
print(f"Running stress test: {test_name}")
return_codes[test_name] = run_stress_test(
configs[test_name],
args.build_dir,
args.output,
vng_path,
args.kernel,
args.verbose,
args.rw,
args.headers
)
for test_name, ret in return_codes.items():
if ret not in (143, 0):
logging.error(f"Failed stress tests for {test_name}: exit {ret}")
sys.exit(ret)
logging.info("All stress tests passed!")
if __name__ == "__main__":
parser = ArgumentParser(prog=__file__)
parser.add_argument(
'-c', '--config',
default=os.path.join(SCRIPT_DIR, "stress_tests.ini"),
help='Path to config file'
)
parser.add_argument('-o', '--output', default='-', help='Scheduler output')
parser.add_argument(
'-t', '--stress-test', default='', help='Name of the stress test (default: all)')
parser.add_argument(
'-b', '--build-dir', default='build', help='Meson build dir')
parser.add_argument(
'-k', '--kernel', default='', help='Kernel path for vng')
parser.add_argument(
'-v', '--verbose', action='store_true', help='Verbose output')
parser.add_argument(
'--vng', action='store_true', default=True, help='Run in vng')
parser.add_argument(
'--sched', default='', help='Scheduler to test (default: all)'
)
parser.add_argument(
'--rw', default=False, help='Mount VNG Directories as RW (dangerous)'
)
parser.add_argument(
'--headers', default='', help='Kernel Headers Path'
)
args = parser.parse_args()
if args.verbose:
logger.setLevel(logging.DEBUG)
stress_tests(args)