1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
|
#!/usr/bin/perl
#-------------------------------------------------------------------------------
# Simple queue management program
# Attempts to keep 'numProc' processes running at the same time
#
# Proceses are defined in a file (one line per process)
#
# Every executed process creates two files: 'pid.stdout' and 'pid.stderr' where
# pid is the process ID. The files contain STDOUT and STDERR for that process.
#
# Pablo Cingolani
#-------------------------------------------------------------------------------
use strict;
use POSIX;
my($uptimeCmd) = "/usr/bin/uptime"; # Uptime command
my($maxUptime);
$| = 1; # Don't use buffers for STDIN/STDOUT
#-------------------------------------------------------------------------------
# Should a new process be run?
# Check some conditions before trying to run the next process
#-------------------------------------------------------------------------------
sub shouldRun() {
if( $maxUptime < 0 ) { return 1; } # Always true if $maxUptime is negative
my($utRes) = `$uptimeCmd`;
my($ut) = 0;
if( $utRes =~ /load average:\s+(\d+\.\d+),/ ) { $ut = $1; }
return $ut < $maxUptime;
}
#-------------------------------------------------------------------------------
# Print something 'printLog' style
#-------------------------------------------------------------------------------
sub printLog($) {
my($str) = @_;
my($now) = strftime "%Y-%m-%d %H:%M:%S", localtime;
print "$now\t$str\n";
}
#-------------------------------------------------------------------------------
# Main
#-------------------------------------------------------------------------------
# Usage: queue numProc File
my($maxNumProc, $sleepTime, $file);
($maxNumProc, $maxUptime, $sleepTime, $file) = @ARGV;
if( $file eq '' ) {
print "Usage: queue.pl maxNumProc maxUptime sleepTime file\n";
print "Where:\n";
print "\tnumProc Number of simultaneous processes\n";
print "\tmaxUptime Maximum allowed uptime (otherwise, pause before launching the next process). Negative means don't care.\n";
print "\tsleepTime Number of seconds to sleep after running a process (zero means no sleep)\n";
print "\tfile File containing all commands to be executed (one per line)\n";
exit(10);
}
#---
# Read file and launch processes
#---
my($cmd);
my($startTime) = time();
my($numProc) = 0;
open BATCH, $file;
while( $cmd = <BATCH> ) {
chomp $cmd;
# Can we launch more processes?
if( $numProc < $maxNumProc ) {
my( $run ) = 0;
do {
# Should the next process run now? (don't run if CPU is too high)
if( shouldRun() ) {
my $retFork = fork();
$run = 1;
if( $retFork == 0 ) { # Child process
# Redirect STDOUT and STDERR to files
open STDOUT, '>', "$$.stdout" or die "Can't redirect STDOUT (PID=$$): $!";
open STDERR, '>', "$$.stderr" or die "Can't redirect STDERR (PID=$$): $!";
exec($cmd);
} elsif ($retFork == '' ) { # Error launching process
print STDERR "Error launching process:\t'$cmd'\n";
} else {
printLog("Executing (PID=$retFork):\t'$cmd'");
$numProc++;
}
} else { printLog("No running"); }
# Sleep before next process
if( $sleepTime > 0 ) {
printLog "Sleep $sleepTime seconds";
sleep($sleepTime);
}
} while( ! $run );
}
# Number of processes exceded? => Wait until one finishes
if( $numProc >= $maxNumProc ) {
# Wait for processes to die
my $deadPid = wait();
printLog "Process PID=$deadPid finished.";
$numProc--;
if( $numProc > 0 ) { print "There " . ($numProc > 1 ? "are" : "is" ) . " still $numProc processes running.\n"; }
}
}
#---
# Done, wait for the remining processes to die
#---
my($deadPid);
while( ($deadPid = wait()) >= 0 ) { # Wait for processes to die
$numProc--;
my($now) = localtime();
printLog "Process PID=$deadPid finished.";
if( $numProc > 0 ) { print "There " . ($numProc > 1 ? "are" : "is" ) . " still $numProc processes running.\n"; }
}
my($elapsed) = time() - $startTime;
print "All processes finished.\nElapsed time $elapsed seconds.\n";
close BATCH;
|