完善SpecialJudge的逻辑

This commit is contained in:
virusdefender 2016-10-02 02:05:16 +08:00
parent d27e1e9fa8
commit b03e9e3b30
7 changed files with 105 additions and 33 deletions

View File

@ -31,18 +31,20 @@ class JudgeServerClient(object):
def ping(self):
return self._request(self.server_base_url + "/ping")
def judge(self, src, language_config, submission_id, max_cpu_time, max_memory, test_case_id):
def judge(self, src, language_config, submission_id, max_cpu_time, max_memory, test_case_id, spj_version=None, spj_config=None):
data = {"language_config": language_config,
"submission_id": submission_id,
"src": src,
"max_cpu_time": max_cpu_time,
"max_memory": max_memory,
"test_case_id": test_case_id}
"test_case_id": test_case_id,
"spj_version": spj_version,
"spj_config": spj_config}
return self._request(self.server_base_url + "/judge", data=data)
def compile_spj(self, src, spj_version, spj_config, test_case_id):
def compile_spj(self, src, spj_version, spj_compile_config, test_case_id):
data = {"src": src, "spj_version": spj_version,
"spj_compile_config": spj_config, "test_case_id": test_case_id}
"spj_compile_config": spj_compile_config, "test_case_id": test_case_id}
return self._request(self.server_base_url + "/compile_spj", data=data)
@ -59,6 +61,13 @@ if __name__ == "__main__":
}
"""
c_spj_src = r"""
#include <stdio.h>
int main(){
return 1;
}
"""
cpp_src = r"""
#include <iostream>
@ -87,14 +96,22 @@ if __name__ == "__main__":
client = JudgeServerClient(token="token", server_base_url="http://123.57.151.42:11235")
print client.ping(), "\n\n"
print client.compile_spj(src=c_src, spj_version="4", spj_config=c_lang_config["spj"],
test_case_id="d8c460de943189a83bad166ec96d975d"), "\n\n"
print client.compile_spj(src=c_spj_src, spj_version="1", spj_compile_config=c_lang_config["spj_compile"],
test_case_id="spj"), "\n\n"
print client.judge(src=cpp_src, language_config=cpp_lang_config, submission_id=str(int(time.time())),
print client.judge(src=c_src, language_config=c_lang_config, submission_id=str(int(time.time())),
max_cpu_time=1000, max_memory=1024 * 1024 * 128,
test_case_id="d8c460de943189a83bad166ec96d975d"), "\n\n"
time.sleep(2)
print client.judge(src=java_src, language_config=java_lang_config, submission_id=str(int(time.time())),
test_case_id="normal"), "\n\n"
print client.judge(src=cpp_src, language_config=cpp_lang_config, submission_id="1",
max_cpu_time=1000, max_memory=1024 * 1024 * 128,
test_case_id="d8c460de943189a83bad166ec96d975d"), "\n\n"
time.sleep(2)
test_case_id="normal"), "\n\n"
print client.judge(src=java_src, language_config=java_lang_config, submission_id="2",
max_cpu_time=1000, max_memory=1024 * 1024 * 1024,
test_case_id="normal"), "\n\n"
print client.judge(src=c_src, language_config=c_lang_config, submission_id="3",
max_cpu_time=1000, max_memory=1024 * 1024 * 128,
test_case_id="spj",
spj_version="1", spj_config=c_lang_config["spj_config"]), "\n\n"

View File

@ -15,13 +15,18 @@ c_lang_config = {
"seccomp_rule": None,
"max_process_number": -1
},
"spj": {
"spj_compile": {
"src_name": "spj-{spj_version}.c",
"exe_name": "spj-{spj_version}",
"max_cpu_time": 10000,
"max_real_time": 20000,
"max_memory": 1024 * 1024 * 1024,
"compile_command": "/usr/bin/gcc -DONLINE_JUDGE -O2 -w -fmax-errors=3 -std=c99 {src_path} -lm -o {exe_path}"
},
"spj_config": {
"exe_name": "spj-{spj_version}",
"command": "{exe_path} {in_file_path} {user_out_file_path}",
"seccomp_rule": "c_cpp"
}
}

View File

@ -38,12 +38,9 @@ class Compiler(object):
if result["result"] != _judger.RESULT_SUCCESS:
with open(compiler_out) as f:
error = f.read().strip()
os.remove(compiler_out)
if error:
raise CompileError(error)
# 如果是spj的话, 不要在test_case文件夹中留下这个文件
os.remove(compiler_out)
raise CompileError("Compiler runtime error, info: %s" % json.dumps(result).decode("utf-8"))
return exe_path

View File

@ -8,8 +8,8 @@ import pwd
JUDGER_WORKSPACE_BASE = "/judger_run"
LOG_BASE = "/log"
COMPILER_LOG_PATH = os.path.join(LOG_BASE, "compile.log")
JUDGER_RUN_LOG_PATH = os.path.join(LOG_BASE, "judger.log")
COMPILER_LOG_PATH = os.path.join(LOG_BASE, "compile.log").encode("utf-8")
JUDGER_RUN_LOG_PATH = os.path.join(LOG_BASE, "judger.log").encode("utf-8")
LOW_PRIVILEDGE_UID = pwd.getpwnam("nobody").pw_uid
LOW_PRIVILEDGE_GID = grp.getgrnam("nogroup").gr_gid

View File

@ -1,7 +1,7 @@
judge_server:
image: judge_server
volumes:
- /data/test_case:/test_case
- /data/JudgeServer/test/test_case:/test_case
- /data/log:/log
- /data/JudgeServer:/code
environment:

View File

@ -12,12 +12,18 @@ from config import TEST_CASE_DIR, JUDGER_RUN_LOG_PATH, LOW_PRIVILEDGE_GID, LOW_P
from exception import JudgeClientError
WA = -1
SPJ_WA = 1
SPJ_AC = 0
SPJ_ERROR = -1
def _run(instance, test_case_file_id):
return instance._judge_one(test_case_file_id)
class JudgeClient(object):
def __init__(self, run_config, exe_path, max_cpu_time, max_memory, test_case_id, submission_dir):
def __init__(self, run_config, exe_path, max_cpu_time, max_memory, test_case_id, submission_dir, spj_version, spj_config):
self._run_config = run_config
self._exe_path = exe_path
self._max_cpu_time = max_cpu_time
@ -30,6 +36,9 @@ class JudgeClient(object):
self._pool = Pool(processes=psutil.cpu_count())
self._test_case_info = self._load_test_case_info()
self._spj_version = spj_version
self._spj_config = spj_config
def _load_test_case_info(self):
try:
with open(os.path.join(self._test_case_dir, "info")) as f:
@ -52,9 +61,36 @@ class JudgeClient(object):
output_md5 = hashlib.md5(f.read().rstrip()).hexdigest()
return output_md5, output_md5 == self._test_case_info["test_cases"][str(test_case_file_id)]["striped_output_md5"]
def _spj(self, in_file_path, user_out_file_path):
command = self._spj_config["command"].format(exe_path=os.path.join(self._test_case_dir,
self._spj_config["exe_name"].format(spj_version=self._spj_version)),
in_file_path=in_file_path, user_out_file_path=user_out_file_path).split(" ")
result = _judger.run(max_cpu_time=self._max_cpu_time * 3,
max_real_time=self._max_cpu_time * 9,
max_memory=self._max_memory * 3,
max_output_size=1024 * 1024 * 1024,
max_process_number=self._run_config["max_process_number"],
exe_path=command[0].encode("utf-8"),
input_path=in_file_path.encode("utf-8"),
output_path="/tmp/spj.out".encode("utf-8"),
error_path="/tmp/spj.out".encode("utf-8"),
args=[item.encode("utf-8") for item in command[1::]],
env=[("PATH=" + os.environ.get("PATH", "")).encode("utf-8")],
log_path=JUDGER_RUN_LOG_PATH,
seccomp_rule_so_path=self._seccomp_rule_path(self._spj_config["seccomp_rule"]),
uid=LOW_PRIVILEDGE_UID,
gid=LOW_PRIVILEDGE_GID)
print result
if result["result"] == _judger.RESULT_SUCCESS or \
(result["result"] == _judger.RESULT_RUNTIME_ERROR and result["exit_code"] in [SPJ_WA, SPJ_ERROR]):
return result["exit_code"]
else:
return SPJ_ERROR
def _judge_one(self, test_case_file_id):
in_file = os.path.join(self._test_case_dir, str(test_case_file_id) + ".in")
out_file = os.path.join(self._submission_dir, str(test_case_file_id) + ".out")
in_file = os.path.join(self._test_case_dir, str(test_case_file_id) + ".in").encode("utf-8")
out_file = os.path.join(self._submission_dir, str(test_case_file_id) + ".out").encode("utf-8")
command = self._run_config["command"].format(exe_path=self._exe_path, exe_dir=os.path.dirname(self._exe_path),
max_memory=self._max_memory / 1024).split(" ")
@ -69,7 +105,7 @@ class JudgeClient(object):
output_path=out_file,
error_path=out_file,
args=[item.encode("utf-8") for item in command[1::]],
env=[("PATH=" + os.getenv("PATH")).encode("utf-8")],
env=[("PATH=" + os.getenv("PATH", "")).encode("utf-8")],
log_path=JUDGER_RUN_LOG_PATH,
seccomp_rule_so_path=self._seccomp_rule_path(self._run_config["seccomp_rule"]),
uid=LOW_PRIVILEDGE_UID,
@ -78,11 +114,23 @@ class JudgeClient(object):
# if progress exited normally, then we should check output result
run_result["output_md5"] = None
if run_result["result"] == 0:
run_result["output_md5"], is_ac = self._compare_output(test_case_file_id)
# -1 == Wrong Answer
if not is_ac:
run_result["result"] = -1
if run_result["result"] == _judger.RESULT_SUCCESS:
if self._test_case_info["spj"]:
if not self._spj_config or not self._spj_version:
raise JudgeClientError("spj_config or spj_version not set")
spj_result = self._spj(in_file_path=in_file, user_out_file_path=out_file)
print "spj_result", spj_result
if spj_result == SPJ_WA:
run_result["result"] = WA
elif spj_result == SPJ_ERROR:
run_result["result"] = _judger.RESULT_SYSTEM_ERROR
else:
run_result["output_md5"], is_ac = self._compare_output(test_case_file_id)
# -1 == Wrong Answer
if not is_ac:
run_result["result"] = WA
return run_result

View File

@ -6,6 +6,7 @@ import json
import os
import shutil
import socket
import logging
import _judger
import psutil
@ -52,11 +53,12 @@ class JudgeServer(object):
raise TokenVerificationFailed("token not set")
return hashlib.sha256(t).hexdigest()
def judge(self, language_config, submission_id, src, max_cpu_time, max_memory, test_case_id):
def judge(self, language_config, submission_id, src, max_cpu_time, max_memory, test_case_id,
spj_version=None, spj_config=None):
# init
compile_config = language_config["compile"]
with InitSubmissionEnv(JUDGER_WORKSPACE_BASE, submission_id=submission_id) as submission_dir:
with InitSubmissionEnv(JUDGER_WORKSPACE_BASE, submission_id=str(submission_id)) as submission_dir:
src_path = os.path.join(submission_dir, compile_config["src_name"])
# write source code into file
@ -72,8 +74,10 @@ class JudgeServer(object):
exe_path=exe_path,
max_cpu_time=max_cpu_time,
max_memory=max_memory,
test_case_id=test_case_id,
submission_dir=submission_dir)
test_case_id=str(test_case_id),
submission_dir=submission_dir,
spj_version=str(spj_version),
spj_config=spj_config)
run_result = judge_client.run()
return run_result
@ -116,6 +120,7 @@ class JudgeServer(object):
return json.dumps({"err": "invalid-method", "data": None})
return json.dumps({"err": None, "data": callback(**data)})
except Exception as e:
logging.exception(e)
ret = dict()
ret["err"] = e.__class__.__name__
ret["data"] = e.message