Skip to content

Commit a6da470

Browse files
committed
run-with-ram has DRY_RUN
DRY_RUN skips closing anything fix pageout tracking fix receiving stdin for background job
1 parent 1d6d37c commit a6da470

1 file changed

Lines changed: 21 additions & 9 deletions

File tree

mac/run-with-ram

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#
1818
# Usage: run-with-ram <command> [args...]
1919
# Env: NOT_CURSOR=1 skip closing Cursor (so the agent doesn't kill itself while debugging)
20+
# Env: DRY_RUN=1 skip closing any apps
2021

2122
set -o errexit
2223
set -o nounset
@@ -25,6 +26,7 @@ set -o pipefail
2526
if [[ $# -lt 1 ]]; then
2627
>&2 echo "USAGE: run-with-ram <command> [args...]"
2728
>&2 echo " NOT_CURSOR=1 skip closing Cursor (for debugging)"
29+
>&2 echo " DRY_RUN=1 skip closing any apps"
2830
exit 1
2931
fi
3032

@@ -71,7 +73,7 @@ is_running() {
7173
#
7274
# Thresholds are conservative (kill the job, not the machine):
7375
# - free < 512 MB AND compressed > 8 GB → near-panic territory
74-
# - pageouts > 50000 → kernel actively evicting pages
76+
# - pageouts since watchdog start > 50000 → kernel actively evicting pages
7577
# - swap file count >= 30 → at 36 files, we got a kernel panic last time
7678
WATCHDOG_PID=""
7779

@@ -82,15 +84,21 @@ start_watchdog() {
8284
# swap files, vm_stat hiccups) must not kill the monitoring loop.
8385
set +o errexit
8486
set +o pipefail
87+
88+
# vm_stat Pageouts is cumulative since boot; track delta from watchdog start.
89+
local baseline_pageouts
90+
baseline_pageouts=$(awk '/Pageouts/{gsub(/\./,"",$2); print $2}' <<< "$(vm_stat)")
91+
8592
while kill -0 "$child_pid" 2>/dev/null; do
8693
local vm_output
8794
vm_output=$(vm_stat)
8895

8996
# Page size on Apple Silicon is 16384 bytes
90-
local pages_free pages_compressed pageouts
97+
local pages_free pages_compressed pageouts pageouts_since_start
9198
pages_free=$(awk '/Pages free/{gsub(/\./,"",$3); print $3}' <<< "$vm_output")
9299
pages_compressed=$(awk '/Pages stored in compressor/{gsub(/\./,"",$5); print $5}' <<< "$vm_output")
93100
pageouts=$(awk '/Pageouts/{gsub(/\./,"",$2); print $2}' <<< "$vm_output")
101+
pageouts_since_start=$(( pageouts - baseline_pageouts ))
94102

95103
local free_mb=$(( pages_free * 16384 / 1024 / 1024 ))
96104
local compressed_mb=$(( pages_compressed * 16384 / 1024 / 1024 ))
@@ -101,13 +109,13 @@ start_watchdog() {
101109

102110
local timestamp
103111
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
104-
echo "$timestamp free=${free_mb}MB compressed=${compressed_mb}MB pageouts=$pageouts swapfiles=$swap_count" >> "$LOG_FILE"
112+
echo "$timestamp free=${free_mb}MB compressed=${compressed_mb}MB pageouts_since_start=$pageouts_since_start swapfiles=$swap_count" >> "$LOG_FILE"
105113

106114
local kill_reason=""
107115
if [[ $free_mb -lt 512 && $compressed_mb -gt 8192 ]]; then
108116
kill_reason="free=${free_mb}MB < 512MB AND compressed=${compressed_mb}MB > 8GB"
109-
elif [[ $pageouts -gt 50000 ]]; then
110-
kill_reason="pageouts=$pageouts > 50000"
117+
elif [[ $pageouts_since_start -gt 50000 ]]; then
118+
kill_reason="pageouts_since_start=$pageouts_since_start > 50000"
111119
elif [[ $swap_count -ge 30 ]]; then
112120
kill_reason="swap_count=$swap_count >= 30 (panic happened at 36)"
113121
fi
@@ -131,28 +139,32 @@ start_watchdog() {
131139
echo "=== run-with-ram: closing apps ==="
132140
for (( i = 0; i < ${#APP_NAMES[@]}; i++ )); do
133141
name="${APP_NAMES[$i]}"
134-
if is_running "$name"; then
142+
if is_running "$name" && [[ -z "${DRY_RUN:-}" ]]; then
135143
WAS_RUNNING_INDICES="$WAS_RUNNING_INDICES $i"
136144
echo " Quitting $name..."
137145
osascript -e "tell application \"$name\" to quit" 2>/dev/null || true
138146
# Some Electron apps (Teams, Discord) ignore AppleScript quit; pkill as fallback
139-
sleep 1
147+
sleep 0.1
140148
if is_running "$name"; then
141149
pkill -f "$name" 2>/dev/null || true
142150
fi
143151
fi
144152
done
145153

146154
# Give Electron apps a moment to flush state before we eat all the RAM
147-
sleep 2
155+
if [[ -z "${DRY_RUN:-}" ]]; then
156+
sleep 2
157+
fi
148158

149159
# ── Run command ───────────────────────────────────────────────────────────────
150160
echo "=== run-with-ram: starting: $* ==="
151161
echo " Watchdog log: $LOG_FILE"
152162

153163
# caffeinate -i: prevent idle sleep during run
154164
# nice -n 10: deprioritizes CPU so watchdogd and kernel threads stay schedulable
155-
caffeinate -i nice -n 10 "$@" &
165+
# <&0: explicitly inherit stdin so piped input reaches the child (bash redirects
166+
# background jobs' stdin away from pipes in interactive shells)
167+
caffeinate -i nice -n 10 "$@" <&0 &
156168
CHILD_PID=$!
157169

158170
start_watchdog "$CHILD_PID"

0 commit comments

Comments
 (0)