#!/usr/bin/perl -w # Calculate estimated render times # Shows how long a job will take, given a specific number of dedicated cpus # # calc-render-time -- Copyright (C) 2006 Greg Ercolano. # This script is released under the GPL Version 2. Keep the copyright notice intact. # This script comes with ABSOLUTELY NO WARRANTY; for details see the GPL Version 2. # Please report bugs / send patches to: erco(at)seriss(period)com. # $ |= 1; use strict; require "ctime.pl"; # GET JOBS REPORT # $1 - jobid # $2 - REFERENCE: %frameinfo hash # $3 - REFERENCE: error message array # sub LoadFrameInfo($$$) { my ($jobid, $frameinfo, $errors) = @_; # EXAMPLE 'rush -lfi' REPORT: # # Average Total # Jobid State Total Perc Elapsed Elapsed Average ETA # ---------------- ----- ----- ---- ---------- ---------- ------------------------ # ontario.1 Que 0 %0 - - - # ontario.1 Run 0 %0 - - - # ontario.1 Done 88 %88 00:00:09 00:13:35 Tue Oct 24 14:34:13 2006 # ontario.1 Fail 12 %12 00:00:13 00:02:39 - # ontario.1 Hold 0 %0 - - - # .. # GET CPU INFO my $cmd = "rush -lfi $jobid"; unless ( open(LFI, "$cmd 2>&1|") ) { print STDERR "$0: '$cmd': $!\n"; exit(1); } while ( ) { chomp($_); # print "Working on: '$_'\n"; if ( /^Jobid/ || /^---/ || /^ / ) { next; } # skip headers if ( /^rush:/ || /^\*\*\*/ ) { push(@{$errors}, $_); next; } # errors # PARSE AVERAGE ELAPSED if ( /\S+\s+Done\s+\S+\s+\S+\s+(\S+)/ ) { $$frameinfo{AverageElapsed} = $1; } # PARSE OTHER FIELDS if ( /\S+\s+(Que|Run|Done|Fail|Hold)\s+(\d+)/ ) { $$frameinfo{$1} = $2; } } close(LFI); } # CONVERT HH:MM:SS TO SECONDS # Handles MM:SS and just SS as well. # sub HMS2Secs($) { if ( $_[0] =~ /^(\d+):(\d+):(\d+)$/ ) { return($1 * 3600 + $2 * 60 + $3); } if ( $_[0] =~ /^(\d+):(\d+)$/ ) { return($1 * 60 + $2); } if ( $_[0] =~ /^(\d+)$/ ) { return($1); } return(0); } # CONVERT SECONDS TO PADDED HH:MM:SS STRING sub Secs2HMS($) { my $secs = $_[0]; my $h = int($secs / 3600); my $m = int(($secs - ($h * 3600)) / 60); my $s = $secs % 60; return(sprintf("%02d:%02d:%02d",$h,$m,$s)); } ### ### MAIN ### { my $jobid = $ARGV[0]; if ( ! defined($jobid) ) { print STDERR "Usage: $0 [HH:MM:SS]\n". "Where:\n". " jobid is the jobid of the job to show render calculations for\n". " HH:MM:SS is the estimated per-frame render time in HH:MM:SS\n". "\n". "Examples:\n". " $0 tahoe.34 -- Show info for tahoe.34 using 'AverageElapsed' from 'Frame Info' report\n". " $0 tahoe.34 00:05:00 -- Show info for tahoe.34 using 05:00 as estimated per-frame render time\n". "\n"; exit(1); } # LOAD FRAME INFO REPORT my (%frames, @errors); LoadFrameInfo($jobid, \%frames, \@errors); # ERRORS IF ANY if ( $#errors >= 0 ) { foreach ( @errors ) { print STDERR "$_\n"; } exit(1); } # PER-FRAME RENDER TIME OVERRIDE FROM USER if ( defined($ARGV[1]) ) { $frames{AverageElapsed} = $ARGV[1]; } # SANITY if ( ! defined $frames{AverageElapsed} || $frames{AverageElapsed} eq "-" ) { print "ERROR: $jobid has no completed frames, must specify estimated per-frame render time\n"; exit(1); } # PARSE SECONDS-PER-FRAME my $secsperframe = HMS2Secs($frames{AverageElapsed}); # RENDER TIME CALCULATION print "#Cpus Estimated Completion\n". "----- ----------------------------------\n"; if ( $frames{Que} == 0 ) { print "(This job is already done.)\n"; exit(0); } my $lastblks = 0; for ( my $cpus = 1; $cpus <= 200 && $cpus <= $frames{Que}; $cpus ++ ) { my $blks = $frames{Que} / $cpus; # number of blocks of cpus if ( $blks != int($blks) ) { $blks = int($blks) + 1; } # ceil() if ( $blks == $lastblks ) { next; } $lastblks = $blks; my $secs = $blks * $secsperframe; my $hms = Secs2HMS($secs); my $eta = ctime(time() + $secs); $eta =~ s/\n//; printf("%-5d %s (%s)\n", $cpus, $hms, $eta); } exit(0); }