#!/usr/bin/perl use IO::Handle; $bench_dir = "bench"; $data_dir = "data"; $save_dir = "save"; $consl = "console.log"; #Save the output of the masters console... useful for debugging (sometimes) open(CONSL, ">>$consl") || print "WARNING: Could not open console log ($consl)\n"; #This is in here for hysterical raisins. This program used to be something #completely different. CONSL->blocking(0); CONSL->autoflush(0); STDOUT->blocking(0); STDOUT->autoflush(0); while(1){ $run_num = int(rand(1000000)); #get rid of the old pool system("mv server.dat old.dat/server.dat-$run_num"); #Clear the old benchmark, import (data) directory, #and any old server.dat files system("rm $bench_dir/* server.dat $data_dir/* "); #Make a new benchmark, If we've got nothing on the hill, use a random #Selection system("./mkbench.pl"); if($run_num > 500000){ #Make a new import (data) selection by using makepop to generate # a directory full of new randomly generated warriors. system("./makepop"); } else { #Make new import (data) selection, takes a random selection from #your save directory. system("./mkranddata.pl"); } #Run the master evolver program, it'll load the benchmark, #import the data directory, and then start listening for clients. run_master(); #By default the master will listen and serve the same blocks forever. #I use several cron jobs and at jobs to perform a few functions: #1) kill the master at midnight every day #2) force the master to restart scoring every 2 hours, (using the # tweak program), this churns the current pool and prevents warriors # that just got a lucky high score from hanging around slowing things # up. #3) Restart the clients from scratch using dsh (from the cluster-it # toolkit), dsh -g nano pkill client-nano ; dsh -g nano ./runevolve #Without the outside scripts, this will never do much of anything. #Dump the current contents of the pool to the save directory. #Start by dumping the top warrior, we'll submit him because bvowk #hasn't written a better script to do this intelligently. open(TW, "./dump -s 0 -f server.dat -s save|"); while(){ if(/Saving/){ $_ = /Saving ([0-9]+-[0-9]+-.*) at position*/; $top_warrior = $1; printf("Top warrior was $top_warrior\n"); close(TW); close(README); } } #Dump the warriors to the save dir print "Dumping all warriors to $save_dir...\n"; system("./dump -f server.dat -d $save_dir -s -1"); #Mail sal with your new warrior using the bsd mail proggie. This may #not work for everyone. print "Mailing $top_warrior to koth\@sal.math.ualberta.ca...\n"; system("cat $save_dir/$top_warrior | mail koth\@sal.math.ualberta.ca"); #If we don't wait here, we won't get the stats on the new hill, we #might have pushed something off. print "Sleeping 5 minutes to let koth\@sal update before building new benchmark"; sleep(120); } #This was just ripped straight from another project, it doesn't really fit #but it works, you wouldn't believe me if I told you what it was originally. sub run_master { use POSIX qw(:sys_wait_h); my $started = 0; my $pid = 0; my @OUTPUT = (); pipe(README, WRITEME); if ($pid = fork) { # parent # $SIG{CHLD} = sub { 1 while ( waitpid(-1, WNOHANG)) > 0 }; close(WRITEME); } else { die "cannot fork: $!" unless defined $pid; # child open(STDOUT, ">&=WRITEME") or die "Couldn't redirect STDOUT: $!"; close(README); exec("./master", "") or die "Couldn't run ./master: $!\n"; exit; } @OUTPUT = (); my $nfound = $delay = 0; do{ my $rin = ''; vec($rin, fileno(README), 1) = 1; $nfound = select($rin, undef, undef, 5); # just check if($nfound) { $new = ; print "$new"; push(@OUTPUT, $new); print CONSL $new; $nfound = 0; } else { #the select timed out, increte the delay timer $delay++; } #Lets see check to see if the client is telling us something important if($delay > 10){ $delay = 0; if($started == 0){ $started = 1; #This is sort of stupid. But it works better than waiting #for the hourly restart to get things going. system("export CLUSTER /home/bvowk/cluster; dsh -g nano ./runevolve &"); } #open a new socket } $running = waitpid(-1, &WNOHANG); }until ($running == -1); close(README); }