Thanks for this. It was most helpful for my home media server ...
I had to make some changes for my needs though as your method for polling for limited PIDs was always returning null... I ended up rewriting abit but the key change was the line:
Code:LIMITED_PIDS=$(ps -eo args | gawk '$1=="cpulimit" {print $3}') ## changed to (more explaination below) ## LIMITED_PIDS=$(ps -eo args | grep cpulimited-bin |grep -v grep |awk '{print $3}')
I needed a version with start/stop built in and also wanted logging.. So my finial code which is still being tested is:
cpulimited.sh
I set a temp directory up for the script and symlinked /usr/bin/cpulimit to ./cpulimited-bin to ease in grep'ing for cpulimit processes spawned by this script. I also added the ability to set changes from a config file. The other change is that BLACKLIST/WHITELIST is a mode toggle (0/1) and PROCESS_LIST would contain the strings to act on... Most all other changes were simply stylistic.Code:#!/bin/bash # ============================================================== # CPU limit daemon - set PID's max. percentage CPU consumptions # ============================================================== # Variables CPU_LIMIT=25 # Maximum percentage CPU consumption by each PID DAEMON_INTERVAL=3 # Daemon check interval in seconds LOG=/var/log/cuplimited.log CPULIMITED_TMPDIR=/tmp/cpulimited CONFIG=/etc/cpulimited/cpulimited.conf BLACKLIST=0 WHITELIST=0 PROCESSES_LIST= do_help() { cat <<EOF Usage: $0 <options> start|stop -f :: Run in foreground -c <config file> :: Use specified config file EOF exit 0 } do_cpuwatcher() { # Search and limit violating PIDs while [ -z "$EXIT" ]; do sleep $DAEMON_INTERVAL # Check for exit DCMD=$(cat "$CONTROL_FILE" |tail -n 1) if [ "$DCMD" = "exit" ]; then echo "Shutdown requested..." PIDS="$(ps ax |grep cpulimited-bin |awk '{print $1}')" echo "Removing CPU limits ..." kill -9 $PIDS >/dev/null 2>&1 sleep 1 cd /tmp echo "Cleaning up ..." rm -rfd $CPULIMITED_TMPDIR echo "Goodbye" EXIT=1 exit 0 fi NEW_PIDS=$(eval "$NEW_PIDS_COMMAND") LIMITED_PIDS=$(ps -eo args | grep cpulimited-bin |grep -v grep |awk '{print $3}') QUEUE_PIDS=$(comm -23 <(echo "$NEW_PIDS" | sort -u) <(echo "$LIMITED_PIDS" | sort -u) | grep -v '^$') if [ -n "$QUEUE_PIDS" ]; then echo "These PIDs are already limited: $LIMITED_PIDS" echo "These PIDs are now entering the queue: $QUEUE_PIDS" fi for i in $QUEUE_PIDS; do echo "Setting limits for PID: $i" if [ -z "$FOREGROUND" ]; then ./cpulimited-bin -p $i -l $CPU_LIMIT -z >>$LOG 2>&1 & else ./cpulimited-bin -p $i -l $CPU_LIMIT -z & fi done done exit 0 } # Init ## Process commandline options while [ "$1" ]; do case "$1" in -f) FOREGROUND=1 shift 1 ;; -c) CONFIG=$2 shift 2 ;; start) CMD=start shift 1 break ;; stop) CMD=stop shift 1 break ;; *) do_help break esac done if [ -z "$CMD" ]; then do_help exit 0 fi [ -f $CONFIG ] && . $CONFIG if [ $BLACKLIST = 1 -a $WHITELIST = 1 ]; then echo "Cannot use both whitelist AND blacklist. Please check your config" exit 1 else if [ "$BLACKLIST" = "yes" ]; then MODE=blacklist NEW_PIDS_COMMAND="top -b -n1 -c | grep -E '$BLACK_PROCESSES_LIST' | gawk '\$9>CPU_LIMIT {print \$1}' CPU_LIMIT=$CPU_LIMIT" fi if [ "$WHITELIST" = "yes" ]; then MODE=whitelist NEW_PIDS_COMMAND="top -b -n1 -c | gawk 'NR>6' | grep -E -v '$WHITE_PROCESSES_LIST' | gawk '\$9>CPU_LIMIT {print \$1}' CPU_LIMIT=$CPU_LIMIT" fi if [ -z "$MODE" ]; then MODE=supervisor NEW_PIDS_COMMAND="top -b -n1 -c | gawk 'NR>6 && \$9>CPU_LIMIT {print \$1}' CPU_LIMIT=$CPU_LIMIT" fi fi ########## END Init ############ case "$CMD" in start) echo "Starting up in $MODE mode ..." if [ -d $CPULIMITED_TMPDIR ]; then echo "Already running or stale tmp directory detected. Aborting ..." exit 23 else mkdir -p $CPULIMITED_TMPDIR CONTROL_FILE="${CPULIMITED_TMPDIR}/control" chown -R root:root $CPULIMITED_TMPDIR chmod 700 $CPULIMITED_TMPDIR cd $CPULIMITED_TMPDIR CPULIMIT=$(which cpulimit) ln -s $CPULIMIT cpulimited-bin touch $CONTROL_FILE if [ -n "$FOREGROUND" ]; then # Do not fork do_cpuwatcher else # Fork into the background do_cpuwatcher >>$LOG & fi fi ;; stop) echo "Sending stop signal ..." CONTROL_FILE="${CPULIMITED_TMPDIR}/control" echo "exit" >$CONTROL_FILE ;; esac
Thanks again!
Bookmarks