From 0776e89d26c8a71340d04d9c1cb36f06e970767f Mon Sep 17 00:00:00 2001 From: Hyperling Date: Sat, 10 Oct 2026 18:41:25 -0700 Subject: [PATCH] Add shell script which stops LLMs from causing system swap. --- files/scripts/llm_swap_stopper.sh | 84 +++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100755 files/scripts/llm_swap_stopper.sh diff --git a/files/scripts/llm_swap_stopper.sh b/files/scripts/llm_swap_stopper.sh new file mode 100755 index 0000000..9c64ac9 --- /dev/null +++ b/files/scripts/llm_swap_stopper.sh @@ -0,0 +1,84 @@ +#!/bin/sh -e +# 2026-10-10 Hyperling +# Stop a system from going into swap due to LLMs. + +### Tuning ### + +typeset -i sleep=10 ram_pct_restart=98 + +### Functions ### + +restart_service() { + if [ -z $1 ]; then + echo "ERROR: Service name must be passed to restart_service()." + return 1 + fi + sv restart $1 || echo "$1 failed to restart, ignoring." +} + +# While we could loop over `ollama ps` and stop them, this ensures that the UIs +# do not sit around waiting for responses from the dead LLMs. It bring them up +# in a fresh state so that work can continue from a more clean slate. +restart_llms() { + restart_service ollama + restart_service zeroclaw + restart_service open-webui +} + +### Main ### + +typeset -i {total,used}_{ram,swap}=0 \ + used_{ram,swap}_pct=0 \ + last_{ram,swap}_pct=100 \ + count=0 + +while [[ true ]]; do + + count=$(expr $count + 1 ) + echo "$(date +'%Y-%m-%d @ %H:%M:%S') - Loop $count" + + # RAM # + + total_ram=$(free | awk '/^Mem:/ {print $2}') + used_ram=$(free | awk '/^Mem:/ {print $3}') + used_ram_pct=$( \ + awk -v used="$used_ram" -v total="$total_ram" \ + 'BEGIN {printf "%d",(used/total)*100}' \ + ) + + echo "Current RAM usage is $used_ram_pct%, was $last_ram_pct% last loop." + + # Check if RAM is over 95% + if [ $used_ram_pct -gt $ram_pct_restart ]; then + echo "WARNING: RAM is over ${ram_pct_restart}% used. Restarting LLMs." + restart_llms + continue + fi + + # Swap # + + total_swap=$(free | awk '/^Swap:/ {print $2}') + used_swap=$(free | awk '/^Swap:/ {print $3}') + used_swap_pct=$( \ + awk -v used="$used_swap" -v total="$total_swap" \ + 'BEGIN {printf "%d",(used/total)*100}' \ + ) + + echo "Current swap usage is $used_swap_pct%, was $last_swap_pct% last loop." + + # Check if swap is growing + if [ $used_swap_pct -gt $last_swap_pct ]; then + echo "WARNING: Swap is growing. Restarting LLMs." + restart_llms + continue + fi + + # Finish # + + echo -e "Check finished, sleeping for ${sleep}...\n" + + last_ram_pct=$used_ram_pct + last_swap_pct=$used_swap_pct + + sleep $sleep +done