############################################################################
#                                                                          #
# The contents of this file are subject to the WebStone Public License     #
# Version 1.0 (the "License"); you may not use this file except in         #
# compliance with the License. You may obtain a copy of the License        #
# at http://www.mindcraft.com/webstone/license10.html                      #
#                                                                          #
# Software distributed under the License is distributed on an "AS IS"      #
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See      #
# the License for the specific language governing rights and limitations   #
# under the License.                                                       #
#                                                                          #
# The Original Code is WebStone 2.5.                                       #
#                                                                          #
# The Initial Developer of the Original Code is Silicon Graphics, Inc.     #
# and Mindcraft, Inc.. Portions created by Silicon Graphics. and           #
# Mindcraft. are Copyright (C) 1995#1998 Silicon Graphics, Inc. and        #
# Mindcraft, Inc. All Rights Reserved.                                     #
#                                                                          #
# Contributor(s): ______________________________________.                  #
#                                                                          #
############################################################################

use Cwd;
use Sys::Hostname;
$wd = cwd;
push(@INC, "$wd/bin");
require('ws-utils.pl');
use File::Copy;
use File::Basename;

#
# Parse command line.
#
while ($ARGV[0] =~ /^-[^\s]/)
{
	if ($ARGV[0] =~ /^-debug$|^-d$/i)
	{
		$debug = 1;
		$| = 1;	# so debugging output is not buffered
		shift;
	}
	else
	{
		&do_usage;
		exit 0;
	}
}
&set_webstone_conf();

print "Clients: $CLIENTS\n";
@clients = split(/,\s*|\s+/, $CLIENTS);

#
# Estimate run time
#
$numclienthosts = $#clients + 1;
$trials = 1 + ( $MAXCLIENTS - $MINCLIENTS ) / $CLIENTINCR;
$runtime = 60 * $ITERATIONS * $trials * $TIMEPERRUN;
$runtime += $trials * ( $MAXCLIENTS + $MINCLIENTS ) / ( 2 * $numclienthosts );
print "Estimated run time: ", &my_floor( $runtime / 3600 ), " hours ", 
	&my_floor( $runtime % 3600 / 60 ), " minutes\n";

#
# Make the results directory if it doesn't exist
#
unless (-d "bin/runs")
{
        mkdir("bin/runs", 0777);
        print "Creating directory 'bin/runs'\n";
}

#
# Distribute webclient binary.
#
$my_hostname = hostname();
"$RCP" and &copy_file_to_clients($RCP, $my_hostname, $DELETE_FILE_CMD, 
				$LOCAL_CLIENTPROGFILE, $CLIENTPROGFILE,  
				@clients);

# BEGIN iterations
foreach $j (1..$ITERATIONS)
{
	for ($numclients = $MINCLIENTS; 
		$numclients <= $MAXCLIENTS;
			$numclients += $CLIENTINCR)
	{
		($date, $timestamp) = &my_getdates;
		print "\n***** Iteration $j, Total clients $numclients *****\n";
		print "$date";
	
		&clean_debug_files($DEBUGFILE, @clients);

		#
		# Create the log directory
		#
		$logdir = "bin/runs/$timestamp";
		-d $logdir and die "Log directory '$logdir' already exists!\n"; 
		mkdir($logdir, 0777) or
			die "Unable to create directory '$logdir': $!\n"; 
		print "Creating log directory '$logdir'\n";

		#
		# Set up the client config file
		#
		$client_config = "$logdir/config";
		open(CFG, "> $client_config") or
			die "Unable to create config file '$client_config': $!\n";
		&debug("Creating config file '$client_config'\n");
		&debug("config file contents:\n");

		$clientsperhost = &my_floor($numclients / $numclienthosts);
		$extraclients = ($numclients % $numclienthosts);
		
		# If clients are all IP numbers and SERVER is a host number 
		# (just a number like "11", not an IP adress) then have each 
		# client hit that host number on its net.  Otherwise just
		# point each webclient at SERVER.
		$use_server = (grep(!/\d+\.\d+\.\d+\.\d+/, @clients) or 
			$SERVER =~ /\D/ ) and $servername=$SERVER;

		foreach $c (@clients)
		{
			unless ($use_server)
			{
				$c =~ /(\d+\.\d+\.\d+)\.\d+$/;
				$servername = "$1.$SERVER";
			}
			if ( $extraclients > 0 )
			{
				print CFG "$c $CLIENTACCOUNT $CLIENTPASSWORD ", $clientsperhost + 1, " $servername\n";
				&debug("$c $CLIENTACCOUNT $CLIENTPASSWORD ", $clientsperhost + 1, " $servername\n");
				$extraclients--;
			}
			else
			{
				print CFG "$c $CLIENTACCOUNT $CLIENTPASSWORD $clientsperhost $servername\n";
				&debug("$c $CLIENTACCOUNT $CLIENTPASSWORD $clientsperhost $servername\n");
			}
		}
		close CFG;

		$fl = basename($FILELIST);
		$fl = "$logdir/$fl";
		copy($FILELIST, $fl) or 
			die("Copying file '$FILELIST' to '$fl': $!\n");

		$WEBSERVERTUNINGFILES and $RCP and
			&get_webservertuningfiles($RCP, $SERVER, $logdir,
						  $WEBSERVERTUNINGFILES);

		#
		# Run benchmark
		#
		$cmd = "$WEBSTONEROOT\\bin\\webmaster.exe -v -W -C $CLIENTPROGFILE";
		$cmd .= " -f $client_config -t $TIMEPERRUN";
		$cmd .= " -U $CLIENTFILELIST"	if $CLIENTFILELIST;
		$FILELIST = ""				if $CLIENTFILELIST;
		$cmd .= " -u $FILELIST"			if $FILELIST;
		$cmd .= " -p $PORTNO"			if $PORTNO;
		$cmd .= " -P $PROXYSERVER"		if $PROXYSERVER;
		$cmd .= " -d"				if $DEBUG;
		$cmd .= " -D $DEBUGFILE"		if $DEBUGFILE;
		$cmd .= " -S"				if $FIXED_RANDOM_SEED;

		print "$cmd\n";

		open(PROC, "$cmd |") or
			die("Unable to run command '$cmd': $!\n");
		$logfilepath = "$logdir/run";
		open(LOGFD, "> $logfilepath") or
			die("Opening file '$logfilepath': $!\n");

		while(<PROC>)
		{
			print LOGFD "$_";
			print;
		}
		close PROC;
		close LOGFD;
	
		print ((&my_getdates)[0]);
	}
}

# rather than bring in the POSIX:strftime or ctime modules, just 
# do a simple subroutine.
sub my_getdates 
{
	my($sec,$min,$hr,$mday,$mon,$yr,$wday) = localtime;
	my($tz) = $ENV{TZ};
	(sprintf("%s %s %2d %02d:%02d:%02d %s %d\n", 
		('Sun','Mon','Tue','Wed','Thu','Fri','Sat')[$days[$wday]], 
		('Jan','Feb','Mar','Apr','May','Jun',
                 'Jul','Aug','Sep','Oct','Nov','Dec')[$mos[$mon]],
		$mday, $hr, $min, $sec, $tz, $yr+1900),
	sprintf("%02d%02d%02d_%02d%02d", $yr, $mon, $mday, $hr, $min));
}


sub my_floor { "$_[0]" =~ /(\d+)\.?.*$/; $1; }


sub copy_file_to_clients
{
	my($rcp, $my_hostname, $del, $localfile, $clientprogfile, @clients) = @_;
	my($cmdline, $remotefile, $rempath);

	# turn 'C:\tmp' into 'c$\tmp' to access NT remote shares
	($remotefile = $clientprogfile) =~ s/^([a-zA-Z]):(.*)/$1\$$2/;

	print "Distributing webclient binary to clients.\n";
	foreach $client (@clients)
	{
	    if ($client eq 'localhost' ||
 		$my_hostname =~ /^$client(\..*$)?/)
	    {
		if ($localfile eq $clientprogfile)
		{
		    &debug("No need to copy '$localfile' to itself!");
		    next;
		}
		$cmdline = "$rcp $localfile $clientprogfile";
	    }
	    else
	    {
		$rempath = "\\\\$client\\$remotefile";
		if (-f $rempath)
		{
			# remove old file from client system.
			$cmdline = "$del $rempath";
			&debug("Executing '$cmdline'\n");
			system($cmdline);
		}

		# copy file to client system.
		$cmdline = "$rcp $localfile $rempath";
            }

	    &debug("Executing '$cmdline'\n");
	    system($cmdline);
	}
}


sub clean_debug_files
{
	my($debugfile, @clients) = @_;
	my ($remotefile);

	# turn 'C:\tmp' into 'c$\tmp' to access NT remote shares
	($remotefile = $debugfile) =~ s/^([a-zA-Z]):(.*)/$1\$$2/;
	$remotefile .= '*';	# append '*' to remove multiple files.

	print "Cleaning client debug files.\n";
	foreach $client (@clients)
	{ 
		unlink( "\\\\$client\\$remotefile" );
	}
}
	    

sub get_webservertuningfiles
{
	my($copy, $server, $logdir, $webservertuningfiles) = @_;
	my($cmdline, $remotefile);

	print "Retrieving webserver tuning files: $webservertuningfiles\n";
	foreach $file (split(/,\s*|\s+/, $webservertuningfiles))
	{ 
		# turn 'C:\tmp' into 'c$\tmp' to access NT remote shares
		($remotefile = $file) =~ s/^([a-zA-Z]):(.*)/$1\$$2/;

		# remove old file from client system.
		$cmdline = "$copy \\\\$server\\$remotefile $logdir";
		&debug("Executing '$cmdline'\n");
		system($cmdline);
	}
}

sub do_usage
{
	print "Usage: $0 [-help|-h] [-debug|-d] [config-file]\n";
	exit 2;
}

# End
