Skip to content

Commit

Permalink
(wip) checker
Browse files Browse the repository at this point in the history
(ok)
  • Loading branch information
shine00chang committed Oct 9, 2024
1 parent bf66df7 commit feb08dc
Show file tree
Hide file tree
Showing 13 changed files with 6,616 additions and 106 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@ node_modules
.env
.DS_Store
replica.key
deploy/dev
!deploy/dev/docker-compose.yml
set-env.sh
1 change: 0 additions & 1 deletion packages/api-server/src/services/submission.services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ async function createSubmission ({ submission, userId, target }: { submission: N

const task: CompilingTask = {
submissionId,
problemId: problem.id,
type: JudgerTaskType.Compiling,
source: submission.source,
language: submission.language,
Expand Down
4 changes: 3 additions & 1 deletion packages/judge-daemon/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
node_modules
dist
dist
box-metas
argon-cache
117 changes: 117 additions & 0 deletions packages/judge-daemon/bits/stdc++.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// C++ includes used for precompiling -*- C++ -*-

// Copyright (C) 2003-2015 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.

// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
// <http://www.gnu.org/licenses/>.

/** @file stdc++.h
* This is an implementation file for a precompiled header.
*/

// 17.4.1.2 Headers

// C
#ifndef _GLIBCXX_NO_ASSERT
#include <cassert>
#endif
#include <cctype>
#include <cerrno>
#include <cfloat>
#include <ciso646>
#include <climits>
#include <clocale>
#include <cmath>
#include <csetjmp>
#include <csignal>
#include <cstdarg>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>

#if __cplusplus >= 201103L
#include <ccomplex>
#include <cfenv>
#include <cinttypes>
#include <cstdalign>
#include <cstdbool>
#include <cstdint>
#include <ctgmath>
#include <cwchar>
#include <cwctype>
#endif

// C++
#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <locale>
#include <map>
#include <memory>
#include <new>
#include <numeric>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <typeinfo>
#include <utility>
#include <valarray>
#include <vector>

#if __cplusplus >= 201103L
#include <array>
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <forward_list>
#include <future>
#include <initializer_list>
#include <mutex>
#include <random>
#include <ratio>
#include <regex>
#include <scoped_allocator>
#include <system_error>
#include <thread>
#include <tuple>
#include <typeindex>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#endif
46 changes: 46 additions & 0 deletions packages/judge-daemon/check.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#include "testlib.h"
#include <bits/stdc++.h>
using namespace std;

const auto YES = "YES";
const auto NO = "NO";
const auto GENERIC_WORD_PATTERN = "[a-zA-Z]+";

int test_count;

vector<string> read_answer(InStream &stream) {
vector<string> res;
for (int i = 1; i <= test_count; ++i) {
setTestCase(i);
auto token = upperCase(stream.readToken(GENERIC_WORD_PATTERN, "token"));
stream.quitif(token != YES && token != NO, _pe,
"Expected YES or NO token, but found \"%s\"",
token.c_str());
res.push_back(token);
}
stream.quitif(!stream.seekEof(), _pe, "Expected EOF after reading %d token(s)",
test_count);

return res;
}

int main(int argc, char **argv) {
registerTestlibCmd(argc, argv);
test_count = inf.readInt();

auto out_tokens = read_answer(ouf);
auto ans_tokens = read_answer(ans);

for (int i = 1; i <= test_count; ++i) {
setTestCase(i);
if (out_tokens[i - 1] != ans_tokens[i - 1]) {
quitf(_wa, "expected %s, found %s", ans_tokens[i - 1].c_str(),
out_tokens[i - 1].c_str());
}
}

quitf(_ok, "%d token(s)", test_count);

return 0;
}

39 changes: 17 additions & 22 deletions packages/judge-daemon/src/services/compile.services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { promises as fs } from 'node:fs'

import { runInSandbox } from './sandbox.services.js'

import { type CompilingTask, SandboxStatus, type CompileSucceeded, type CompileFailed, CompilingStatus } from '@argoncs/types'
import { type CompilingTask, SandboxStatus, type CompileSucceeded, type CompileFailed, CompilingStatus, type CompilingCheckerTask } from '@argoncs/types'
import { minio } from '@argoncs/common'
import { languageConfigs } from '../../configs/language.configs.js'

Expand Down Expand Up @@ -50,38 +50,33 @@ export async function compileSubmission ({ task, boxId }: { task: CompilingTask,
}
}

export async function compileChecker ({ task, boxId }: { task: CompilingTask, boxId: number }): Promise<CompileSucceeded | CompileFailed> {

export async function compileChecker ({ task, boxId }: { task: CompilingCheckerTask, boxId: number })
{
const workDir = `/var/local/lib/isolate/${boxId}/box`
const srcPath = path.join(workDir, 'checker.cpp')
const binaryPath = path.join(workDir, 'checker')
const logPath = path.join(workDir, 'checker-log.txt')
await fetchCheckerSource(srcPath);
await fs.writeFile(srcPath, task.source);

const command = '/usr/bin/g++ -o2 -w -fmax-errors=3 -std=c++17 checker.cpp -lm -o checker'

console.log('command:', command);
console.log(workDir, srcPath, binaryPath);

const result = await runInSandbox(
{
task: {
constraints: {},
command,
stderrPath: logPath,
env: 'PATH=/bin:/usr/local/bin:/usr/bin'
},
boxId
})
const result = await runInSandbox({
task: {
constraints: {},
command,
stderrPath: logPath,
env: 'PATH=/bin:/usr/local/bin:/usr/bin'
},
boxId
})

console.log('compiled')
if (result.status !== SandboxStatus.Succeeded) {
return {
status: CompilingStatus.Failed,
log: (await fs.readFile(logPath)).toString()
}
}
console.log('compiled checker')
if (result.status !== SandboxStatus.Succeeded)
throw `Checker compilation for problem ${task.problemId} failed`

await minio.fPutObject('checkers', task.problemId, binaryPath)
return { status: CompilingStatus.Succeeded }
console.log("checker put'ed")
}
46 changes: 23 additions & 23 deletions packages/judge-daemon/src/services/grading.services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ import {
runInSandbox
} from './sandbox.services.js'

import { fetchBinary, fetchTestcase } from './storage.services.js'
import {NotFoundError} from 'http-errors-enhanced'
import { fetchBinary, fetchTestcase, fetchChecker } from './storage.services.js'

export async function gradeSubmission ({ task, boxId }: { task: GradingTask, boxId: number }): Promise<GradingResult> {

const workDir = `/var/local/lib/isolate/${boxId}/box`
const config = languageConfigs[task.language]
const binaryPath = path.join(workDir, config.binaryFile)
const inputPath = path.join(workDir, 'in.txt')
const outputPath = path.join(workDir, 'out.txt');
const answerPath = path.join(workDir, 'ans.txt')
const checkerPath = path.join(workDir, 'checker');

Expand Down Expand Up @@ -47,27 +47,27 @@ export async function gradeSubmission ({ task, boxId }: { task: GradingTask, box

//return new Promise((resolve, reject) => resolve({ message: '', status: GradingStatus.Accepted, memory: 1, time: 1, wallTime: 1}));

if (sandboxResult.status === SandboxStatus.Succeeded) {
const { time, wallTime, memory } = sandboxResult
try {
await exec(`diff -Z -B ${answerPath} ${path.join(workDir, 'out.txt')}`)
return {
status: GradingStatus.Accepted,
time,
wallTime,
memory,
message: 'Submission accepted'
}
} catch (err) {
return {
status: GradingStatus.WrongAnswer,
time,
wallTime,
memory,
message: 'Wrong answer'
}
}
} else {
if (sandboxResult.status !== SandboxStatus.Succeeded)
return sandboxResult

const { time, wallTime, memory } = sandboxResult
try {
// TODO: IDK if the checker crashes or what on wrong answer. test this
await exec(`./${checkerPath} -Z -B ${answerPath} ${outputPath}`)
return {
status: GradingStatus.Accepted,
time,
wallTime,
memory,
message: 'Submission accepted'
}
} catch (err) {
return {
status: GradingStatus.WrongAnswer,
time,
wallTime,
memory,
message: 'Wrong answer'
}
}
}
37 changes: 36 additions & 1 deletion packages/judge-daemon/src/services/storage.services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ async function cacheTestcase ({ objectName, versionId }: { objectName: string, v
const key = path.join(cacheDir, 'testcases', objectName, versionId)
const size = (await minio.statObject('testcases', objectName, { versionId })).size
// @ts-expect-error typing bug
await minio.fGetObject('testcases', objectName, key, { versionId })
minio.fGetObject('testcases', objectName, key, { versionId })
cache.set(key, key, { size })
}

Expand Down Expand Up @@ -73,3 +73,38 @@ export async function fetchBinary ({ objectName, destPath }: { objectName: strin
await fs.copyFile(key, destPath)
}
}

async function cacheChecker ({ objectName, versionId }: { objectName: string, versionId: string }): Promise<void> {
// TODO: try catch. checker may not exist, throw something.
try {
const key = path.join(cacheDir, 'checkers', objectName, versionId)
const size = (await minio.statObject('checkers', objectName, { versionId })).size


// @ts-expect-error typing bug
minio.fGetObject('checkers', objectName, key, { versionId })
cache.set(key, key, { size })

} catch (err) {
console.log('cache checker error:', err)
throw "not found cache"
}
}

export async function fetchChecker ({ objectName, versionId, destPath }: { objectName: string, versionId: string, destPath: string }): Promise<void> {
const key = path.join(cacheDir, 'checkers', objectName, versionId)
if (cache.get(key) != null) {
await fs.copyFile(key, destPath); return
}
if (downloading.get(key) != null) {
await downloading.get(key)
if (cache.get(key) != null) {
await fs.copyFile(key, destPath)
}
} else {
downloading.set(key, cacheTestcase({ objectName, versionId }))
await downloading.get(key)
downloading.delete(key)
await fs.copyFile(key, destPath)
}
}
Loading

0 comments on commit feb08dc

Please sign in to comment.