mirror of
https://github.com/QingdaoU/JudgeServer.git
synced 2025-11-04 14:50:01 +08:00
完善SpecialJudge的逻辑
This commit is contained in:
parent
d27e1e9fa8
commit
b03e9e3b30
@ -31,18 +31,20 @@ class JudgeServerClient(object):
|
|||||||
def ping(self):
|
def ping(self):
|
||||||
return self._request(self.server_base_url + "/ping")
|
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,
|
data = {"language_config": language_config,
|
||||||
"submission_id": submission_id,
|
"submission_id": submission_id,
|
||||||
"src": src,
|
"src": src,
|
||||||
"max_cpu_time": max_cpu_time,
|
"max_cpu_time": max_cpu_time,
|
||||||
"max_memory": max_memory,
|
"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)
|
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,
|
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)
|
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"""
|
cpp_src = r"""
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
@ -87,14 +96,22 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
client = JudgeServerClient(token="token", server_base_url="http://123.57.151.42:11235")
|
client = JudgeServerClient(token="token", server_base_url="http://123.57.151.42:11235")
|
||||||
print client.ping(), "\n\n"
|
print client.ping(), "\n\n"
|
||||||
print client.compile_spj(src=c_src, spj_version="4", spj_config=c_lang_config["spj"],
|
print client.compile_spj(src=c_spj_src, spj_version="1", spj_compile_config=c_lang_config["spj_compile"],
|
||||||
test_case_id="d8c460de943189a83bad166ec96d975d"), "\n\n"
|
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,
|
max_cpu_time=1000, max_memory=1024 * 1024 * 128,
|
||||||
test_case_id="d8c460de943189a83bad166ec96d975d"), "\n\n"
|
test_case_id="normal"), "\n\n"
|
||||||
time.sleep(2)
|
|
||||||
print client.judge(src=java_src, language_config=java_lang_config, submission_id=str(int(time.time())),
|
print client.judge(src=cpp_src, language_config=cpp_lang_config, submission_id="1",
|
||||||
max_cpu_time=1000, max_memory=1024 * 1024 * 128,
|
max_cpu_time=1000, max_memory=1024 * 1024 * 128,
|
||||||
test_case_id="d8c460de943189a83bad166ec96d975d"), "\n\n"
|
test_case_id="normal"), "\n\n"
|
||||||
time.sleep(2)
|
|
||||||
|
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"
|
||||||
|
|||||||
@ -15,13 +15,18 @@ c_lang_config = {
|
|||||||
"seccomp_rule": None,
|
"seccomp_rule": None,
|
||||||
"max_process_number": -1
|
"max_process_number": -1
|
||||||
},
|
},
|
||||||
"spj": {
|
"spj_compile": {
|
||||||
"src_name": "spj-{spj_version}.c",
|
"src_name": "spj-{spj_version}.c",
|
||||||
"exe_name": "spj-{spj_version}",
|
"exe_name": "spj-{spj_version}",
|
||||||
"max_cpu_time": 10000,
|
"max_cpu_time": 10000,
|
||||||
"max_real_time": 20000,
|
"max_real_time": 20000,
|
||||||
"max_memory": 1024 * 1024 * 1024,
|
"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}"
|
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -38,12 +38,9 @@ class Compiler(object):
|
|||||||
if result["result"] != _judger.RESULT_SUCCESS:
|
if result["result"] != _judger.RESULT_SUCCESS:
|
||||||
with open(compiler_out) as f:
|
with open(compiler_out) as f:
|
||||||
error = f.read().strip()
|
error = f.read().strip()
|
||||||
|
os.remove(compiler_out)
|
||||||
if error:
|
if error:
|
||||||
raise CompileError(error)
|
raise CompileError(error)
|
||||||
|
|
||||||
# 如果是spj的话, 不要在test_case文件夹中留下这个文件
|
|
||||||
os.remove(compiler_out)
|
|
||||||
|
|
||||||
raise CompileError("Compiler runtime error, info: %s" % json.dumps(result).decode("utf-8"))
|
raise CompileError("Compiler runtime error, info: %s" % json.dumps(result).decode("utf-8"))
|
||||||
|
|
||||||
return exe_path
|
return exe_path
|
||||||
|
|||||||
@ -8,8 +8,8 @@ import pwd
|
|||||||
JUDGER_WORKSPACE_BASE = "/judger_run"
|
JUDGER_WORKSPACE_BASE = "/judger_run"
|
||||||
LOG_BASE = "/log"
|
LOG_BASE = "/log"
|
||||||
|
|
||||||
COMPILER_LOG_PATH = os.path.join(LOG_BASE, "compile.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")
|
JUDGER_RUN_LOG_PATH = os.path.join(LOG_BASE, "judger.log").encode("utf-8")
|
||||||
|
|
||||||
LOW_PRIVILEDGE_UID = pwd.getpwnam("nobody").pw_uid
|
LOW_PRIVILEDGE_UID = pwd.getpwnam("nobody").pw_uid
|
||||||
LOW_PRIVILEDGE_GID = grp.getgrnam("nogroup").gr_gid
|
LOW_PRIVILEDGE_GID = grp.getgrnam("nogroup").gr_gid
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
judge_server:
|
judge_server:
|
||||||
image: judge_server
|
image: judge_server
|
||||||
volumes:
|
volumes:
|
||||||
- /data/test_case:/test_case
|
- /data/JudgeServer/test/test_case:/test_case
|
||||||
- /data/log:/log
|
- /data/log:/log
|
||||||
- /data/JudgeServer:/code
|
- /data/JudgeServer:/code
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
@ -12,12 +12,18 @@ from config import TEST_CASE_DIR, JUDGER_RUN_LOG_PATH, LOW_PRIVILEDGE_GID, LOW_P
|
|||||||
from exception import JudgeClientError
|
from exception import JudgeClientError
|
||||||
|
|
||||||
|
|
||||||
|
WA = -1
|
||||||
|
SPJ_WA = 1
|
||||||
|
SPJ_AC = 0
|
||||||
|
SPJ_ERROR = -1
|
||||||
|
|
||||||
|
|
||||||
def _run(instance, test_case_file_id):
|
def _run(instance, test_case_file_id):
|
||||||
return instance._judge_one(test_case_file_id)
|
return instance._judge_one(test_case_file_id)
|
||||||
|
|
||||||
|
|
||||||
class JudgeClient(object):
|
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._run_config = run_config
|
||||||
self._exe_path = exe_path
|
self._exe_path = exe_path
|
||||||
self._max_cpu_time = max_cpu_time
|
self._max_cpu_time = max_cpu_time
|
||||||
@ -30,6 +36,9 @@ class JudgeClient(object):
|
|||||||
self._pool = Pool(processes=psutil.cpu_count())
|
self._pool = Pool(processes=psutil.cpu_count())
|
||||||
self._test_case_info = self._load_test_case_info()
|
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):
|
def _load_test_case_info(self):
|
||||||
try:
|
try:
|
||||||
with open(os.path.join(self._test_case_dir, "info")) as f:
|
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()
|
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"]
|
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):
|
def _judge_one(self, test_case_file_id):
|
||||||
in_file = os.path.join(self._test_case_dir, str(test_case_file_id) + ".in")
|
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")
|
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),
|
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(" ")
|
max_memory=self._max_memory / 1024).split(" ")
|
||||||
@ -69,7 +105,7 @@ class JudgeClient(object):
|
|||||||
output_path=out_file,
|
output_path=out_file,
|
||||||
error_path=out_file,
|
error_path=out_file,
|
||||||
args=[item.encode("utf-8") for item in command[1::]],
|
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,
|
log_path=JUDGER_RUN_LOG_PATH,
|
||||||
seccomp_rule_so_path=self._seccomp_rule_path(self._run_config["seccomp_rule"]),
|
seccomp_rule_so_path=self._seccomp_rule_path(self._run_config["seccomp_rule"]),
|
||||||
uid=LOW_PRIVILEDGE_UID,
|
uid=LOW_PRIVILEDGE_UID,
|
||||||
@ -78,11 +114,23 @@ class JudgeClient(object):
|
|||||||
|
|
||||||
# if progress exited normally, then we should check output result
|
# if progress exited normally, then we should check output result
|
||||||
run_result["output_md5"] = None
|
run_result["output_md5"] = None
|
||||||
if run_result["result"] == 0:
|
if run_result["result"] == _judger.RESULT_SUCCESS:
|
||||||
run_result["output_md5"], is_ac = self._compare_output(test_case_file_id)
|
if self._test_case_info["spj"]:
|
||||||
# -1 == Wrong Answer
|
if not self._spj_config or not self._spj_version:
|
||||||
if not is_ac:
|
raise JudgeClientError("spj_config or spj_version not set")
|
||||||
run_result["result"] = -1
|
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
|
return run_result
|
||||||
|
|
||||||
|
|||||||
13
server.py
13
server.py
@ -6,6 +6,7 @@ import json
|
|||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import socket
|
import socket
|
||||||
|
import logging
|
||||||
|
|
||||||
import _judger
|
import _judger
|
||||||
import psutil
|
import psutil
|
||||||
@ -52,11 +53,12 @@ class JudgeServer(object):
|
|||||||
raise TokenVerificationFailed("token not set")
|
raise TokenVerificationFailed("token not set")
|
||||||
return hashlib.sha256(t).hexdigest()
|
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
|
# init
|
||||||
compile_config = language_config["compile"]
|
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"])
|
src_path = os.path.join(submission_dir, compile_config["src_name"])
|
||||||
|
|
||||||
# write source code into file
|
# write source code into file
|
||||||
@ -72,8 +74,10 @@ class JudgeServer(object):
|
|||||||
exe_path=exe_path,
|
exe_path=exe_path,
|
||||||
max_cpu_time=max_cpu_time,
|
max_cpu_time=max_cpu_time,
|
||||||
max_memory=max_memory,
|
max_memory=max_memory,
|
||||||
test_case_id=test_case_id,
|
test_case_id=str(test_case_id),
|
||||||
submission_dir=submission_dir)
|
submission_dir=submission_dir,
|
||||||
|
spj_version=str(spj_version),
|
||||||
|
spj_config=spj_config)
|
||||||
run_result = judge_client.run()
|
run_result = judge_client.run()
|
||||||
return run_result
|
return run_result
|
||||||
|
|
||||||
@ -116,6 +120,7 @@ class JudgeServer(object):
|
|||||||
return json.dumps({"err": "invalid-method", "data": None})
|
return json.dumps({"err": "invalid-method", "data": None})
|
||||||
return json.dumps({"err": None, "data": callback(**data)})
|
return json.dumps({"err": None, "data": callback(**data)})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
logging.exception(e)
|
||||||
ret = dict()
|
ret = dict()
|
||||||
ret["err"] = e.__class__.__name__
|
ret["err"] = e.__class__.__name__
|
||||||
ret["data"] = e.message
|
ret["data"] = e.message
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user