3 # version 1.1, 05.12.2005, Hauke Laging, http://www.hauke-laging.de/software/
4 # slightly edited by Jan Mette, spam-o-mat at nickname.berlin.de
5 # This software is licensed under the Gnu GPL, see http://www.fsf.org/
7 # This script has the task to prevent I/O intensive system processes from
8 # annoying the user by slowing the system down. These typical administrative
9 # processes are not required to complete within a short time so it makes sense
10 # to reduce the I/O priority of these tasks (which usually impacts the performance
11 # of user processes much more than the CPU proirity).
13 # This script does not affect processes which have been niced to a value below zero
14 # (higher priority) or already ioniced (to any value).
15 # This is the most simple way to prevent a process from being affected by this script.
16 # You can configure if a white list or black list approach is used: Either only the
17 # configured programs are affected or only those not.
19 # The script runs as a daemon and reads the current PID list from ps every few
20 # seconds. It cannot (or at least does not) prevent tasks from starting with
21 # high I/O priority (high := high enough to annoy) but this problem es solved
22 # after a few seconds.
24 # Thus this script should be started in the background. It writes to STDOUT what
27 # This script requires kernel 2.6.13 or above and the availability of ionice.
31 # USR1: The current list of known processes and their I/O priotity change status
32 # is dumped into the file $dump_file. Values 1,2 and 3 represent set priorities
33 # whereas 0 represents an unchanged priority.
35 @args = ("/bin/bash","-c","type ionice");
39 print "The program 'ionice' is not available; aborting.\n";
50 $syslog_tag="ioniced.pl";
54 $leave_inid_pids_untouched=0;
56 $dump_file="/tmp/ioniced.dump";
57 %known_pids = (); # Werte: 1,2,3 fuer die gesetzten, 0 fuer die unveraenderten
60 # processes that should be skipped
62 %skip_these = ("init"=>0,"ps"=>0,"sshd"=>0,"syslog-ng"=>0,"httpd2-prefork"=>0,"pdflush"=>0); # values: dummys
65 # processes that should be ioniced
67 %ionice_these = (find
=>3,tar
=>3,updatedb
=>3,mandb
=>3,cp
=>3,mv
=>3,rpm
=>3,gzip
=>3,kio_file
=>3); # values: new I/O priority level
71 ############ DO NOT EDIT BELOW THIS LINE ############
74 if (not open(FH
,"> $dump_file"))
78 foreach (keys %known_pids)
80 print FH
$_," ",$known_pids{$_},"\n";
85 $SIG{USR1
}="dump_ioprios";
87 # BEGIN: initialize the hash with the present pids
88 @pslines = qx/ps -eo pid,ruid,nice,comm/;
93 next if $i == 1; # header line pf ps output
96 @elements = split(" +",$_);
100 $command=$elements[3];
102 $change_it=0 if ($leave_inid_pids_untouched);
103 $change_it=0 if ($ruid>=$min_user_id && $ruid<=$max_user_id);
104 $change_it=0 if ($nice<0);
105 $change_it=0 if (exists($skip_these{$command}));
106 if ($change_it) # execute this one conditionally only because it takes time
108 $ionice_status=qx/ionice -p $pid/;
109 $ionice_status =~ s/:.*$//;
110 $change_it=0 if ($ionice_status != "none");
114 $change_it=0 unless (exists($ionice_these{$command}));
119 $explicit_io_class=$ionice_these{$command};
120 if ($whitelist && defined($explicit_io_class) && ($explicit_io_class eq 1 || $explicit_io_class eq 2 || $explicit_io_class eq 3))
122 $io_class=$explicit_io_class;
124 $known_pids{$pid}=$io_class;
125 system("ionice -c${io_class} -p${pid}");
126 print "PID ${pid} ($command) has been changed to I/O class ${io_class}.\n";
129 system("logger -t \"${syslog_tag}\" \"PID ${pid} ($command) has been changed to I/O class ${io_class}.\"");
135 print "PID ${pid}'s ($command) I/O class has not been changed.\n"
138 print "Initialization finished.\n";
139 # END: initialize the hash with the present pids
144 print "\n\nChecking for new PIDs:\n";
145 @pslines = qx/ps -eo pid,ruid,nice,comm/;
147 %current_pids=(); # Werte: Dummys
151 next if $i == 1; # header line pf ps output
154 @elements = split(" +",$_);
158 $command=$elements[3];
159 $current_pids{$pid}=0;
160 next if (exists($known_pids{$pid}));
161 next if ($command eq "ps");
163 $change_it=0 if ($ruid>=$min_user_id && $ruid<=$max_user_id);
164 $change_it=0 if ($nice<0);
165 $change_it=0 if (exists($skip_these{$command}));
166 if ($change_it) # execute this one conditionally only because it takes time
168 $ionice_status=qx/ionice -p $pid/;
169 $ionice_status =~ s/:.*$//;
170 chomp($ionice_status);
171 $change_it=0 if ($ionice_status ne "none");
175 $change_it=0 unless (exists($ionice_these{$command}));
180 $explicit_io_class=$ionice_these{$command};
181 if ($whitelist && defined($explicit_io_class) && ($explicit_io_class eq 1 || $explicit_io_class eq 2 || $explicit_io_class eq 3))
183 $io_class=$explicit_io_class;
185 $known_pids{$pid}=$io_class;
186 system("ionice -c${io_class} -p${pid}");
187 print "PID ${pid} ($command) has been changed to I/O class ${io_class}.\n";
190 system("logger -t \"${syslog_tag}\" \"PID ${pid} ($command) has been changed to I/O class ${io_class}.\"");
196 print "PID ${pid}'s ($command) I/O class has not been changed.\n"
199 print "\n\nPID check\n";
200 foreach (keys %known_pids)
202 unless (exists($current_pids{$_}))
204 delete($known_pids{$_});
205 print "PID ",$_," does not exist any more and has been deleted from the hash.\n";