summaryrefslogtreecommitdiff
path: root/competition/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'competition/main.cpp')
-rw-r--r--competition/main.cpp213
1 files changed, 44 insertions, 169 deletions
diff --git a/competition/main.cpp b/competition/main.cpp
index 90579db..604263c 100644
--- a/competition/main.cpp
+++ b/competition/main.cpp
@@ -4,7 +4,6 @@
#include <iomanip>
#include <vector>
#include <string>
-#include <stdexcept>
#include <utility>
#include <algorithm>
#include <optional>
@@ -16,12 +15,13 @@
#include <cassert>
#include <errno.h>
#include <unistd.h>
-#include <signal.h>
#include <sys/stat.h>
#include <sys/time.h>
-#include <sys/fcntl.h>
-#include <sys/wait.h>
#include "../board.h"
+#include "job.h"
+#include "process.h"
+#include "error.h"
+#include "multilog.h"
using namespace std;
@@ -33,6 +33,10 @@ static const int num_matches = 5;
static const int timeout_msec = 60000;
+// TODO no globals
+static MultiLog gMultiLog;
+
+
static char hexchar(int n) {
return "0123456789ABCDEF"[n];
}
@@ -64,6 +68,16 @@ static void mkdirp(const string_view name) {
}
}
+static int64_t fileLastModified(const string_view fname) {
+ struct stat st;
+ if (stat(fname.data(), &st) < 0) {
+ if (errno == EEXIST) return 0;
+ perror("stat");
+ exit(1);
+ }
+ return st.st_mtim.tv_sec * 1000000LL + st.st_mtim.tv_nsec;
+}
+
static int64_t gettimestamp() {
struct timeval tv;
gettimeofday(&tv, nullptr);
@@ -89,9 +103,11 @@ struct MatchResult {
struct Player {
string fname, safename;
vector<MatchResult> results;
+ int64_t lastModified;
Player(const string &fname)
- : fname(fname), safename(makeSafe(fname)) {}
+ : fname(fname), safename(makeSafe(fname)),
+ lastModified(fileLastModified(fname)) {}
};
int MatchResult::score() const {
@@ -127,155 +143,6 @@ MatchResult MatchResult::inverted() const {
return r;
}
-class StopCompetitionError : public runtime_error {
-public:
- StopCompetitionError()
- : runtime_error("StopCompetitionError") {}
- explicit StopCompetitionError(const string &what_arg)
- : runtime_error(what_arg) {}
- explicit StopCompetitionError(const char *what_arg)
- : runtime_error(what_arg) {}
-};
-
-class Process {
- string execname;
- optional<string> stderrRedirect;
- pid_t pid = -1;
- int infd = -1, outfd = -1;
-
- string readBuf;
-
-public:
- Process(const string_view execname)
- : execname(execname) {}
-
- void redirectStderr(const string_view fname) {
- stderrRedirect = fname;
- }
-
- void run() {
- int stderrfd = -1;
- if (stderrRedirect) {
- stderrfd = open(stderrRedirect->data(), O_WRONLY|O_CREAT|O_TRUNC, 0644);
- if (stderrfd < 0) {
- perror("open");
- cout << endl << "ERROR: Cannot open player log file '" << *stderrRedirect << "'" << endl;
- throw StopCompetitionError();
- }
- }
-
- int pipefds[2];
- if (pipe(pipefds) < 0) {
- perror("pipe");
- exit(1);
- }
- infd = pipefds[1];
- int child_in = pipefds[0];
-
- if (pipe(pipefds) < 0) {
- perror("pipe");
- exit(1);
- }
- outfd = pipefds[0];
- int child_out = pipefds[1];
-
- pid = fork();
- if (pid < 0) {
- perror("fork");
- exit(1);
- }
-
- if (pid == 0) {
- if (stderrRedirect) dup2(stderrfd, STDERR_FILENO);
- dup2(child_in, STDIN_FILENO);
- dup2(child_out, STDOUT_FILENO);
- close(infd);
- close(outfd);
-
- execlp(execname.data(), execname.data(), NULL);
- cerr << endl << "ERROR: Error executing player file '" << execname << "'" << endl;
- exit(255);
- }
-
- if (stderrfd >= 0) close(stderrfd);
- close(child_in);
- close(child_out);
- }
-
- void wait() {
- while (true) {
- int status;
- if (waitpid(pid, &status, 0) < 0) {
- if (errno == EINTR) continue;
- perror("waitpid");
- break;
- }
- if (WIFEXITED(status)) break;
- }
- }
-
- void stop() {
- if (pid != -1) kill(pid, SIGSTOP);
- }
-
- void unStop() {
- if (pid != -1) kill(pid, SIGCONT);
- }
-
- bool writeLine(const string_view line) {
- string str;
- str.reserve(line.size() + 1);
- str += line;
- str += '\n';
-
- size_t cursor = 0;
- while (cursor < str.size()) {
- ssize_t nw = write(infd, str.data() + cursor, str.size() - cursor);
- if (nw < 0) {
- if (errno == EINTR) continue;
- perror("write");
- return false;
- }
- cursor += nw;
- }
-
- return true;
- }
-
- optional<string> readLine() {
- size_t idx = readBuf.find('\n');
- if (idx != string::npos) {
- string res = readBuf.substr(0, idx);
- readBuf = readBuf.substr(idx + 1);
- return res;
- }
-
- while (true) {
- string s(1024, '\0');
- ssize_t nr = read(outfd, &s[0], s.size());
- if (nr < 0) {
- if (errno == EINTR) continue;
- perror("read");
- return nullopt;
- }
- s.resize(nr);
-
- idx = s.find('\n');
- if (idx != string::npos) {
- string res = readBuf + s.substr(0, idx);
- readBuf = s.substr(idx + 1);
- return res;
- }
-
- readBuf += s;
- }
- }
-
- void terminate() {
- if (pid != -1) kill(pid, SIGTERM);
- }
-};
-
static string gameCodeName(const Player &p1, const Player &p2, int index) {
return p1.safename + "-" + p2.safename + "-" + to_string(index);
}
@@ -293,9 +160,13 @@ static string gameLogPath(const Player &p1, const Player &p2, int index) {
}
static optional<MatchResult> readMatchCache(const Player &p1, const Player &p2, int index) {
- ifstream f(matchCachePath(p1, p2, index));
+ string path = matchCachePath(p1, p2, index);
+ ifstream f(path);
if (!f) return nullopt;
+ int64_t cacheStamp = fileLastModified(path);
+ if (p1.lastModified > cacheStamp || p2.lastModified > cacheStamp) return nullopt;
+
MatchResult mres;
string word;
f >> word >> mres.ms1 >> mres.ms2;
@@ -334,10 +205,11 @@ static void recordResult(Player &p1, Player &p2, const MatchResult &result) {
}
static void playMatch(Player &p1, Player &p2, int index) {
- cout << p1.fname << " - " << p2.fname << ": " << flush;
+ int logId = gMultiLog.add(p1.fname + " - " + p2.fname + ": ");
if (optional<MatchResult> optres = readMatchCache(p1, p2, index)) {
- cout << optres->describe(p1, p2) << " (cached)" << endl;
+ gMultiLog.append(logId, optres->describe(p1, p2) + " (cached)");
+ gMultiLog.complete(logId);
recordResult(p1, p2, *optres);
return;
}
@@ -348,7 +220,7 @@ static void playMatch(Player &p1, Player &p2, int index) {
string gamelog_path = gameLogPath(p1, p2, index);
ofstream gamelog(gamelog_path);
if (!gamelog) {
- cout << endl << "ERROR opening game log file " << gamelog_path << endl;
+ cout << "ERROR opening game log file " << gamelog_path << endl;
throw StopCompetitionError();
}
@@ -367,7 +239,7 @@ static void playMatch(Player &p1, Player &p2, int index) {
while (true) {
for (int i = 0; i < 2; i++) {
if (!procs[i].writeLine(lastMove)) {
- cout << endl << "ERROR writing move to player " << i+1 << endl;
+ cout << "ERROR writing move to player " << i+1 << endl;
throw StopCompetitionError();
}
@@ -375,7 +247,7 @@ static void playMatch(Player &p1, Player &p2, int index) {
int64_t start = gettimestamp();
optional<string> oline = procs[i].readLine();
if (!oline) {
- cout << endl << "ERROR reading move from player " << i+1 << endl;
+ cout << "ERROR reading move from player " << i+1 << endl;
throw StopCompetitionError();
}
@@ -392,11 +264,11 @@ static void playMatch(Player &p1, Player &p2, int index) {
optional<Move> omv = Move::parse(lastMove);
if (!omv) {
- cout << endl << "ERROR in player " << i+1 << ": unreadable move '" << lastMove << "'" << endl;
+ cout << "ERROR in player " << i+1 << ": unreadable move '" << lastMove << "'" << endl;
throw StopCompetitionError();
}
if (!board.isValid(*omv, i == 0 ? -1 : 1)) {
- cout << endl << "ERROR in player " << i+1 << ": invalid move " << *omv << endl;
+ cout << "ERROR in player " << i+1 << ": invalid move " << *omv << endl;
throw StopCompetitionError();
}
@@ -425,7 +297,8 @@ match_done:
procs[i].wait();
}
- cout << mres.describe(p1, p2) << endl;
+ gMultiLog.append(logId, mres.describe(p1, p2));
+ gMultiLog.complete(logId);
gamelog << "\nResult: " << mres.describe(p1, p2) << "\n"
<< "P1 took " << mres.ms1 / 1000000.0 << " seconds\n"
@@ -435,17 +308,17 @@ match_done:
recordResult(p1, p2, mres);
}
-static void playerPit(Player &p1, Player &p2) {
+static void playerPit(Scheduler &scheduler, Player &p1, Player &p2) {
for (int i = 0; i < num_matches; i++) {
- playMatch(p1, p2, i + 1);
+ scheduler.submit([&p1, &p2, i]() { playMatch(p1, p2, i + 1); });
}
}
-static void fullCompetition(vector<Player> &players) {
+static void fullCompetition(Scheduler &scheduler, vector<Player> &players) {
for (size_t p1i = 0; p1i < players.size(); p1i++) {
for (size_t p2i = p1i + 1; p2i < players.size(); p2i++) {
- playerPit(players[p1i], players[p2i]);
- playerPit(players[p2i], players[p1i]);
+ playerPit(scheduler, players[p1i], players[p2i]);
+ playerPit(scheduler, players[p2i], players[p1i]);
}
}
}
@@ -465,7 +338,9 @@ int main(int argc, char **argv) {
mkdirp(playerlogdir);
mkdirp(gamelogdir);
- fullCompetition(players);
+ Scheduler scheduler(2);
+ fullCompetition(scheduler, players);
+ scheduler.finish();
vector<pair<string, int>> scores;
for (const Player &player : players) {