#!/bin/bash

. get_root
sched 1 $$

# TODO detect high CPU usage
# TODO detect disk nearly full, stop processes that are writing fast

# TODO this would work better if it looked for processes that are growing,
# rather than just stopping the biggest ones.

sleep=0.5
emergency_sleep=0.1

# low water marks

base_RealFreeLWM=150000
base_SwapFreeLWM=3000000

delta_LWM=10000

RealFreeLWM=$base_RealFreeLWM
SwapFreeLWM=$base_SwapFreeLWM

cd /proc

# FIXME this will only stop a single large process, not a collection of smaller
# processes that add up to a large amount

stop_biggest() {
	if [ "$1" = "ram" ]; then
		col=6
	else
		col=5
	fi
	chvt 1 &
	for L in `ps aux | tail -n +2 | awk '{print $2" "$'$col'}' | sort -k2,2rn | awk '{print "P="$1";S="$2}'`; do
		eval "$L"
		if [ -z `eval echo \\\$stopped_$P` ]; then
			break
		fi
	done
	kill -STOP $P
	echo >&2 "$P is using $S kB - stopped"
	echo "`ps u -p $P`"
	eval stopped_$P=1
	sleep=$emergency_sleep
}

while true; do
	eval `</proc/meminfo sed 's/: */=/; s/ kB$//'`
	RealFree=$[$MemFree + $Buffers + $Cached]
	if [ "$RealFree" -lt "$RealFreeLWM" ]; then
		echo >&2 "RAM low: $RealFree"
		stop_biggest ram
		RealFreeLWM=$[RealFree - $delta_LWM ]
		echo "$RealFree > $RealFreeLWM"
	elif [ "$SwapFree" -lt "$SwapFreeLWM" ]; then
		echo >&2 "Swap low: $SwapFree"
		stop_biggest swap
		SwapFreeLWM=$[SwapFree - $delta_LWM ]
		echo "$SwapFree > $SwapFreeLWM"
	fi
	sleep $sleep
done

#MemTotal:      1552696 kB
#MemFree:       1215472 kB
#Buffers:          9048 kB
#Cached:         188932 kB
#SwapCached:      21628 kB
#Active:         120756 kB
#Inactive:       140792 kB
#HighTotal:      655040 kB
#HighFree:       439704 kB
#LowTotal:       897656 kB
#LowFree:        775768 kB
#SwapTotal:     4104564 kB
#SwapFree:      4005876 kB
#Dirty:             172 kB
#Writeback:           0 kB
#AnonPages:       56508 kB
#Mapped:          23244 kB
#Slab:            34060 kB
#SReclaimable:    10940 kB
#SUnreclaim:      23120 kB
#PageTables:       3164 kB
#NFS_Unstable:        0 kB
#Bounce:              0 kB
#WritebackTmp:        0 kB
#CommitLimit:   4880912 kB
#Committed_AS:   589416 kB
#VmallocTotal:   114680 kB
#VmallocUsed:     55608 kB
#VmallocChunk:    57328 kB
#HugePages_Total:     0
#HugePages_Free:      0
#HugePages_Rsvd:      0
#HugePages_Surp:      0
#Hugepagesize:     2048 kB
#DirectMap4k:     77824 kB
#DirectMap2M:    839680 kB
