#!/usr/bin/perl -wT # # ctrl_athcool.pl # Version: 1.0.2 25-FEB-2008 # Author: David Mathog, Biology Division, Caltech # Contact: mathog@caltech.edu # Copyright: 2007, David Mathog and Caltech # # This procedure keeps on eye on how busy the system is and # toggles athcool on or off. If the system is busy, it turns it # off, and if it is slow it turns it on. This enables power saving # on a more or less idle system, without sacrificing (much) performance when # the system is busy. # # It looks ONLY at the idle time in /proc/stat. The higher that value per # second the more idle the system is, the lower that value per second, the more # busy the system is. Start this as a daemon when athcool starts. # # v1.0.2 fixed bug # v1.0.1 added support for toggling athcool on heavy network load # v1.0.0 first version # # Parameters are: # None, values are hardwired in here # ##################################################################### # License terms: # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #################################################################### use strict; #################################################################### # site specific values, modify to fit your site!!!! # delete @ENV{'ENV', 'BASH_ENV'}; #or -T complains $ENV{PATH} = '/bin:/usr/bin:/usr/local/bin'; my $STATFILE = '/proc/stat'; my $NETFILE = '/proc/net/dev'; my $ATHCOOL = '/usr/sbin/athcool'; my $INTERVAL = 1; # time sampling interval in seconds my $IDLE_DOWN = 50; # threshold for idle measurement going down (indicates an idle -> busy system) my $IDLE_UP = 70; # threshold for idle measurement going up (indicates a busy -> idle system) my $DELTAP_DOWN = 1000; # threshold for packet rate measurement going down (indicates a busy -> idle system) my $DELTAP_UP = 2000; # threshold for idle measurement going up (indicates an idle -> busy system) my $DELAY_OFF = 0; # seconds it must be busy (below IDLE_DOWN or above DELTAP_UP) before turning athcool off my $DELAY_ON = 3; # seconds it must be idle (above IDLE_UP AND DELTAP_DOWN) before turning athcool on #################################################################### # # Do not modify anything below this point # my $lastidle=0; #idle time info from last interval my $lastp=0; #sum packets my $idle=0; #cumulative idle time my $packets=0; my $deltap=0; my $idif; #idle time info from this interval 0 = busy, 100 is all idle, may read 101 my $line; my @chunks; my $discard_text; my $count_off = $DELAY_OFF; my $count_on = $DELAY_ON; # start athcool (script must know what state athcool is in, harmless if athcool is already running) my $athcool_state = 1; $discard_text= `$ATHCOOL on`; while (1) { open (SFILE, "<$STATFILE") or die; $line = ; close(SFILE); @chunks = split(" ",$line); #0 is "CPU" string $idle = $chunks[4]; #Time in idle state open (SFILE, "<$NETFILE") or die; while(){ $line = ; if($line =~ m/eth0/){ @chunks = split(" ",$line); #0 is "ETH0" string $packets = $chunks[1] + $chunks[9]; #Time in idle state $deltap = $packets - $lastp; #garbage on first cycle, but not used on first cycle $lastp = $packets; } } close(SFILE); if($lastidle == 0){ $lastidle = $idle; # and don't shift anything } else { $idif = $idle - $lastidle; # fraction of time idle 0 to 100 (more or less) $lastidle = $idle; # print "DEBUG idif $idif deltap $deltap DELTAP_UP $DELTAP_UP DELTAP_DOWN $DELTAP_DOWN count_on $count_on count_off $count_off\n"; if(($idif <= $IDLE_DOWN) || ($deltap >= $DELTAP_UP)){ $count_on = $DELAY_ON; $count_off -= 1; if($count_off <= 0){ $count_off = 0; if($athcool_state == 1){ # print "DEBUG athcool off\n"; $discard_text= `$ATHCOOL off`; $athcool_state = 0; } } } elsif( ($idif >= $IDLE_UP) && ($deltap <= $DELTAP_DOWN) ){ $count_on -= 1; $count_off = $DELAY_OFF; if($count_on <= 0){ $count_on= 0; if($athcool_state == 0){ # print "DEBUG athcool on\n"; $discard_text= `$ATHCOOL on`; $athcool_state = 1; } } } else { $count_on = $DELAY_ON; $count_off = $DELAY_OFF; } } sleep(1); } exit;