#!/usr/bin/perl
# begin_generated_IBM_copyright_prolog                             
#                                                                  
# This is an automatically generated copyright prolog.             
# After initializing,  DO NOT MODIFY OR MOVE                       
# **************************************************************** 
# Licensed Materials - Property of IBM                             
# 5724-Y95                                                         
# (C) Copyright IBM Corp.  2010, 2014    All Rights Reserved.      
# US Government Users Restricted Rights - Use, duplication or      
# disclosure restricted by GSA ADP Schedule Contract with          
# IBM Corp.                                                        
#                                                                  
# end_generated_IBM_copyright_prolog                               

##use strict;
use warnings;
use Getopt::Std;
use Cwd qw(realpath abs_path getcwd);
use File::Basename;
use File::Temp qw/ tempdir /;

use FindBin;
use lib "${FindBin::Bin}";
use lib "${FindBin::Bin}/impl/bin";
use lib "${FindBin::Bin}/../system/impl/bin";

use SPL::Helper;
use SPL::Msg; # load message constants

sub submitPerfRun($$);
sub generateXml($);
sub createDir($);
# set the install dir

my $installDir = $ENV{'STREAMS_INSTALL'};
if (!defined(${installDir})) {
  SPLDie(1, SPL::Msg::STREAMS_INSTALL_UNDEFINED);
}

# set the location of the transport profile application
my $statDir = "${installDir}/etc/stat";   

# set the streamtool location
my $streamtool = "${installDir}/bin/streamtool";

## process options
my %opts;
my @options = ('help|h', 'use-transport|F=s', 'silent|s', 'local|l', 'output-directory|o=s', 'data-directory|d=s', 'instance-id|i=s', 'keep|k' );
SPLGetOptionsLong(\&SPL::Msg::STS_USAGE, \%opts, @options);

# set the transport 
my $transport;
$opts{'use-transport'} = "tcp" unless($opts{'use-transport'});
if($opts{'use-transport'} eq "tcp") {
    $transport = "tcp";
} elsif($opts{'use-transport'} eq "llm_rum_tcp") {
    $transport = "llm_rum_tcp";
} elsif($opts{'use-transport'} eq "llm_rum_ib") {
    $transport = "llm_rum_ib";
} else {
  SPLDie(1, SPL::Msg::INVALID_TRANSPORT_KIND($opts{'use-transport'}));
}

# set the instance
my $instance = $opts{'instance-id'} ? $opts{'instance-id'} : $ENV{'STREAMS_INSTANCE_ID'}; # default instance

## check if instance has been started
my $startedInstance = "${streamtool} lsjobs -i ${instance}";
system ("${startedInstance} 2>/dev/null 1>/dev/null ");
if ($? ne 0) {
  SPLDie(1, SPL::Msg::INSTANCE_NOT_RUNNING(${instance}));
}

my $cwd = getcwd();

my $verbose = 1;
if(defined($opts{'silent'})) {
  $verbose = 0;
}

my $runLocal = 0;
if(defined($opts{'local'})) {
  $runLocal = 1;
}

# set output directory
my $outdir = $opts{'output-directory'} ? $opts{'output-directory'} : "./output/etc/stat"; # default directory 

# create output dir if it doesn't exist
createDir($outdir);

# set absolute path of output dir for later 
${outdir} = abs_path(${outdir});

# set output file
my $outfile = "${outdir}/transportStatModelFor_${transport}.xml";
if ($runLocal) {
  $outfile = "${outdir}/transportStatModelFor_${transport}_local.xml";
}

SPLStdOutLn(SPL::Msg::USING_INSTANCE(${instance})) if $verbose;

# create temporary dir and copy benchmark Makefile and source to it
my $template = "./transportStatTmpDir.XXXXX";
my $cleanup = defined($opts{'keep'}) ? 0 : 1;
my $tmpdir = tempdir($template, CLEANUP => $cleanup);

system ("cp  ${statDir}/Makefile ${tmpdir}");
system ("cp -r ${statDir}/ThroughputSpl ${tmpdir}");

chdir ${tmpdir} || SPLDie(1,SPL::Msg::CANNOT_CD_TO_TEMP_DIR(${tmpdir}));

mkdir("data") unless ($opts{'data-directory'});
my $dataDir = $opts{'data-directory'} ? $opts{'data-directory'} : "data";

## Compile benchmark for specific transport
my $compileLine = "make SPL_DATA_DIR=$dataDir ";
if ($runLocal) {
   $compileLine = "SPL_CMD_ARGS=\"-F ${transport} 300000000 A\"";
} else {
    $compileLine .= "SPL_CMD_ARGS=\"-F ${transport} 100000000\"";
}
SPLStdOutLn(SPL::Msg::COMPILING_TRANSPORT_BENCHMARK(${transport},${tmpdir})) if $verbose;

system ("${compileLine}");
if ($? ne 0) {
  SPLDie(1, SPL::Msg::FAILED_TO_BUILD_TRANSPORT_BENCHMARK);
}

## remove all result files 
system ("rm -f $dataDir/resultsReceiver.csv");
system ("rm -f $dataDir/resultsSender.csv");

## submit performance runs for all tuple sizes (4 -> 16384)
my $tupleSizeCounter = 4;
my $i;

for ($i = 0; $i < 13; $i++) {
    submitPerfRun($tupleSizeCounter, $dataDir);
    $tupleSizeCounter *= 2;
}

SPLStdOutLn(SPL::Msg::GEN_TRANSPORT_XML_FILE(${outfile})) if $verbose;

## generate XML to appropriate file
generateXml($dataDir);

# cd back to current working dir
chdir ${cwd};   

exit 0;

sub createDir($) 
{
   my ($dir) = @_;
   return if -d $dir;
   my $parent = File::Basename::dirname($dir);
   createDir ($parent) unless -d $parent || $dir eq $parent;
   -d $dir or mkdir $dir or SPLDie(1, SPL::Msg::CANNOT_CREATE_DIRECTORY($dir));
   # set the new directory permission from its parent
   my ($dev,$ino,$mode) = stat ($parent);
   chmod $mode, $dir;
}

sub submitPerfRun($$) 
{
    my ($tupleSize, $dataDir) = @_;
    
    SPLStdOutLn(SPL::Msg::RUNNING_TRANSPORT_BENCHMARK(${tupleSize})) if $verbose;

    system ("rm -f $dataDir/endReceiver");
    system ("rm -f $dataDir/endSender");

    my $submitJob = "${streamtool} submitjob --P nbytes=${tupleSize} output/*.adl -i ${instance} --outfile ./jobList";
    my $rc = system ("${submitJob}");
    $rc = $rc >> 8;
    if ($rc != 0) {
        SPLDie(1, SPL::Msg::STATS_SUBMITJOB_FAILED(${instance}));
    }

    do {
        sleep 2;
        # the following is to refresh the NFS file system 
        system ("ls -l $dataDir 2>/dev/null 1>/dev/null");
     } while((not -f "$dataDir/endSender") || (not -f "$dataDir/endReceiver"));

    my $cancelJob = "${streamtool} canceljob -i ${instance} --file ./jobList";
    system ("${cancelJob}");
}

sub generateXml($) 
{
    my ($dataDir) = @_;
    open(my $fhs, '<', "$dataDir/resultsSender.csv") or die "Cannot open $dataDir/resultsSender.csv for read, rc=$!\n";
    open(my $fhr, '<', "$dataDir/resultsReceiver.csv") or die "Cannot open $dataDir/resultsReceiver.csv for read, rc=$!\n";
    open(my $fho, '>', "${outfile}") or die "Cannot open output file: ${outfile}, rc=$!\n";

    my $xmlhdr = "
<transportStatModel
    xmlns=\"http://www.ibm.com/xmlns/prod/streams/spl/transportStat\"
    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" 
    xmlns:cmn=\"http://www.ibm.com/xmlns/prod/streams/spl/common\"    xsi:schemaLocation=\"http://www.ibm.com/xmlns/prod/streams/spl/transport transportStatModel.xsd\">

  <productVersion>1.0.0.0</productVersion>
  <cpuKind>Nahalem</cpuKind>
  <bogoMips>6000</bogoMips>
";

    print {$fho} $xmlhdr;

    my $profhdr = "
  <transportProfile>   
    <transportKind>${transport}</transportKind>
";

    print {$fho} $profhdr;

    my $tupleSizeSender;
    my $tupleSizeReceiver;
    my $rate;
    my $senderUtil;
    my $receiverUtil;
    my $elapsedTime;

    while(<$fhr>) {
        chomp;
        # read and parse line from receiver results
        ($tupleSizeReceiver, $rate, $elapsedTime, $receiverUtil) = split(/,/);
   
        # write tuple size and transfer rate from receiver
        print {$fho} "       <tuplePerf>\n";
        print {$fho} "          <size>${tupleSizeReceiver}</size>\n";
        print {$fho} "          <rate>${rate}</rate>\n";

   
        # read and parse line from sender results
        defined( $_ = <$fhs> ) or SPLDie(1, SPL::Msg::FAILED_TO_WRITE_XML);
        chomp;
        ($tupleSizeSender, $rate, $elapsedTime, $senderUtil) = split(/,/);

        # check that sender and receiver tuple sizes are in sync
        (${tupleSizeSender} == ${tupleSizeReceiver}) or SPLDie(1, SPL::Msg::FAILED_TO_WRITE_XML);

        # write sender and receiver cpu utilization
        print {$fho} "          <senderUtil>${senderUtil}</senderUtil>\n";
        print {$fho} "          <receiverUtil>${receiverUtil}</receiverUtil>\n";
        print {$fho} "       </tuplePerf>\n"; 
   
    }


    print {$fho} "  </transportProfile>
</transportStatModel>\n";

    close $fho;
    close $fhr;
    close $fhs;
}

