#!/usr/bin/env bash # Run a heavy command on the 8 GB Pi with a memory guard. Raspberry Pi OS boots with cgroup_disable=memory, so # systemd MemoryMax cannot be used; instead the command runs in its own process group and is stopped (TERM, then # KILL) as soon as the system's MemAvailable drops below MIN_FREE_MB -- before the kernel OOM killer would pick # victims such as the desktop session. Prints the peak resident memory of the command's process tree. # MIN_FREE_MB=1200 bash scripts/pi_run.sh set -uo pipefail MIN_FREE_MB=${MIN_FREE_MB:-1200} setsid "$@" & pid=$! peak=0 tripped=0 tree_rss() { # kB, summed over the process group ps -o rss= -g "$pid" 2>/dev/null | awk '{s+=$1} END {print s+0}' } while kill -0 "$pid" 2>/dev/null; do rss=$(tree_rss); (( rss > peak )) && peak=$rss avail=$(awk '/^MemAvailable:/ {print int($2/1024)}' /proc/meminfo) if (( avail < MIN_FREE_MB )); then echo "pi_run: MemAvailable ${avail} MiB < ${MIN_FREE_MB} MiB -- stopping the job (process group $pid)" >&2 kill -TERM -- "-$pid" 2>/dev/null; sleep 5; kill -KILL -- "-$pid" 2>/dev/null tripped=1 break fi sleep 1 done wait "$pid"; rc=$? (( tripped )) && rc=137 echo "pi_run: exit $rc, peak RSS $((peak / 1024)) MiB, guard ${MIN_FREE_MB} MiB free" >&2 exit $rc