fint-epqv2 / tools /runmem_cgroup.py
HelloSun's picture
Add Flint expert paging port and memory benchmark
e2e6c43 verified
Raw History Blame Contribute Delete
3.01 kB
#!/usr/bin/env python3
"""Run a command inside a cgroup-v2 MemoryMax scope and report peak memory."""
import argparse
import json
import os
import subprocess
import sys
import time
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--limit-gib", type=int, required=True)
parser.add_argument("--timeout", type=float, default=7200)
parser.add_argument("command", nargs=argparse.REMAINDER)
args = parser.parse_args()
command = args.command[1:] if args.command[:1] == ["--"] else args.command
if not command:
parser.error("missing command")
if args.limit_gib not in (2, 4, 8, 16, 32):
parser.error("limit must be 2, 4, 8, 16, or 32 GiB")
unit = f"flint-epq-bench-{os.getpid()}"
runner = [
"systemd-run", "--quiet", "--wait", "--collect", "--pipe",
"--unit", unit, "--property", f"MemoryMax={args.limit_gib}G",
"--property", "MemorySwapMax=0", "--", *command,
]
started = time.monotonic()
process = subprocess.Popen(runner, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
time.sleep(1)
if process.poll() is not None:
output, _ = process.communicate()
if output:
sys.stdout.write(output)
print("UNTESTED: systemd/cgroup MemoryMax unavailable; RLIMIT_DATA is not a substitute", file=sys.stderr)
return 77
peak = swap_peak = 0
while process.poll() is None:
try:
cgroup = subprocess.check_output(
["systemctl", "show", f"{unit}.scope", "-p", "ControlGroup", "--value"],
text=True, stderr=subprocess.DEVNULL,
).strip()
if cgroup:
path = os.path.join("/sys/fs/cgroup", cgroup.lstrip("/"))
for name, target in (("memory.peak", "peak"), ("memory.swap.peak", "swap")):
try:
with open(os.path.join(path, name), encoding="ascii") as stream:
value = int(stream.read().strip())
if target == "peak":
peak = max(peak, value)
else:
swap_peak = max(swap_peak, value)
except OSError:
pass
except (OSError, subprocess.CalledProcessError):
pass
if time.monotonic() - started > args.timeout:
process.kill()
break
time.sleep(0.25)
output, _ = process.communicate()
if output:
sys.stdout.write(output)
print("RUNMEM " + json.dumps({
"limit_gib": args.limit_gib,
"peak_bytes": peak,
"peak_gib": round(peak / (1024 ** 3), 3),
"swap_peak_bytes": swap_peak,
"wall_s": round(time.monotonic() - started, 2),
"exit": process.returncode,
"cmd": command,
"method": "cgroup-v2-MemoryMax",
}))
return process.returncode
if __name__ == "__main__":
raise SystemExit(main())