#91 Renicing Tasks by Process Name

There are many times when it's useful to change the priority of a specific task, whether it's an IRC or chat server that's supposed to use only "spare" cycles, an MP3 player app or file download that has become less important, or a real-time CPU monitor being increased in priority. The renice command, however, requires you to specify the process ID, which can be a hassle. A much more useful approach is to have a script that matches process name to process ID and then renices the specified application.

The Code

#!/bin/sh

# renicename - Renices the job that matches the specified name.

user=""; tty=""; showpid=0; niceval="+1"        # initialize

while getopts "n:u:t:p" opt; do
  case $opt in
   n ) niceval="$OPTARG";               ;;
   u ) if [ ! -z "$tty" ] ; then
         echo "$0: error: -u and -t are mutually exclusive." >&2
         exit 1
       fi
       user=$OPTARG                     ;;
   t ) if [ ! -z "$user" ] ; then
         echo "$0: error: -u and -t are mutually exclusive." >&2
         exit 1
       fi
       tty=$OPTARG                      ;;
   p ) showpid=1;                       ;;
   ? ) echo "Usage: $0 [-n niceval] [-u user|-t tty] [-p] pattern" >&2
       echo "Default niceval change is "$niceval" (plus is lower" >&2
       echo "priority, minus is higher, but only root can go below 0)" >&2
       exit 1
  esac
done
shift $(($OPTIND − 1))  # eat all the parsed arguments

if [ $# -eq 0 ] ; then
  echo "Usage: $0 [-n niceval] [-u user|-t tty] [-p] pattern" >&2
  exit 1
fi

if [ ! -z "$tty" ] ; then
  pid=$(ps cu -t $tty | awk "/ $1/ { print \$2 }")
elif [ ! -z "$user" ] ; then
  pid=$(ps cu -U $user | awk "/ $1/ { print \$2 }")
else
  pid=$(ps cu -U ${USER:-LOGNAME} | awk "/ $1/ { print $2 }")
fi

if [ -z "$pid" ] ; then
  echo "$0: no processes match pattern $1" >&2 ; exit 1
elif [ ! -z "$(echo $pid | grep ' ')" ] ; then
  echo "$0: more than one process matches pattern ${1}:"
  if [ ! -z "$tty" ] ; then
    runme="ps cu -t $tty"
  elif [ ! -z "$user" ] ; then
    runme="ps cu -U $user"
  else
    runme="ps cu -U ${USER:-LOGNAME}"
  fi
  eval $runme | 
      awk "/ $1/ { printf "  user %−8.8s  pid %−6.6s  job %s
", 
      $1,$2,$11 }"
  echo "Use -u user or -t tty to narrow down your selection criteria."
elif [ $showpid -eq 1 ] ; then
  echo $pid
else
  # ready to go: let's do it!
  echo -n "Renicing job ""
  echo -n $(ps cp $pid | sed 's/ [ ]*/ /g' | tail −1 |  cut -d  -f5-)
  echo "" ($pid)"
  renice $niceval $pid
fi

exit 0

How It Works

This script borrows liberally from the earlier Script #52, Killing Processes by Name, which does a similar mapping of process name to process ID, but then kills the jobs, rather than just lowering their priority.

In this situation, you don't want to accidentally renice a number of matching processes (imagine renicename -n 10 "*", for example), so the script fails if more than one process matches the criteria. Otherwise, it makes the change specified and lets the actual renice program report any errors that may have been encountered.

Running the Script

You have a number of different possible options when running this script: -n val allows you to specify the desired nice (job priority) value. The default is specified as niceval=1. The -u user flag allows matching processes to be limited by user, while -t tty allows a similar filter by terminal name. To see just the matching process ID and not actually renice the application, use the -p flag. In addition to one or more flags, renicename requires a command pattern that will be compared to the running process names on the system to ascertain which of the processes match.

The Results

First off, here are the results when there is more than one matching process:

$ renicename "vim"
renicename: more than one process matches pattern vim:
  user taylor    pid 10581   job vim
  user taylor    pid 10949   job vim
Use -u user or -t tty to narrow down your selection criteria.

I subsequently quit one of these processes and ran the same command:

$ renicename "vim"
Renicing job "vim" (10949)
11131: old priority 0, new priority 1

We can confirm that this worked by using the -alr (or -al) flags to ps:

$ ps -alr
  UID   PID  PPID CPU PRI NI    VSZ    RSS STAT  TT     TIME COMMAND
    0   439   438   0  31  0  14048    568 Ss   std  0:00.84 login -pf taylor
  501   440   439   0  31  0   1828    756 S    std  0:00.56 -bash (bash)
    0 10577   438   0  31  0  14048    572 Ss    p2  0:00.83 login -pf taylor
  501 10578 10577   0  31  0   1828    760 S     p2  0:00.16 -bash (bash)
  501 10949 10578   0  30  1  11004   2348 SN+   p2  0:00.09 vim reniceme
    0 11152   440   0  31  0   1372    320 R+   std  0:00.01 ps -alr

Notice that the vim process (10949) has a nice value (the NI column) of 1, while everything else I'm running has a nice value of 0, the standard user priority level.

Hacking the Script

An interesting addendum to this script is another script that watches for certain programs to be launched and automatically renices them to a set priority; this can be helpful if certain Internet services or applications tend to consume most of the CPU resources, for example. The script uses renicename to map process name to process ID and then checks the process's current nice level and issues a renice if the nice level specified as a command argument is higher (a lesser priority) than the current level:

#!/bin/sh

# watch_and_nice - Watches for the specified process name, and renices it
#  to the desired value when seen.

renicename="$HOME/bin/renicename"

if [ $# -ne 2 ] ; then
  echo "Usage: $(basename $0) desirednice jobname" >&2
  exit 1
fi

pid="$($renicename -p "$2")"

if [ ! -z "$(echo $pid | sed 's/[0–9]*//g')" ] ; then
  echo "Failed to make a unique match in the process table for $2" >&2
  exit 1
fi

currentnice="$(ps -lp $pid | tail −1 | awk '{print $6}')"

if [ $1 -gt $currentnice ] ; then
  echo "Adjusting priority of $2 to $1"
  renice $1 $pid
fi

exit 0

Within a cron job, this script could be used to ensure that certain apps are pushed to the desired priority within a few minutes of being launched.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.137.240