#!/bin/sh
# repro-subsched-starve.sh - reproduction for the sub-scheduler
# attach-claim starvation report.
#
# Needs: >=4 CPUs, cgroup2 mounted at /sys/fs/cgroup, sched_ext cid-form
# kernel. Run from tools/sched_ext after building scx_k2 and
# scx_perfprobe (see mail). Root required.
#
# Usage: sh repro-subsched-starve.sh [before|after] [hog]
#   before: move the busy-loop task into the cgroup BEFORE the child
#           attaches (the starved configuration, order (a) in the mail)
#   after : move it AFTER the child attaches (order (b), not starved)
#   hog   : 1 = also run a root-owned busy task on cpu2 (raises the
#           failure rate to ~100%)
set -e
ORDER=${1:-before}
HOG=${2:-0}
CG=/sys/fs/cgroup

echo "+cpu" > $CG/cgroup.subtree_control
mkdir -p $CG/ss/a

./scx_perfprobe > perfprobe.log 2>&1 &
PP=$!
./scx_k2 -g $CG/ss/a > root.log 2>&1 &
RP=$!
sleep 2

taskset 0x1 sh -c 'while :; do :; done' &
SPIN=$!
if [ "$ORDER" = before ]; then
	echo $SPIN > $CG/ss/a/cgroup.procs
	echo "[repro] spinner $SPIN moved into ss/a BEFORE child attach"
fi
if [ "$HOG" = 1 ]; then
	taskset 0x4 sh -c 'while :; do :; done' &
	HOGPID=$!
	echo "[repro] root-owned hog $HOGPID on cpu2"
fi

./scx_k2 -s $CG/ss/a > sub.log 2>&1 &
SP=$!
sleep 2
if [ "$ORDER" = after ]; then
	echo $SPIN > $CG/ss/a/cgroup.procs
	echo "[repro] spinner $SPIN moved into ss/a AFTER child attach"
fi

T0=$(awk '{print $14+$15}' /proc/$SPIN/stat)
sleep 6
T1=$(awk '{print $14+$15}' /proc/$SPIN/stat)

echo "[repro] spinner utime+stime over the 6s window: $((T1 - T0)) (of ~600, USER_HZ)"
echo "[repro] --- root.log counters (last 3 lines) ---"
tail -3 root.log
echo "[repro] --- sub.log counters (last 3 lines) ---"
tail -3 sub.log
if [ "$ORDER" = before ]; then
	echo "[repro] expected: spinner ~0-90 (starved, usually 0; healthy is ~600), setcnt bursts then freezes,"
	echo "[repro]          subdisp0=0 (the child's ops.dispatch never runs for cid0)"
else
	echo "[repro] expected: spinner ~600, setcnt ~6000"
fi

kill $RP $SP $PP $SPIN 2>/dev/null || true
[ -n "$HOGPID" ] && kill $HOGPID 2>/dev/null || true
rmdir $CG/ss/a 2>/dev/null || true
sleep 1
