feat: vm-native setup, verify and gpu tooling with acpi and bench
This commit is contained in:
83
scripts/libvirt-hook-cpu-isolation.sh
Executable file
83
scripts/libvirt-hook-cpu-isolation.sh
Executable file
@@ -0,0 +1,83 @@
|
||||
#!/bin/bash
|
||||
# libvirt qemu hook: keep host processes off the cores a pinned guest is using.
|
||||
#
|
||||
# Install as /etc/libvirt/hooks/qemu (or drop into /etc/libvirt/hooks/qemu.d/).
|
||||
#
|
||||
# On start it reads the domain's own <cputune> from the XML libvirt passes on
|
||||
# stdin, works out which host CPUs the guest occupies, and confines the systemd
|
||||
# slices to the rest. On stop it hands everything back.
|
||||
#
|
||||
# Measured on a 16 vCPU guest pinned to one CCD of a 7950X: stalls over 10 us in
|
||||
# a 10 second window fell from ~100 to ~52, and CPU throughput rose about 2%.
|
||||
#
|
||||
# Deliberately exits 0 on every path. libvirt treats a non-zero hook exit during
|
||||
# prepare/start as fatal, and a tuning helper must never stop a VM booting.
|
||||
|
||||
DOMAIN="$1"
|
||||
OPERATION="$2"
|
||||
|
||||
ALL=$(cat /sys/devices/system/cpu/present) # not nproc: that honours this hook's own affinity
|
||||
NCPU=$(( ${ALL##*-} + 1 ))
|
||||
SLICES="system.slice user.slice init.scope"
|
||||
|
||||
restore() {
|
||||
for s in $SLICES; do
|
||||
systemctl set-property --runtime -- "$s" AllowedCPUs="$ALL" 2>/dev/null
|
||||
done
|
||||
}
|
||||
|
||||
case "$OPERATION" in
|
||||
prepare)
|
||||
XML=$(cat) # libvirt feeds the domain XML on stdin
|
||||
# every cpuset the guest pins itself to: vcpupin, emulatorpin, iothreadpin
|
||||
GUEST=$(printf '%s' "$XML" | grep -oE "cpuset='[0-9,-]+'" |
|
||||
sed "s/cpuset='//;s/'//" | tr ',' '\n' | sort -u | tr '\n' ',' | sed 's/,$//')
|
||||
[ -n "$GUEST" ] || exit 0 # not a pinned domain, nothing to do
|
||||
|
||||
HOST=$(python3 - "$GUEST" "$NCPU" <<'PY' 2>/dev/null
|
||||
import sys
|
||||
def expand(spec):
|
||||
out = set()
|
||||
for part in spec.split(','):
|
||||
if not part: continue
|
||||
if '-' in part:
|
||||
a, b = part.split('-'); out.update(range(int(a), int(b) + 1))
|
||||
else:
|
||||
out.add(int(part))
|
||||
return out
|
||||
guest, n = expand(sys.argv[1]), int(sys.argv[2])
|
||||
rest = sorted(set(range(n)) - guest)
|
||||
if not rest:
|
||||
sys.exit(1) # guest wants everything; leave the host alone
|
||||
# collapse back into ranges
|
||||
out, start, prev = [], rest[0], rest[0]
|
||||
for c in rest[1:] + [None]:
|
||||
if c == prev + 1:
|
||||
prev = c; continue
|
||||
out.append(str(start) if start == prev else "%d-%d" % (start, prev))
|
||||
if c is None: break
|
||||
start = prev = c
|
||||
print(",".join(out))
|
||||
PY
|
||||
)
|
||||
[ -n "$HOST" ] || exit 0 # nothing left for the host, or it failed
|
||||
|
||||
for s in $SLICES; do
|
||||
systemctl set-property --runtime -- "$s" AllowedCPUs="$HOST" 2>/dev/null
|
||||
done
|
||||
logger -t libvirt-cpu-isolation "$DOMAIN starting: host slices confined to $HOST (guest has $GUEST)"
|
||||
;;
|
||||
|
||||
release|stopped)
|
||||
restore
|
||||
logger -t libvirt-cpu-isolation "$DOMAIN $OPERATION: host slices restored to $ALL"
|
||||
;;
|
||||
*)
|
||||
# Deliberately does nothing. An earlier version called virsh here to check
|
||||
# whether any domain was still running - that deadlocks libvirtd, because
|
||||
# libvirt is blocked waiting for this hook to return while the hook waits on
|
||||
# libvirt. Never call virsh from a libvirt hook.
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
Reference in New Issue
Block a user