#!/usr/bin/perl
#
# ANTs farm scenario running script
# Bryan Horling - Aug 2002
# ##################################################################

# ###
# Note: this script assumes you have passwordless ssh logins enabled
# from the originating server (the one you run this script on) to 
# a collection of other servers (the ones specified by @AGENT_HOSTS).
# This script uses ssh to spawn remote plugins and agents on those
# hosts to distribute the load of the simulation.  You should change
# the @AGENT_HOSTS array to specify your set of local machines, and
# ensure that the farm package is available on those machines at the
# same location (e.g. it exists at /home/<username>/research/farm or
# similar)
# ###

# Agent hosts. ** You will need to edit this **
@AGENT_HOSTS = (chok, marduk, angus, ogma, dino, crush, tiamat, ramses, narsil, qed, mulan, ymir);

# Simulator host, the machine it will be run from
$SIMULATOR_HOST = `uname -n`; chomp($SIMULATOR_HOST);

# The display
$DISPLAY="$SIMULATOR_HOST:0.0";
#$DISPLAY=$ENV{'DISPLAY'};

# How long should it run for? (0 = forever)
$END = 10000;

# Make the arg list, currently this is passed into the FarmDriver
# To see what the FarmDriver supports, look for calls to getCommandLineArgument
# in its source code.
$ARGS = join(" ", @ARGV);

# Find the farm directory
#$FARM_DIR  = "?esearch/farm";
$FARM_DIR  = `pwd`; chomp($FARM_DIR);
$FARM_DIR =~ s/$ENV{'HOME'}\/*//;
$FARM_DIR =~ s/\/[^\/]*$//;

# The Metagents.  Adjust NUM_AGENTS to control how many metagents are
# spawned, and the AGENTS assignment line to control which metagent
# is used.  The format is $AGENTS{"<java arguments>"} = "<run path>";
$NUM_AGENTS = 5;
for ($i = 0; $i < $NUM_AGENTS; $i++) {
	$AGENTS{"farm.sat.plugins.SATMetAgent -host $SIMULATOR_HOST -name MA$i -msgmintime 0 -msgmaxtime 0 -msgbytetime 0 -msglossrate 0 2> MA$i.log"} = "$FARM_DIR/sat";
}

# The Plugins.  Add new plugins to this list as needed.  The format
# is roughly the same as the agents above.
%PLUGINS = (
	"farm.generic.plugins.drivers.TimeDriver -host $SIMULATOR_HOST -gui -end $END " => "$FARM_DIR/generic",
	"farm.generic.plugins.gui.GraphGui -host $SIMULATOR_HOST -track \"TotalVariables,TotalClauses,TotalMessagesReceived,TotalUtility,PossibleConflicts,TotalConflicts\"" => "$FARM_DIR/generic",
	"farm.sat.plugins.drivers.SATDriver -host $SIMULATOR_HOST $ARGS -metagents $NUM_AGENTS" => "$FARM_DIR/sat",
	"farm.sat.plugins.SATAnalysis -host $SIMULATOR_HOST" => "$FARM_DIR/sat",
#	"farm.generic.plugins.PropertyLog -host $SIMULATOR_HOST -log \":value\" -o ../sat/values.log" => "$FARM_DIR/generic",
);

# Simulator.  This is used to spawn the simulator.
$NUM_PLUGINS = $NUM_AGENTS + keys(%PLUGINS);
%SIMULATORS = (
	"farm.simulator.FarmSimulator -m $NUM_PLUGINS -s simulator.sav 2> simulator.log" => "$FARM_DIR/simulator"
);

# Kill the simulator.  This is used to kill the simulator.
%KILLSIMULATORS = (
	"farm.generic.plugins.drivers.KillDriver -host $SIMULATOR_HOST" => "$FARM_DIR/simulator"
);

# Get the java cmd from the makefile
$JAVA=`make runjava`; chomp($JAVA);
$JAVA .= " ";

###################################################################
# You shouldn't need to change anything below this line
###################################################################

system("xhost +");
if ($ARGV[0] eq "kill") {
	killscenario();
} else {
	runscenario();
}

###################################################################
###################################################################

sub runscenario {
	# Run the registry
	runregistry();
	sleep(1);

	# Run the simulator
	foreach $key (keys %SIMULATORS) {
		if (fork()) { runsim($SIMULATORS{$key}, $key); }
	}
	sleep(3);

	# Run the agents
	foreach $key (keys %AGENTS) {
		if (fork()) { runplugin($AGENTS{$key}, $key); }
		else { $PLUGIN_HOST++; }
	}
	sleep(3);

	# Run the plugins
	foreach $key (keys %PLUGINS) {
		if (fork()) { runplugin($PLUGINS{$key}, $key); }
		else { $PLUGIN_HOST++; }
	}
}

sub killscenario {

	foreach $key (keys %KILLSIMULATORS) {
		runplugin($KILLSIMULATORS{$key}, $key, 1);
	}

	foreach $host (@AGENT_HOSTS) {
		if (fork()) { remote($host, "", "killall -q -9 java"); }
	}
}

###################################################################
###################################################################

# Run the registry
sub runregistry {
	my $PSREG = `ps auxww | grep rmiregistry | grep -v grep`;
	system("make registry") unless ($PSREG);
}

# Run the simulator
sub runsim {
	local($dir, $class, $exit) = @_;

	local $cmd = $JAVA . $class;

	remote($SIMULATOR_HOST, $dir, $cmd, $exit);
}

# Run a plugin
sub runplugin {
	local($dir, $class, $exit) = @_;

	local $cmd = $JAVA . $class;

	remote($AGENT_HOSTS[$PLUGIN_HOST % @AGENT_HOSTS], $dir, $cmd, $exit);
}

# Do a remote command
sub remote {
	($host, $dir, $cmd, $exit) = @_;

	$NAME = "/tmp/runfarm.$$." . rand();
	chomp($host);

	# Write out the command
	open (FILE, "> $NAME");
	print FILE "ssh -T $host<<EOF\n";
	#print FILE "xhost +localhost\n";
	print FILE "export DISPLAY=$DISPLAY\n";
	print FILE "cd $dir\n";
	print FILE "$cmd\n";
	print FILE "EOF\n";
	close FILE;

	# Run the command
	print "$host > $cmd\n";
	$CMD = "bash $NAME";
	system ($CMD);
	#system ("cat $NAME");

	unlink $NAME;
	exit unless $exit;
}
