Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

my huge pull request #1

Open
wants to merge 63 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
81792a8
added kvmstuff code to this repo
hawken93 Oct 27, 2014
5f57fba
fix vmcontroller utf-8 issues
hawken93 Oct 27, 2014
0a7e20f
killing vm no longer kills controller
hawken93 Oct 27, 2014
447ae5c
make these work without warnings given -O2 -Wall -Werror -lrt -std=gn…
hawken93 Oct 27, 2014
6f0316c
size_t is the correct type for get_index (c version)
hawken93 Oct 27, 2014
3bb1d33
okay, this should be damn safe
hawken93 Oct 27, 2014
d318467
add problem1 back
hawken93 Oct 27, 2014
3ed5748
Add evalstatus to objsync so clients can access it
hawken93 Oct 27, 2014
f3aa4f4
controller to measure vm startup delay
hawken93 Oct 27, 2014
504945a
configurable disk image
hawken93 Oct 28, 2014
07e798b
Moved results to a separate file, run two scoreboards and use source …
hawken93 Oct 28, 2014
a0bddf0
scoreboard update
hawken93 Oct 28, 2014
2aaeb6d
remove the annoying utf8 nbsp character that breaks the compiler
hawken93 Oct 28, 2014
43acfff
some more configurability for controller.py
hawken93 Oct 28, 2014
8c6435a
whoops...
hawken93 Oct 28, 2014
a64aac3
scoreboard/style.css
hawken93 Oct 28, 2014
ce1203e
undo the addition of problem1 - only makes the pull request messy
hawken93 Oct 28, 2014
7060c3a
substitute accidental tabs for spaces (sorry!) and remove some silly …
hawken93 Oct 28, 2014
05fba2c
kvmstuff: add inittab
hawken93 Oct 28, 2014
4c02b31
scoreboard: firefox compat
hawken93 Oct 28, 2014
4021172
whoops, email store now works again
hawken93 Oct 28, 2014
0a80af0
update readme.md
hawken93 Oct 28, 2014
55c614e
timing on todo
hawken93 Oct 28, 2014
13171f7
backend: store the code itself with the result
hawken93 Oct 28, 2014
6f9b36f
frontend: remove configview
hawken93 Oct 28, 2014
06fd3af
Make the status field one led and one variable text box
hawken93 Oct 28, 2014
cb30ab7
readme updated
hawken93 Oct 28, 2014
723a0e9
backend: more error handling to the frontend
hawken93 Oct 29, 2014
388b526
frontend: compiler output <br />
hawken93 Oct 29, 2014
dc96676
frontend: updated styles.css
hawken93 Oct 29, 2014
a7fd0e3
Merge branch 'master' of github.com:hawken93/maps-arcade
hawken93 Oct 29, 2014
3238d5c
backend: don't publish solution code to the scoreboard
hawken93 Oct 29, 2014
a1d01f8
Backend: Added /problem endpoint
martinvl Oct 29, 2014
ed88113
Frontend: Now loading problem data from server
martinvl Oct 29, 2014
74fdb75
scoreboard: CSS fixes
hawken93 Oct 29, 2014
79de5c5
backend: fix too strict sanitizing of results
hawken93 Oct 29, 2014
2939376
remove accidental tabs
hawken93 Oct 29, 2014
8228311
eval server evaluation order: alphabetically by test id
hawken93 Oct 29, 2014
2c73846
vmcontroller: soft cpu limit is now timelimit+1
hawken93 Oct 29, 2014
532ca91
controller: add handling of optional tasks
hawken93 Oct 29, 2014
1c61d10
Remove bloated output
martinvl Oct 29, 2014
3c4a276
Added problem 1
martinvl Oct 29, 2014
17d7dfa
controller: fix handling of optional tasks
hawken93 Oct 29, 2014
b37f517
Merge branch 'master' of github.com:hawken93/maps-arcade
hawken93 Oct 29, 2014
f8ee755
Fixed problem1 formatting
martinvl Oct 29, 2014
a8569ea
Fixed issue in problem 1 python tail
martinvl Oct 29, 2014
dcd4523
Fixed issue in problem 1 java head
martinvl Oct 29, 2014
c031c96
Server now forwards test optional flag
martinvl Oct 29, 2014
d61c631
Adjusted test case 16 on problem 1
martinvl Oct 29, 2014
44f5913
Fixed problem 1 text formatting
martinvl Oct 29, 2014
43da06e
Updated config to use problem 1
martinvl Oct 29, 2014
432cdc3
Fixed edge cases on sorting alg
martinvl Oct 29, 2014
e8e223a
whoops, controller.py got impatient with virtual machines when compiling
hawken93 Oct 29, 2014
6e5ec40
add extra files in kvmstuff to gitignore
hawken93 Oct 29, 2014
3db5411
backend: underscore tricks + comment inbound json debugging in Evalua…
hawken93 Oct 29, 2014
22e537f
Update Results.js to avoid potential degrading of results
hawken93 Oct 29, 2014
738699c
frontend/main.js: small indentation fix
hawken93 Oct 29, 2014
37772af
README update
hawken93 Oct 29, 2014
b917eba
shrink wheezy.img to 2.2GB so it can fit in RAM
hawken93 Oct 30, 2014
cc1eaf0
Added problem 2
martinvl Oct 30, 2014
1a219c8
Merge branch 'master' of https://github.com/hawken93/maps-arcade
martinvl Oct 30, 2014
220d621
fix problem2 C head/tail to .. work better?
hawken93 Oct 31, 2014
6f9c354
add all the junk, feel free to delete me
hawken93 Apr 17, 2015
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ frontend/scoreboard/bundle.js
*/stage
results
emails
kvmstuff/config.py
kvmstuff/config.pyc
kvmstuff/wheezy.img
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
## TODO
[ ] Ease configuration, change problem, etc.
[ ] Tighten security, chroot jail
* [ ] frontend code must get the problem from the server instead of static configuration
* [ ] scoreboard must only allow improvements per username
* [ ] more accurate timing: a good algorithm was able to get 0 microseconds :3
* [ ] probably tons more
3 changes: 3 additions & 0 deletions backend/EvaluationClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ function EvaluationClient(id, socket) {

this.idle = false;
this.ready = false;
this.cur = 0;
this.max = 0;
this.name = "unknown";
}

module.exports = EvaluationClient;
54 changes: 36 additions & 18 deletions backend/EvaluationServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@ var EventEmitter = require('events').EventEmitter;
var inherits = require('inherits');
var Q = require('q');
var WebSocketServer = require('ws').Server;
var _ = require('underscore');
var ObjDist = require('objdist');

var EvaluationClient = require('./EvaluationClient');

function EvaluationServer(problem, opts) {
function EvaluationServer(problem, opts, transport, path) {
this.problem = problem;
this.opts = opts || {};
this.evalstatus = new ObjDist(transport, {prefix:path});
this.setStatus();

this.setup();
}
Expand All @@ -32,17 +36,19 @@ EvaluationServer.prototype.evaluate = function (language, src) {
var self = this;

function send() {
self.sendSubmission(submission.data, self.getClient()).fail(function (err) {
var client = self.getClient();
if(!client) {
console.error('failed to get a client');
return false;
}
self.sendSubmission(submission.data, client).fail(function (err) {
console.error('failed sending submission to client');
console.error(err);

console.error('retrying...');
send();
});
return true;
}
send();

return submission.promise;
if(send()) return submission.promise;
return undefined;
};

// --- interal API ---
Expand Down Expand Up @@ -74,21 +80,24 @@ EvaluationServer.prototype.handleConnection = function (socket) {
});

socket.on('error', function (err) {
client.deferred.reject(err);
client.deferred.reject({event:'error', status:err});
});

socket.on('close', function () {
client.deferred.reject('connection closed');
client.deferred.reject({event:'error', status:'connection closed'});
delete self.clients[clientId];
delete self.idleClients[clientId];
self.setStatus();
});
};

EvaluationServer.prototype.handleReceivedEvent = function (payload, client) {
console.dir(payload);
// Debugs everything received from the server
//console.dir(payload);
switch (payload.event) {
case 'ready':
client.ready = true;
client.name = payload.data.name;

if (client.idle) {
this.idleClients[client.id] = client;
Expand All @@ -98,43 +107,47 @@ EvaluationServer.prototype.handleReceivedEvent = function (payload, client) {
this.sendProblem(this.problem, client);
break;
case 'freeslots':
client.idle = payload.data.cur > 0;
client.cur = payload.data.cur;
client.max = payload.data.max;
client.idle = client.cur > 0;

if (client.ready) {
if (client.idle) {
this.idleClients[client.id] = client;
} else {
delete this.idleClients[client.id];
}
this.setStatus();
}
break;
case 'compile':
var submission = this.submissions[payload.data.submissionId];

if (payload.data.success !== 0) {
submission.reject('compile', payload);
// event, status
submission.reject({event:'compile', status:payload.data});
} else {
submission.notify('compile', payload);
submission.notify({event:'compile', status:payload.data});
}
break;
case 'eval':
var submission = this.submissions[payload.data.submissionId];
submission.evalTime += payload.data.walltime;

if (payload.data.success !== 0) {
submission.reject('eval', payload);
submission.reject({event:'eval', status:payload.data.success});
} else {
++submission.numAccepted;
submission.notify('eval', submission.numAccepted);
submission.notify({event:'eval', status:submission.numAccepted});
}
break;
case 'endsub':
var submission = this.submissions[payload.data.submissionId];

if (payload.data.errstr) {
submission.reject('error', payload.data.errstr);
submission.reject({event:'error', status:payload.data.errstr});
} else {
submission.resolve(submission.evalTime, payload);
submission.resolve(submission.evalTime);
}

break;
Expand Down Expand Up @@ -185,3 +198,8 @@ EvaluationServer.prototype.sendProblem = function (problem, client) {

return deferred.promise;
};
EvaluationServer.prototype.setStatus = function () {
this.evalstatus.setObject(_.map(this.clients, function(client) {
return _.pick(client, ['id', 'name', 'max', 'cur']);
}));
};
155 changes: 155 additions & 0 deletions backend/Results.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
var EventEmitter = require('events').EventEmitter;
var inherits = require('inherits');
var ObjDist = require('objdist');
var Datastore = require('nedb');
var _ = require('underscore');

function Results(transport, prefix, filename) {
this.dist = new ObjDist(transport, {prefix:prefix});
this.store = new Datastore({filename: filename, autoload: true});
this.publishResults();
}

module.exports = Results;
inherits(Results, EventEmitter);

Results.prototype.sendResult = function(result, socket) {
var self = this;
this.once('publish', function(){
var results = self.dist.getObject();

for (var idx in results) {
var rankedResult = results[idx];

if (rankedResult.name == result.name && rankedResult.problemID == result.problemID) {
var sendResult = _.clone(result);

sendResult.rank = rankedResult.rank;
sendResult.impTime = self.formatTime(result.impTime);
sendResult.runTime = self.formatTime(result.runTime);
sendResult = _.pick(sendResult, ['problemID', 'rank', 'language', 'name', 'impTime', 'runTime', 'codeSize', 'accepted']);

socket.emit('result', sendResult);
console.dir(result);
return;
}
}
console.err("Results.prototype.sendResult: We are asked to send the result for "+result.name+" at problem "+result.problemID+" but no such result exists!");
});
};

// We are forced to call self.publishResults() at some point.
Results.prototype.addResult = function(result) {
// TODO: Q
var query = {
'problemID': result.problemID,
'name': result.name
};
var self = this;

// We need to get the results before we formatted them and added them to the public object
// Only interested in this users results
this.store.find(query, function(err, results) {
if (err) {
console.dir(err);
return;
}

var update = true;
for (var idx in results) {
var rankedResult = results[idx];

// This one is worse (Is my operator pointing the right way?)
if (result_cmp(rankedResult, result) < 0) {
console.log("Old result is better, not updating: (old, new):");
console.log(rankedResult);
console.log(result);
update = false;
} else {
console.log("New result is better, updating");
}
break;
}

if (update) {
self.store.update(query, result, {upsert:true}, function (err) {
if (err) {
console.dir(err);
return;
}

self.publishResults();
});
} else {
self.publishResults();
}
});
};

Results.prototype.formatTime = function(time) {
var formattedTime = '';

if (time < 1/1000) {
formattedTime = Math.round(time*1000000) + '&mu;s';
} else if (time < 1/10) {
formattedTime = Math.round(time*1000) + 'ms';
} else {
time = Math.round(time*100)/100;

if (time == Math.round(time)) {
formattedTime = time + '.00s';
} else if (time == Math.round(time*10)/10) {
formattedTime = time + '0s';
} else {
formattedTime = time + 's';
}
}

return formattedTime;
};

Results.prototype.getRankedResults = function(results) {
// TODO: Why copy?
var results = results.slice(0); // copy

results.sort(result_cmp);

for (var rank in results) {
results[rank].rank = parseInt(rank) + 1;
}

return results;
};

Results.prototype.publishResults = function() {
var self = this;
this.store.find({}, function(err, results) {
if (err) {
console.dir(err);
return;
}

results = self.getRankedResults(results);

for (var idx in results) {
var result = results[idx];

result.impTime = self.formatTime(result.impTime);
result.runTime = self.formatTime(result.runTime);
results[idx] = _.pick(result, ['problemID', 'rank', 'language', 'name', 'impTime', 'runTime', 'codeSize', 'accepted']);
}

self.dist.setObject(results);
self.emit('publish');
});
};

function result_cmp(lhs, rhs) {
// var lhsBadness = (1e-7 + lhs.impTime) * (1e-7 + lhs.runTime) * (1 + lhs.codeSize);
// var rhsBadness = (1e-7 + rhs.impTime) * (1e-7 + rhs.runTime) * (1 + rhs.codeSize);
// hack: ignore impTime
var lhsBadness = (1e-7 + lhs.runTime) * (1 + lhs.codeSize);
var rhsBadness = (1e-7 + rhs.runTime) * (1 + rhs.codeSize);

return lhsBadness/rhsBadness - 1;
}
Loading