#!/usr/bin/perl
#
# scan job execution log file from the LLNL T3D system, and use convert2swf.pm
# to convert the data into the standard workload format.
#

use warnings;
use strict;
use Time::Local;
use POSIX;
use convert2swf_v4;


############################
#
# DO THE CONVERSION:
#

my $tz_str    = "US/Pacific";
my $max_procs = 256;
my $max_nodes = 128;
my @queues    = ();

$ENV{TZ} = $tz_str;
POSIX::tzset();

SWF::init( $tz_str, $max_procs, \@queues );

my $format_bugs;
my $jobs_data = get_jobs();

my ($zero, $maxtime) = SWF::convert( $jobs_data, $format_bugs );

my $header = generate_header( $zero, $maxtime, $max_procs );

SWF::print( $header );



#################################
# SPECIFICS for LLNL T3D workload

# the input is generated by scanBj.pl from per-roll data.
# the format of each entry includes the following space-separated fields:
# 0  start date of first quantum
# 1  start time of first quantum
# 2  process ID
# 3  User
# 4  nodes
# 5  total time of all quanta
# 6  number of quanta
# 7  exit code (R=rolled out, K=killed, -=competed, S=strange[meaning last quanta ended with R instead of - or K])
# 8  job

my $job_cnt;

sub get_jobs {
##############
# parse input format and create a hash for each job

    my @list_of_jobs;

    #
    # scan trace and collect job info
    #
    while (<>) {

	#
	# parse line and extract info
	#

	if (/^\s*$/) {		# empty line
	    next;
	}

	$_ =~ /\s*(.*)\s*/;		# get rid of white space at ends
	$_ = $1;
	my @line = split('\s+');	# split into fields

	if ($#line != 8) {
	    $format_bugs .= "format_problem $_\n";
	    warn(">>>Format problem on $_\ngot $#line fields (should be 8)");
	    next;
	}

	my %nj;

	#
	# set the desired fields as specified in convert2swf.pl
	#

	$nj{trace}  = $_;	# used for error messages

	# translate human readable start date and time into time array
	my @begtmarr;
	$begtmarr[5] = 96;
	($begtmarr[4],$begtmarr[3]) = split('/',$line[0]);
	($begtmarr[2],$begtmarr[1],$begtmarr[0]) = split(':',$line[1]);
	$begtmarr[4]--;
	my $start = &timelocal(@begtmarr);

	$nj{start}  = $start;


	my $run = $line[5];

	$nj{run} = $run;


	my $procs = $line[4];

	$nj{procs} = $procs;


	# handle status values
	if (($line[7] eq "K") || ($line[7] eq "S")) {
	    $nj{status} = 0;
	}
	elsif ($line[7] eq "-") {
	    $nj{status} = 1;
	}


	$nj{user}  = $line[3];

	$nj{app} = $line[8];

	$list_of_jobs[$job_cnt++] = \%nj;
    }

    return \@list_of_jobs;
}


sub generate_header {
    my ($zero, $maxtime, $max_procs) = @_;

    my ($sec, $min, $hr, $mday, $mon, $year, $wday, $yday, $isdst);

    $header  = "; Version: 2.2\n";
    $header .= "; Computer: Cray T3D\n";
    $header .= "; Installation: Lawrence Livermore National Lab\n";

    $header .= "; Acknowledge: Moe Jette\n";
    $header .= "; Information: http://www.llnl.gov/sccd/\n";
    $header .= ";              http://www.cs.huji.ac.il/labs/parallel/workload/\n";

    $header .= sprintf("; Conversion: Dror Feitelson (feit\@cs.huji.ac.il) %s\n",
		       strftime("%d %b %Y", localtime()));


    $header .= sprintf("; MaxJobs: %d\n", $job_cnt);
    $header .= sprintf("; MaxRecords: %d\n", $job_cnt);
    $header .= "; Preemption: Yes\n";

    $header .= sprintf("; UnixStartTime: %d\n", $zero);
    $header .= "; TimeZone: -28800\n";
    $header .= sprintf("; TimeZoneString: %s\n", $tz_str);

    $header .= sprintf("; StartTime: %s\n",
	   strftime("%a %b %2d %H:%M:%S %Z %Y", localtime($zero)));

    $header .= sprintf("; EndTime:   %s\n",
	   strftime("%a %b %2d %H:%M:%S %Z %Y", localtime($maxtime)));

    $header .= "; MaxNodes: $max_nodes\n";
    $header .= "; MaxProcs: $max_procs\n";

    $header .= "; Note: The system worked with a coarse version of gang scheduling, where entire\n";
    $header .= "; Note: jobs were 'rolled out' and then 'rolled in' later on. Here there is one \n";
    $header .= "; Note: line per job and not per roll; start time is of the first roll, and used\n";
    $header .= "; Note: CPU time is total over all rolls.\n";

    return $header;
}

