A bash monitor that samples cpu.pressure, memory.pressure, and io.pressure for a target cgroup and drives a two-threshold hysteretic state machine: enter THROTTLED when avg10 > HIGH, and return to HEALTHY only after avg60 has stayed below LOW for a full dwell window. It tolerates partial reads, transient ENOENT, and avg resets to 0; recovers in-progress dwell state from an append-only log across restarts; and on SIGTERM flushes a final record and releases its lock.
Files written and verified at ~/psi-governor/ (psi-governor.sh, test-psi-governor.sh, SOLUTION.md). Full solution below.
A bash monitor that samples cpu.pressure, memory.pressure, and io.pressure for a target cgroup and drives a two-threshold hysteretic state machine: enter THROTTLED when avg10 > HIGH, and return to HEALTHY only after avg60 has stayed below LOW for a full dwell window. It tolerates partial reads, transient ENOENT, and avg resets to 0; recovers in-progress dwell state from an append-only log across restarts; and on SIGTERM flushes a final record and releases its lock.
Five distinct failure modes make the "obvious" implementation wrong.
The intuitive loop compares avg10 > HIGH and avg10 < LOW directly. avg10 is a short 10 s exponentially weighted average; under load hovering near a threshold it crosses and re-crosses repeatedly, emitting a transition on every crossing. Fix: asymmetric hysteresis — enter on fast avg10 > HIGH, leave only after slow avg60 stays < LOW for a dwell window. A single noisy sample moves avg10 but cannot move avg60 below LOW and survive the whole window.
PSI files are seq_files; a read racing teardown can return empty, a full-only line, or a torn line missing avg60. Parsing by field index yields an empty string; arithmetic then errors under set -e or coerces to 0, which falsely looks like "no pressure" and can clear THROTTLED. Fix: parse avg10/avg60 by token, skip a resource unless both are present, and treat "no usable sample" as hold state.
ENOENT during cgroup renameDuring reclaim-rename a pressure file momentarily disappears. This must not be fatal and must not change state; unreadable resources are skipped.
0avg10=0.00 avg60=0.00 is a legitimate low sample (both tokens present) and must be accepted as low — distinguished from truncation by token presence, not value.
In-memory-only state is amnesiac on restart: it defaults to HEALTHY, then re-reads pressure and either emits a duplicate entry transition or restarts the dwell clock. Fix: a durable append-only log with TRANSITION, DWELL, DWELL_RESET, FINAL records, replayed on startup.
SIGTERM with no trap leaves stale stateWithout a trap the process dies mid-record and orphans its pidfile. Fix: trap TERM/INT, emit a final record, and remove the pidfile only if it names this process; reclaim a stale pidfile (dead owner) on startup.
psi-governor.sh#!/usr/bin/env bash
# psi-governor.sh — cgroup v2 PSI pressure hysteresis governor
#
# Samples cpu.pressure / memory.pressure / io.pressure for a target cgroup
# and drives a two-threshold state machine:
#
# * HEALTHY -> THROTTLED when max(avg10) > HIGH
# * THROTTLED -> HEALTHY only after max(avg60) has stayed < LOW for a
# full dwell window (so one noisy sample can
# never oscillate the state)
#
# It is tolerant of malformed/partial PSI files, transient ENOENT (cgroup
# being renamed), and avg windows reset to 0. State is recovered from an
# append-only transition log so a restart in the middle of a dwell window
# neither re-fires a transition nor loses dwell progress. SIGTERM flushes a
# final record and releases the owner pidfile.
#
# Exit status: 0 normal, 1 already running / bad config.
set -u
# --------------------------------------------------------------------------
# Configuration (all overridable via environment)
# --------------------------------------------------------------------------
CGROUP_DIR=${PSI_CGROUP_DIR:-/sys/fs/cgroup}
HIGH=${PSI_HIGH:-10.0} # avg10 % to enter THROTTLED
LOW=${PSI_LOW:-5.0} # avg60 % that must stay low to exit
DWELL=${PSI_DWELL:-30} # seconds avg60 must stay < LOW
POLL=${PSI_POLL_INTERVAL:-1} # seconds between samples
LOG=${PSI_LOG:-} # append-only transition log (optional)
PIDFILE=${PSI_PIDFILE:-${LOG:+${LOG}.pid}}
FILES=(cpu.pressure memory.pressure io.pressure)
STATE=HEALTHY
DWELL_START=""
MAX10=""
MAX60=""
FINALIZED=0
# --------------------------------------------------------------------------
# Helpers
# --------------------------------------------------------------------------
now() { date +%s; }
gt() { awk -v a="$1" -v b="$2" 'BEGIN{exit !(a>b)}'; }
lt() { awk -v a="$1" -v b="$2" 'BEGIN{exit !(a<b)}'; }
maxf() { awk -v a="$1" -v b="$2" 'BEGIN{print (b>a)?b:a}'; }
# Append a record to the log (best-effort, never fatal).
logevent() {
[ -n "$LOG" ] || return 0
printf '%s %s\n' "$(now)" "$*" >>"$LOG"
}
# Read the three PSI files and set MAX10/MAX60 to the max across resources.
# Returns 1 when there is no usable sample (all files missing/partial).
read_pressures() {
local f line v10 v60
MAX10=""
MAX60=""
for f in "${FILES[@]}"; do
# `some` is the first line on every kernel that exposes these files.
# A truncated/partial write may drop it or the avg60 token; skip.
line=$(awk '/^some[[:space:]]/{print; exit}' "$CGROUP_DIR/$f" 2>/dev/null) || true
[ -n "${line:-}" ] || continue
v10=$(printf '%s\n' "$line" | awk '{for(i=1;i<=NF;i++){if($i ~ /^avg10=/){sub(/^avg10=/,"",$i);print $i;exit}}}')
v60=$(printf '%s\n' "$line" | awk '{for(i=1;i<=NF;i++){if($i ~ /^avg60=/){sub(/^avg60=/,"",$i);print $i;exit}}}')
[ -n "${v10:-}" ] && [ -n "${v60:-}" ] || continue
if [ -z "$MAX10" ]; then
MAX10=$v10
MAX60=$v60
else
MAX10=$(maxf "$MAX10" "$v10")
MAX60=$(maxf "$MAX60" "$v60")
fi
done
[ -n "$MAX10" ]
}
# Rebuild STATE and DWELL_START from the append-only log. Records are
# processed in order so the last transition and the dwell marker that
# belongs to it win.
recover_state() {
[ -n "$LOG" ] && [ -s "$LOG" ] || return 0
local ts ev rest k v
STATE=HEALTHY
DWELL_START=""
while read -r ts ev rest; do
case $ev in
TRANSITION)
# rest: from=... to=... max10=... max60=...
k=${rest#*to=}; v=${k%% *}
STATE=$v
DWELL_START=""
;;
DWELL)
# rest: since=<epoch> ...
k=${rest#*since=}; v=${k%% *}
if [ "$STATE" = THROTTLED ]; then
DWELL_START=$v
fi
;;
DWELL_RESET)
DWELL_START=""
;;
*) : ;;
esac
done <"$LOG"
}
transition() {
local to=$1
printf '%s %s %s %s->%s max10=%s max60=%s\n' \
"$(now)" "TRANSITION" "from=$STATE" "$STATE" "$to" "$MAX10" "$MAX60"
logevent "TRANSITION from=$STATE to=$to max10=$MAX10 max60=$MAX60"
if [ "$to" = HEALTHY ]; then
STATE=HEALTHY
else
STATE=THROTTLED
fi
DWELL_START=""
}
# --------------------------------------------------------------------------
# Lock / ownership (stale pidfile is reclaimed, never left behind)
# --------------------------------------------------------------------------
acquire_lock() {
[ -n "$PIDFILE" ] || return 0
if [ -e "$PIDFILE" ]; then
local old
old=$(cat "$PIDFILE" 2>/dev/null || true)
if [ -n "$old" ] && kill -0 "$old" 2>/dev/null; then
echo "psi-governor: already running as pid $old" >&2
exit 1
fi
rm -f "$PIDFILE"
fi
printf '%s\n' "$$" >"$PIDFILE"
}
release_lock() {
[ -n "$PIDFILE" ] || return 0
if [ "$(cat "$PIDFILE" 2>/dev/null || true)" = "$$" ]; then
rm -f "$PIDFILE"
fi
}
finalize() {
[ "$FINALIZED" -eq 1 ] && return 0
FINALIZED=1
printf '%s FINAL state=%s max10=%s max60=%s\n' \
"$(now)" "$STATE" "${MAX10:-?}" "${MAX60:-?}"
logevent "FINAL state=$STATE max10=${MAX10:-?} max60=${MAX60:-?}"
release_lock
}
on_term() {
finalize
exit 0
}
# --------------------------------------------------------------------------
# Main
# --------------------------------------------------------------------------
acquire_lock
recover_state
trap on_term TERM INT
while :; do
if read_pressures; then
case $STATE in
HEALTHY)
if gt "$MAX10" "$HIGH"; then
transition THROTTLED
fi
;;
THROTTLED)
if lt "$MAX60" "$LOW"; then
t=$(now)
if [ -z "$DWELL_START" ]; then
DWELL_START=$t
logevent "DWELL since=$DWELL_START max10=$MAX10 max60=$MAX60"
elif [ $((t - DWELL_START)) -ge "$DWELL" ]; then
transition HEALTHY
fi
elif [ -n "$DWELL_START" ]; then
# avg60 climbed back above LOW: restart the dwell clock.
DWELL_START=""
logevent "DWELL_RESET max10=$MAX10 max60=$MAX60"
fi
;;
esac
fi
# Missing/partial sample: hold current state and dwell progress.
sleep "$POLL"
done
| Concern | Mechanism |
|---|---|
| Oscillation | Entry on avg10 > HIGH; exit only on avg60 < LOW for DWELL seconds. |
| Noisy sample during dwell | Dwell aborts only when avg60 ≥ LOW, so an avg10 spike that leaves avg60 low does not abort. |
| Partial read | Require both avg10= and avg60= tokens; otherwise skip the resource. |
| No data at all | read_pressures returns 1; loop holds state and dwell progress. |
ENOENT |
2>/dev/null || true; missing file simply skipped. |
Avg reset to 0 |
0.00 is a valid, low sample; dwell proceeds. |
| Restart mid-dwell | recover_state replays TRANSITION/DWELL/DWELL_RESET in order. |
SIGTERM |
finalize writes FINAL, removes pidfile iff owned by $$. |
| Stale owner | acquire_lock reclaims a pidfile whose pid is not alive. |
Log format (append-only, space separated):
<epoch> TRANSITION from=HEALTHY to=THROTTLED max10=40.0 max60=40.0
<epoch> DWELL since=<epoch> max10=1.0 max60=1.0
<epoch> DWELL_RESET max10=1.0 max60=20.0
<epoch> FINAL state=HEALTHY max10=0.0 max60=0.0
PSI_CGROUP_DIR=/sys/fs/cgroup/my.slice \
PSI_HIGH=10 PSI_LOW=5 PSI_DWELL=30 PSI_POLL_INTERVAL=1 \
PSI_LOG=/var/log/psi-governor.log \
./psi-governor.sh
Transitions print to stdout and append to $PSI_LOG; $PSI_LOG.pid is the owner file.
The harness builds a synthetic fixture cgroup tree (three writable *.pressure files), rewrites it between polls, and asserts the exact emitted timeline plus no duplicates across a kill/restart performed mid-dwell.
test-psi-governor.sh#!/usr/bin/env bash
# test-psi-governor.sh — synthetic fixture verification for psi-governor.sh
set -u
HERE=$(cd "$(dirname "$0")" && pwd)
GOV="$HERE/psi-governor.sh"
TMP=$(mktemp -d)
CGROUP="$TMP/cgroup"
LOG="$TMP/transitions.log"
PIDFILE="$TMP/gov.pid"
OUT="$TMP/out.log"
ERR="$TMP/err.log"
mkdir -p "$CGROUP"
: >"$LOG"
fail() { echo "FAIL: $*" >&2; echo "--- log ---" >&2; cat "$LOG" >&2; echo "--- err ---" >&2; cat "$ERR" >&2; exit 1; }
pass() { echo "PASS: $*"; }
write_pressure() { # avg10 avg60
local a10=$1 a60=$2 f
for f in cpu.pressure memory.pressure io.pressure; do
printf 'some avg10=%s avg60=%s avg300=0.00 total=0\n' "$a10" "$a60" >"$CGROUP/.$f.tmp"
mv "$CGROUP/.$f.tmp" "$CGROUP/$f"
done
}
start_gov() {
PSI_CGROUP_DIR="$CGROUP" PSI_HIGH=10 PSI_LOW=5 PSI_DWELL=3 \
PSI_POLL_INTERVAL=0.2 PSI_LOG="$LOG" PSI_PIDFILE="$PIDFILE" \
"$GOV" >"$OUT" 2>>"$ERR" &
GOV_PID=$!
}
stop_gov() { # graceful
kill -TERM "$GOV_PID" 2>/dev/null || true
wait "$GOV_PID" 2>/dev/null || true
}
timeline() { awk '$2=="TRANSITION"{f="";t="";for(i=3;i<=NF;i++){if($i~/^from=/){sub("from=","",$i);f=$i}if($i~/^to=/){sub("to=","",$i);t=$i}}print f"->"t}' "$LOG"; }
cleanup() { stop_gov; rm -rf "$TMP"; }
trap cleanup EXIT
# --- Setup: healthy fixture -------------------------------------------------
write_pressure 0 0
start_gov
sleep 0.6
# --- Tolerance: transient ENOENT + truncated 'some'-only file --------------
rm -f "$CGROUP/io.pressure"
printf 'some avg10=0.00\n' >"$CGROUP/cpu.pressure" # truncated: no avg60
printf 'not a psi line\n' >"$CGROUP/memory.pressure" # garbage
sleep 0.6
kill -0 "$GOV_PID" 2>/dev/null || fail "governor died on malformed input"
write_pressure 0 0
sleep 0.4
[ -s "$LOG" ] && [ ! -s "$OUT" ] || true
if [ -n "$(timeline)" ]; then fail "tolerance window produced spurious transitions"; fi
pass "tolerates ENOENT, truncated and malformed PSI files"
# --- Enter THROTTLED --------------------------------------------------------
write_pressure 40 40
sleep 0.6
[ "$(timeline)" = "HEALTHY->THROTTLED" ] \
|| fail "expected single HEALTHY->THROTTLED, got: $(timeline | tr '\n' ',')"
pass "entered THROTTLED on avg10 > high"
# --- Start dwell, then kill mid-dwell and restart ---------------------------
write_pressure 1 1
sleep 0.8 # stay < LOW; dwell clock running (DWELL=3)
grep -q ' DWELL ' "$LOG" || fail "dwell marker not written"
stop_gov
grep -q ' FINAL ' "$LOG" || fail "SIGTERM did not flush final record"
[ -e "$PIDFILE" ] && fail "pidfile left behind after SIGTERM"
pass "SIGTERM flushed FINAL record and released pidfile"
# Restart: state and dwell progress must be recovered from the log.
: >"$OUT"
start_gov
sleep 0.6
[ "$(timeline | tail -1)" = "HEALTHY->THROTTLED" ] \
|| fail "restart re-fired a transition: $(timeline | tr '\n' ',')"
pass "restart mid-dwell did not re-fire a transition"
# Wait out the remainder of the dwell window.
sleep 4.5
stop_gov
# --- Assert exact timeline, no duplicates -----------------------------------
EXPECTED=$'HEALTHY->THROTTLED\nTHROTTLED->HEALTHY'
ACTUAL=$(timeline)
[ "$ACTUAL" = "$EXPECTED" ] || fail "timeline mismatch; expected [$EXPECTED] got [$ACTUAL]"
[ "$(printf '%s\n' "$ACTUAL" | grep -c '^HEALTHY->THROTTLED$')" -eq 1 ] || fail "duplicated entry transition"
[ "$(printf '%s\n' "$ACTUAL" | grep -c '^THROTTLED->HEALTHY$')" -eq 1 ] || fail "duplicated exit transition"
pass "exact transition timeline with no duplicates across kill/restart"
# --- Dwell reset when avg60 climbs back above LOW ---------------------------
: >"$LOG"
write_pressure 0 0
start_gov
sleep 0.4
write_pressure 40 40 # enter THROTTLED
sleep 0.6
write_pressure 1 1 # start dwell
sleep 0.8
grep -q ' DWELL ' "$LOG" || fail "dwell marker not written (reset phase)"
write_pressure 1 20 # avg10 low but avg60 > LOW -> abort dwell
sleep 0.6
grep -q ' DWELL_RESET ' "$LOG" || fail "dwell was not reset when avg60 rose above LOW"
write_pressure 0 0 # avg window reset to 0 -> legitimate low sample
sleep 4.5
stop_gov
EXPECTED2=$'HEALTHY->THROTTLED\nTHROTTLED->HEALTHY'
ACTUAL2=$(timeline)
[ "$ACTUAL2" = "$EXPECTED2" ] || fail "reset-phase timeline mismatch: [$ACTUAL2]"
pass "dwell resets on avg60 > LOW and avg reset to 0 is treated as low"
# --- Stale-owner lock reclamation ------------------------------------------
printf '999999\n' >"$PIDFILE" # dead pid
: >"$LOG"
write_pressure 0 0
start_gov
sleep 0.5
kill -0 "$GOV_PID" 2>/dev/null || fail "refused to reclaim stale pidfile"
stop_gov
[ -e "$PIDFILE" ] && fail "pidfile left after clean exit"
pass "reclaimed stale owner and released lock on exit"
echo "ALL TESTS PASSED"
chmod +x psi-governor.sh test-psi-governor.sh
./test-psi-governor.sh
Observed output (reproduced across repeated runs):
PASS: tolerates ENOENT, truncated and malformed PSI files
PASS: entered THROTTLED on avg10 > high
PASS: SIGTERM flushed FINAL record and released pidfile
PASS: restart mid-dwell did not re-fire a transition
PASS: exact transition timeline with no duplicates across kill/restart
PASS: dwell resets on avg60 > LOW and avg reset to 0 is treated as low
PASS: reclaimed stale owner and released lock on exit
ALL TESTS PASSED
What each assertion proves:
io.pressure removed, cpu.pressure truncated to a some-only line (no avg60), and memory.pressure garbage, the governor stays alive and emits no spurious transitions.HEALTHY->THROTTLED.SIGTERM produces FINAL and the pidfile is gone.HEALTHY->THROTTLED, THROTTLED->HEALTHY, each once, despite a kill/restart mid-dwell.avg60 rise writes DWELL_RESET; a subsequent avg60=0 is accepted and a single exit transition fires.The fix is a small, dependency-free bash governor built on three ideas: asymmetric hysteresis (avg10 to enter, avg60 + dwell to leave), defensive sampling (token-presence parsing, hold-not-clear on missing data), and durable, replayable state (append-only log with explicit DWELL/DWELL_RESET markers plus a SIGTERM/stale-lock protocol). The synthetic-fixture harness exercises every failure mode and asserts the exact transition timeline, including across a kill/restart in the middle of a dwell window.
# Evidence - Problem class: bash-cgroup-v2-psi-pressure-hysteresis-governor - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-11T16:05:28.716Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Implement a bash monitor that samples cgroup v2 PSI files (cpu.pressure, memory.pressure, io.pressure) for a target cgroup and drives a two-threshold hysteresis state machine: enter THROTTLED when avg10 exceeds the high watermark, and return to HEALTHY only after avg60 has stayed below the low watermark for a full dwell window, so a single noisy sample can never cause an oscillation. The script must tolerate truncated or partial reads (a pressure file with only the 'some' line, a transient ENOENT while a cgroup is being reclaim-renamed, an avg window reset to 0), recover in-progress state from its append-only transition log so a restart mid-dwell does not re-fire a transition, and on SIGTERM flush a final transition record and release its lock without leaving a stale owner. Verify with a synthetic fixture cgroup tree that you rewrite between polls, asserting the exact emitted transition timeline plus no duplicated transitions across a kill/restart cycle performed in the middle of a dwell window.", "environment": "bash", "language": "shell", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "bash-cgroup-v2-psi-pressure-hysteresis-governor", "provider": "openrouter", "solved_at": "2026-09-11T16:05:28.716Z", "version": "5.2"}Files written and verified at ~/psi-governor/ (psi-governor.sh, test-psi-governor.sh, SOLUTION.md). Full solution below.
A bash monitor that samples cpu.pressure, memory.pressure, and io.pressure for a target cgroup and drives a two-threshold hysteretic state machine: enter THROTTLED when avg10 > HIGH, and return to HEALTHY only after avg60 has stayed below LOW for a full dwell window. It tolerates partial reads, transient ENOENT, and avg resets to 0; recovers in-progress dwell state from an append-only log across restarts; and on SIGTERM flushes a final record and releases its lock.
Five distinct failure modes make the "obvious" implementation wrong.
The intuitive loop compares avg10 > HIGH and avg10 < LOW directly. avg10 is a short 10 s exponentially weighted average; under load hovering near a threshold it crosses and re-crosses repeatedly, emitting a transition on every crossing. Fix: asymmetric hysteresis — enter on fast avg10 > HIGH, leave only after slow avg60 stays < LOW for a dwell window. A single noisy sample moves avg10 but cannot move avg60 below LOW and survive the whole window.
PSI files are seq_files; a read racing teardown can return empty, a full-only line, or a torn line missing avg60. Parsing by field index yields an empty string; arithmetic then errors under set -e or coerces to 0, which falsely looks like "no pressure" and can clear THROTTLED. Fix: parse avg10/avg60 by token, skip a resource unless both are present, and treat "no usable sample" as hold state.
ENOENT during cgroup renameDuring reclaim-rename a pressure file momentarily disappears. This must not be fatal and must not change state; unreadable resources are skipped.
0avg10=0.00 avg60=0.00 is a legitimate low sample (both tokens present) and must be accepted as low — distinguished from truncation by token presence, not value.
In-memory-only state is amnesiac on restart: it defaults to HEALTHY, then re-reads pressure and either emits a duplicate entry transition or restarts the dwell clock. Fix: a durable append-only log with TRANSITION, DWELL, DWELL_RESET, FINAL records, replayed on startup.
SIGTERM with no trap leaves stale stateWithout a trap the process dies mid-record and orphans its pidfile. Fix: trap TERM/INT, emit a final record, and remove the pidfile only if it names this process; reclaim a stale pidfile (dead owner) on startup.
psi-governor.sh#!/usr/bin/env bash
# psi-governor.sh — cgroup v2 PSI pressure hysteresis governor
#
# Samples cpu.pressure / memory.pressure / io.pressure for a target cgroup
# and drives a two-threshold state machine:
#
# * HEALTHY -> THROTTLED when max(avg10) > HIGH
# * THROTTLED -> HEALTHY only after max(avg60) has stayed < LOW for a
# full dwell window (so one noisy sample can
# never oscillate the state)
#
# It is tolerant of malformed/partial PSI files, transient ENOENT (cgroup
# being renamed), and avg windows reset to 0. State is recovered from an
# append-only transition log so a restart in the middle of a dwell window
# neither re-fires a transition nor loses dwell progress. SIGTERM flushes a
# final record and releases the owner pidfile.
#
# Exit status: 0 normal, 1 already running / bad config.
set -u
# --------------------------------------------------------------------------
# Configuration (all overridable via environment)
# --------------------------------------------------------------------------
CGROUP_DIR=${PSI_CGROUP_DIR:-/sys/fs/cgroup}
HIGH=${PSI_HIGH:-10.0} # avg10 % to enter THROTTLED
LOW=${PSI_LOW:-5.0} # avg60 % that must stay low to exit
DWELL=${PSI_DWELL:-30} # seconds avg60 must stay < LOW
POLL=${PSI_POLL_INTERVAL:-1} # seconds between samples
LOG=${PSI_LOG:-} # append-only transition log (optional)
PIDFILE=${PSI_PIDFILE:-${LOG:+${LOG}.pid}}
FILES=(cpu.pressure memory.pressure io.pressure)
STATE=HEALTHY
DWELL_START=""
MAX10=""
MAX60=""
FINALIZED=0
# --------------------------------------------------------------------------
# Helpers
# --------------------------------------------------------------------------
now() { date +%s; }
gt() { awk -v a="$1" -v b="$2" 'BEGIN{exit !(a>b)}'; }
lt() { awk -v a="$1" -v b="$2" 'BEGIN{exit !(a<b)}'; }
maxf() { awk -v a="$1" -v b="$2" 'BEGIN{print (b>a)?b:a}'; }
# Append a record to the log (best-effort, never fatal).
logevent() {
[ -n "$LOG" ] || return 0
printf '%s %s\n' "$(now)" "$*" >>"$LOG"
}
# Read the three PSI files and set MAX10/MAX60 to the max across resources.
# Returns 1 when there is no usable sample (all files missing/partial).
read_pressures() {
local f line v10 v60
MAX10=""
MAX60=""
for f in "${FILES[@]}"; do
# `some` is the first line on every kernel that exposes these files.
# A truncated/partial write may drop it or the avg60 token; skip.
line=$(awk '/^some[[:space:]]/{print; exit}' "$CGROUP_DIR/$f" 2>/dev/null) || true
[ -n "${line:-}" ] || continue
v10=$(printf '%s\n' "$line" | awk '{for(i=1;i<=NF;i++){if($i ~ /^avg10=/){sub(/^avg10=/,"",$i);print $i;exit}}}')
v60=$(printf '%s\n' "$line" | awk '{for(i=1;i<=NF;i++){if($i ~ /^avg60=/){sub(/^avg60=/,"",$i);print $i;exit}}}')
[ -n "${v10:-}" ] && [ -n "${v60:-}" ] || continue
if [ -z "$MAX10" ]; then
MAX10=$v10
MAX60=$v60
else
MAX10=$(maxf "$MAX10" "$v10")
MAX60=$(maxf "$MAX60" "$v60")
fi
done
[ -n "$MAX10" ]
}
# Rebuild STATE and DWELL_START from the append-only log. Records are
# processed in order so the last transition and the dwell marker that
# belongs to it win.
recover_state() {
[ -n "$LOG" ] && [ -s "$LOG" ] || return 0
local ts ev rest k v
STATE=HEALTHY
DWELL_START=""
while read -r ts ev rest; do
case $ev in
TRANSITION)
# rest: from=... to=... max10=... max60=...
k=${rest#*to=}; v=${k%% *}
STATE=$v
DWELL_START=""
;;
DWELL)
# rest: since=<epoch> ...
k=${rest#*since=}; v=${k%% *}
if [ "$STATE" = THROTTLED ]; then
DWELL_START=$v
fi
;;
DWELL_RESET)
DWELL_START=""
;;
*) : ;;
esac
done <"$LOG"
}
transition() {
local to=$1
printf '%s %s %s %s->%s max10=%s max60=%s\n' \
"$(now)" "TRANSITION" "from=$STATE" "$STATE" "$to" "$MAX10" "$MAX60"
logevent "TRANSITION from=$STATE to=$to max10=$MAX10 max60=$MAX60"
if [ "$to" = HEALTHY ]; then
STATE=HEALTHY
else
STATE=THROTTLED
fi
DWELL_START=""
}
# --------------------------------------------------------------------------
# Lock / ownership (stale pidfile is reclaimed, never left behind)
# --------------------------------------------------------------------------
acquire_lock() {
[ -n "$PIDFILE" ] || return 0
if [ -e "$PIDFILE" ]; then
local old
old=$(cat "$PIDFILE" 2>/dev/null || true)
if [ -n "$old" ] && kill -0 "$old" 2>/dev/null; then
echo "psi-governor: already running as pid $old" >&2
exit 1
fi
rm -f "$PIDFILE"
fi
printf '%s\n' "$$" >"$PIDFILE"
}
release_lock() {
[ -n "$PIDFILE" ] || return 0
if [ "$(cat "$PIDFILE" 2>/dev/null || true)" = "$$" ]; then
rm -f "$PIDFILE"
fi
}
finalize() {
[ "$FINALIZED" -eq 1 ] && return 0
FINALIZED=1
printf '%s FINAL state=%s max10=%s max60=%s\n' \
"$(now)" "$STATE" "${MAX10:-?}" "${MAX60:-?}"
logevent "FINAL state=$STATE max10=${MAX10:-?} max60=${MAX60:-?}"
release_lock
}
on_term() {
finalize
exit 0
}
# --------------------------------------------------------------------------
# Main
# --------------------------------------------------------------------------
acquire_lock
recover_state
trap on_term TERM INT
while :; do
if read_pressures; then
case $STATE in
HEALTHY)
if gt "$MAX10" "$HIGH"; then
transition THROTTLED
fi
;;
THROTTLED)
if lt "$MAX60" "$LOW"; then
t=$(now)
if [ -z "$DWELL_START" ]; then
DWELL_START=$t
logevent "DWELL since=$DWELL_START max10=$MAX10 max60=$MAX60"
elif [ $((t - DWELL_START)) -ge "$DWELL" ]; then
transition HEALTHY
fi
elif [ -n "$DWELL_START" ]; then
# avg60 climbed back above LOW: restart the dwell clock.
DWELL_START=""
logevent "DWELL_RESET max10=$MAX10 max60=$MAX60"
fi
;;
esac
fi
# Missing/partial sample: hold current state and dwell progress.
sleep "$POLL"
done
| Concern | Mechanism |
|---|---|
| Oscillation | Entry on avg10 > HIGH; exit only on avg60 < LOW for DWELL seconds. |
| Noisy sample during dwell | Dwell aborts only when avg60 ≥ LOW, so an avg10 spike that leaves avg60 low does not abort. |
| Partial read | Require both avg10= and avg60= tokens; otherwise skip the resource. |
| No data at all | read_pressures returns 1; loop holds state and dwell progress. |
ENOENT |
2>/dev/null || true; missing file simply skipped. |
Avg reset to 0 |
0.00 is a valid, low sample; dwell proceeds. |
| Restart mid-dwell | recover_state replays TRANSITION/DWELL/DWELL_RESET in order. |
SIGTERM |
finalize writes FINAL, removes pidfile iff owned by $$. |
| Stale owner | acquire_lock reclaims a pidfile whose pid is not alive. |
Log format (append-only, space separated):
<epoch> TRANSITION from=HEALTHY to=THROTTLED max10=40.0 max60=40.0
<epoch> DWELL since=<epoch> max10=1.0 max60=1.0
<epoch> DWELL_RESET max10=1.0 max60=20.0
<epoch> FINAL state=HEALTHY max10=0.0 max60=0.0
PSI_CGROUP_DIR=/sys/fs/cgroup/my.slice \
PSI_HIGH=10 PSI_LOW=5 PSI_DWELL=30 PSI_POLL_INTERVAL=1 \
PSI_LOG=/var/log/psi-governor.log \
./psi-governor.sh
Transitions print to stdout and append to $PSI_LOG; $PSI_LOG.pid is the owner file.
The harness builds a synthetic fixture cgroup tree (three writable *.pressure files), rewrites it between polls, and asserts the exact emitted timeline plus no duplicates across a kill/restart performed mid-dwell.
test-psi-governor.sh#!/usr/bin/env bash
# test-psi-governor.sh — synthetic fixture verification for psi-governor.sh
set -u
HERE=$(cd "$(dirname "$0")" && pwd)
GOV="$HERE/psi-governor.sh"
TMP=$(mktemp -d)
CGROUP="$TMP/cgroup"
LOG="$TMP/transitions.log"
PIDFILE="$TMP/gov.pid"
OUT="$TMP/out.log"
ERR="$TMP/err.log"
mkdir -p "$CGROUP"
: >"$LOG"
fail() { echo "FAIL: $*" >&2; echo "--- log ---" >&2; cat "$LOG" >&2; echo "--- err ---" >&2; cat "$ERR" >&2; exit 1; }
pass() { echo "PASS: $*"; }
write_pressure() { # avg10 avg60
local a10=$1 a60=$2 f
for f in cpu.pressure memory.pressure io.pressure; do
printf 'some avg10=%s avg60=%s avg300=0.00 total=0\n' "$a10" "$a60" >"$CGROUP/.$f.tmp"
mv "$CGROUP/.$f.tmp" "$CGROUP/$f"
done
}
start_gov() {
PSI_CGROUP_DIR="$CGROUP" PSI_HIGH=10 PSI_LOW=5 PSI_DWELL=3 \
PSI_POLL_INTERVAL=0.2 PSI_LOG="$LOG" PSI_PIDFILE="$PIDFILE" \
"$GOV" >"$OUT" 2>>"$ERR" &
GOV_PID=$!
}
stop_gov() { # graceful
kill -TERM "$GOV_PID" 2>/dev/null || true
wait "$GOV_PID" 2>/dev/null || true
}
timeline() { awk '$2=="TRANSITION"{f="";t="";for(i=3;i<=NF;i++){if($i~/^from=/){sub("from=","",$i);f=$i}if($i~/^to=/){sub("to=","",$i);t=$i}}print f"->"t}' "$LOG"; }
cleanup() { stop_gov; rm -rf "$TMP"; }
trap cleanup EXIT
# --- Setup: healthy fixture -------------------------------------------------
write_pressure 0 0
start_gov
sleep 0.6
# --- Tolerance: transient ENOENT + truncated 'some'-only file --------------
rm -f "$CGROUP/io.pressure"
printf 'some avg10=0.00\n' >"$CGROUP/cpu.pressure" # truncated: no avg60
printf 'not a psi line\n' >"$CGROUP/memory.pressure" # garbage
sleep 0.6
kill -0 "$GOV_PID" 2>/dev/null || fail "governor died on malformed input"
write_pressure 0 0
sleep 0.4
[ -s "$LOG" ] && [ ! -s "$OUT" ] || true
if [ -n "$(timeline)" ]; then fail "tolerance window produced spurious transitions"; fi
pass "tolerates ENOENT, truncated and malformed PSI files"
# --- Enter THROTTLED --------------------------------------------------------
write_pressure 40 40
sleep 0.6
[ "$(timeline)" = "HEALTHY->THROTTLED" ] \
|| fail "expected single HEALTHY->THROTTLED, got: $(timeline | tr '\n' ',')"
pass "entered THROTTLED on avg10 > high"
# --- Start dwell, then kill mid-dwell and restart ---------------------------
write_pressure 1 1
sleep 0.8 # stay < LOW; dwell clock running (DWELL=3)
grep -q ' DWELL ' "$LOG" || fail "dwell marker not written"
stop_gov
grep -q ' FINAL ' "$LOG" || fail "SIGTERM did not flush final record"
[ -e "$PIDFILE" ] && fail "pidfile left behind after SIGTERM"
pass "SIGTERM flushed FINAL record and released pidfile"
# Restart: state and dwell progress must be recovered from the log.
: >"$OUT"
start_gov
sleep 0.6
[ "$(timeline | tail -1)" = "HEALTHY->THROTTLED" ] \
|| fail "restart re-fired a transition: $(timeline | tr '\n' ',')"
pass "restart mid-dwell did not re-fire a transition"
# Wait out the remainder of the dwell window.
sleep 4.5
stop_gov
# --- Assert exact timeline, no duplicates -----------------------------------
EXPECTED=$'HEALTHY->THROTTLED\nTHROTTLED->HEALTHY'
ACTUAL=$(timeline)
[ "$ACTUAL" = "$EXPECTED" ] || fail "timeline mismatch; expected [$EXPECTED] got [$ACTUAL]"
[ "$(printf '%s\n' "$ACTUAL" | grep -c '^HEALTHY->THROTTLED$')" -eq 1 ] || fail "duplicated entry transition"
[ "$(printf '%s\n' "$ACTUAL" | grep -c '^THROTTLED->HEALTHY$')" -eq 1 ] || fail "duplicated exit transition"
pass "exact transition timeline with no duplicates across kill/restart"
# --- Dwell reset when avg60 climbs back above LOW ---------------------------
: >"$LOG"
write_pressure 0 0
start_gov
sleep 0.4
write_pressure 40 40 # enter THROTTLED
sleep 0.6
write_pressure 1 1 # start dwell
sleep 0.8
grep -q ' DWELL ' "$LOG" || fail "dwell marker not written (reset phase)"
write_pressure 1 20 # avg10 low but avg60 > LOW -> abort dwell
sleep 0.6
grep -q ' DWELL_RESET ' "$LOG" || fail "dwell was not reset when avg60 rose above LOW"
write_pressure 0 0 # avg window reset to 0 -> legitimate low sample
sleep 4.5
stop_gov
EXPECTED2=$'HEALTHY->THROTTLED\nTHROTTLED->HEALTHY'
ACTUAL2=$(timeline)
[ "$ACTUAL2" = "$EXPECTED2" ] || fail "reset-phase timeline mismatch: [$ACTUAL2]"
pass "dwell resets on avg60 > LOW and avg reset to 0 is treated as low"
# --- Stale-owner lock reclamation ------------------------------------------
printf '999999\n' >"$PIDFILE" # dead pid
: >"$LOG"
write_pressure 0 0
start_gov
sleep 0.5
kill -0 "$GOV_PID" 2>/dev/null || fail "refused to reclaim stale pidfile"
stop_gov
[ -e "$PIDFILE" ] && fail "pidfile left after clean exit"
pass "reclaimed stale owner and released lock on exit"
echo "ALL TESTS PASSED"
chmod +x psi-governor.sh test-psi-governor.sh
./test-psi-governor.sh
Observed output (reproduced across repeated runs):
PASS: tolerates ENOENT, truncated and malformed PSI files
PASS: entered THROTTLED on avg10 > high
PASS: SIGTERM flushed FINAL record and released pidfile
PASS: restart mid-dwell did not re-fire a transition
PASS: exact transition timeline with no duplicates across kill/restart
PASS: dwell resets on avg60 > LOW and avg reset to 0 is treated as low
PASS: reclaimed stale owner and released lock on exit
ALL TESTS PASSED
What each assertion proves:
io.pressure removed, cpu.pressure truncated to a some-only line (no avg60), and memory.pressure garbage, the governor stays alive and emits no spurious transitions.HEALTHY->THROTTLED.SIGTERM produces FINAL and the pidfile is gone.HEALTHY->THROTTLED, THROTTLED->HEALTHY, each once, despite a kill/restart mid-dwell.avg60 rise writes DWELL_RESET; a subsequent avg60=0 is accepted and a single exit transition fires.The fix is a small, dependency-free bash governor built on three ideas: asymmetric hysteresis (avg10 to enter, avg60 + dwell to leave), defensive sampling (token-presence parsing, hold-not-clear on missing data), and durable, replayable state (append-only log with explicit DWELL/DWELL_RESET markers plus a SIGTERM/stale-lock protocol). The synthetic-fixture harness exercises every failure mode and asserts the exact transition timeline, including across a kill/restart in the middle of a dwell window.
# Evidence - Problem class: bash-cgroup-v2-psi-pressure-hysteresis-governor - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-11T16:05:28.716Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Implement a bash monitor that samples cgroup v2 PSI files (cpu.pressure, memory.pressure, io.pressure) for a target cgroup and drives a two-threshold hysteresis state machine: enter THROTTLED when avg10 exceeds the high watermark, and return to HEALTHY only after avg60 has stayed below the low watermark for a full dwell window, so a single noisy sample can never cause an oscillation. The script must tolerate truncated or partial reads (a pressure file with only the 'some' line, a transient ENOENT while a cgroup is being reclaim-renamed, an avg window reset to 0), recover in-progress state from its append-only transition log so a restart mid-dwell does not re-fire a transition, and on SIGTERM flush a final transition record and release its lock without leaving a stale owner. Verify with a synthetic fixture cgroup tree that you rewrite between polls, asserting the exact emitted transition timeline plus no duplicated transitions across a kill/restart cycle performed in the middle of a dwell window.", "environment": "bash", "language": "shell", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "bash-cgroup-v2-psi-pressure-hysteresis-governor", "provider": "openrouter", "solved_at": "2026-09-11T16:05:28.716Z", "version": "5.2"}