#!/usr/bin/perl

# CONFIGURATION:
# This scipt uses test5a and test5b from the sun connectathon suite.
# A modified version of test5b is used which does not delete the file
# after reading. This allows the script to perform both a buffered and
# an unbuffered read test on the same file.

# ssh must be configured so that the user executing the script can 
# log in to the server without supplying a password. This is used
# to force the server to touch the file so that an unbuffered read
# can be performed.

# These options must be specified here
$server = "cupertino";				# name of nfs server
$rem_dir = "/exports/cthon_server/cthon/"; 	# nfs directory to mount
$directory = "/net/nfstestdir/cthon"; 		# where to mount nfs directory

# These options can be set from the command line.
# These are the defaults
$test5_granularity = 10e6;
$test5_factor = 10;
$test5_min = $test5_granularity;
$test5_max = 3e9;
$mode = "lin"; 	# Linear or logarithmic file size scale for test5
$quiet = 0; 	# If 1, print test results on STDOUT
		# (If no output file is used, will do this anyways)
$printfile = 0; 

sub usage {
	if ($mode eq "lin")
	{
		$test5_lin = "TRUE";
		$test5_log = "FALSE";
	}
	if ($mode eq "log")
	{
		$test5_lin = "FALSE";
		$test5_log = "TRUE";	
	}
	print <<"ENDUSAGE"
test5_ciruit [options]

Options: (defaults are in parens)
-o filename		Save results into a file
--quiet			Don't show results on STDOUT
--lin ($test5_lin)		Use linear scaling for test5
--granularity=n ($test5_granularity)	Granularity for linear scaling in test5
--log ($test5_log)		Use logarithmic scaling for test5
--factor=n ($test5_factor)		Factor for logarithmic scaling in test5
--min=n ($test5_min)		Minimum file size for test5
--max=n ($test5_max)		Maximum file size for test5
ENDUSAGE
}

sub getCollisions {
	my $if_results = `/sbin/ifconfig | grep collisions`;
	$if_results =~ /collisions:(\d+)/;
	return $1
}

sub runTest {
	my $test_string = $_[0]; 

	my $collisions1 = getCollisions();
	my $result = `$test_string`;
	my $collisions2 = getCollisions();
	my $net_collisions = $collisions2 - $collisions1;
	$result .= "Collisions: " . $net_collisions . "\n\n";
}

sub printResult
{
	my $result = $_[0];
	if ($printfile)
	{
		print OUTFILE $result;
	}
	if (!$quiet)
	{
		print $result;
	}
}	

# Set test directory
$ENV{"NFSTESTDIR"} = $directory;

# Check for command line switches to override defaults
# Probably a more elegant way to do this.
while ($arg = shift)
{
	if ($arg eq "--usage" || $arg eq "--help")
	{
		usage;
		exit(0);
	}
	elsif ($arg eq "--quiet")
	{
		$quiet=1;
	}
	elsif ($arg eq "-o")
	{
		$printfile = 1;
		if (!($outfile = shift))
		{
			die "Can't open $outfile for writing";
		}
	}
	elsif ($arg eq "--lin")
	{
		$mode = "lin";
	}
	elsif ($arg eq "--log")
	{
		$mode = "log";
	}
	elsif ($arg =~ /^--granularity=(\d+)/)
	{
		$test5_granularity = $1;
	}
	elsif ($arg =~ /^--factor=(\d+)/)
	{
		$test5_factor = $1;
	}
	elsif ($arg =~ /^--min=(\d+)/)
	{
		$test5_min = $1;
	}
	elsif ($arg =~ /^--max=(\d+)/)
	{
		$test5_max = $1;
	}
	else
	{
		print "Invalid option $arg\n";
		usage;
		exit(1);
	}
}

# Warn if using quiet mode, without writing to a file
if ($quiet && !$printfile)
{
	warn "Using quiet mode without an output file. Results will be lost!"
}

if ($printfile)
{
	open OUTFILE, ">$outfile" or die "Can't open $outfile for writing";
}

# Use test5a and test5b for write & read tests
$i = $test5_min;
while ($i <= $test5_max)
{
	# Do write
	$result = runTest("test5a -t $i 1");
	printResult($result);

	# Do buffered read
	printResult("Buffered read:\n");
	$result = runTest("test5b -t $i 1");
	printResult($result);

	# Have server touch the file, so we can do an
	# unbuffered read.
	$touch_cmd = "ssh $server touch $rem_dir" . "bigfile";
	sleep 1;
	`$touch_cmd`; 

	# Do the unbuffered read.
	printResult("Unbuffered read:\n");
	$result = runTest("test5b -t $i 1");
	printResult($result);

	# Delete the file.
	# (test5b has been modified to not do this automatically)
	unlink("${rem_dir}bigfile");

	# If printing to a file, re-open it. This forces
	# a flush of the file, so if the test is ended prematurely,
	# the results won't be lost.
	if ($printfile)
	{
		open OUTFILE, ">>$outfile" or die "Can't open $outfile for writing";
	}

	# Increment file size, depending on mode
	if ($mode eq "lin")
	{
		$i += $test5_granularity;
	}
	elsif ($mode eq "log")
	{
		$i *= $test5_factor;
	}
	else
	{
		die "Invalid test5 mode";
	}
}
