From b43dfe37c8d2e713a478b1e92cf73aff696e2feb Mon Sep 17 00:00:00 2001 From: virusdefender <1670873886@qq.com> Date: Thu, 2 Jul 2015 23:39:18 +0800 Subject: [PATCH] =?UTF-8?q?judge=E5=9C=A8ubuntu=E4=B8=8A=E6=9A=82=E6=97=B6?= =?UTF-8?q?=E8=83=BD=E8=B7=91=E8=B5=B7=E6=9D=A5=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- judge/client.py | 86 +++++++++++++++++++++++++++++------------------ judge/consts.py | 17 ++++++++++ judge/settings.py | 14 +++++--- 3 files changed, 81 insertions(+), 36 deletions(-) create mode 100644 judge/consts.py diff --git a/judge/client.py b/judge/client.py index 47e9f6f..8302f75 100644 --- a/judge/client.py +++ b/judge/client.py @@ -4,7 +4,8 @@ import time import commands from Queue import Queue from thread_pool import ThreadPool -from settings import MAX_RUNNING_NUMBER, LRUN_GID, LRUN_UID, USE_TMPFS +from settings import max_running_number, lrun_gid, lrun_uid, use_tmpfs +from consts import Language, Result class JudgeClientException(Exception): @@ -18,34 +19,33 @@ class JudgeClient(object): self.language = language # 可执行文件路径,比如 /root/1/a.out /root/1/Main.class self.exec_file_path = exec_file_path - # 最大的cpu时间 + # 最大的cpu时间 单位ms self.max_cpu_time = max_cpu_time - # 最大实际运行时间 + # 最大实际运行时间 单位ms self.max_real_time = max_real_time - # 最大cpu占用,注意不要小于500000 + # 最大cpu占用,注意不要小于500000 单位byte self.max_memory = max_memory # 测试用例文件路径,比如/root/testcase/1/ self.test_case_dir = test_case_dir # 判题结果队列 self.result_queue = Queue() # 线程池 - self.thread_pool = ThreadPool(size=MAX_RUNNING_NUMBER, + self.thread_pool = ThreadPool(size=max_running_number, result_queue=self.result_queue) self.thread_pool.start() # 测试用例配置项 - self.test_case_config = {} - self.load_test_case_config() + self.test_case_info = self.load_test_case_info() - def load_test_case_config(self): - # 读取测试用例配置项 转换为dict + def load_test_case_info(self): + # 读取测试用例信息 转换为dict # try: - # f = open(self.test_case_dir + "config") - # self.test_case_config = json.loads(f.read()) + # f = open(self.test_case_dir + "info") + # return json.loads(f.read()) # except IOError: # raise JudgeClientException("Test case config file not found") # except ValueError: # raise JudgeClientException("Test case config file format error") - return {"test_case_number": 1, + return {"test_case_number": 2, "test_cases": { "1": {"input_name": "1.in", @@ -64,24 +64,26 @@ class JudgeClient(object): """ 设置相关运行限制 进制访问网络 如果启用tmpfs 就把代码输出写入tmpfs,否则写入硬盘 """ + # todo 系统调用白名单 chroot等参数 + # fixme 时间的单位问题 command = "lrun" + \ " --max-cpu-time " + str(self.max_cpu_time) + \ " --max-real-time " + str(self.max_real_time) + \ " --max-memory " + str(self.max_memory) + \ " --network false" + \ - " --uid " + str(LRUN_UID) + \ - " --gid " + str(LRUN_GID) - if USE_TMPFS: - command += (" --tmpfs /var " + - str(int(self.test_case_config["test_cases"][str(test_case_id)]["output_size"] * 1.2))) + " --uid " + str(lrun_uid) + \ + " --gid " + str(lrun_gid) + #if use_tmpfs: + # command += (" --tmpfs /var " + + # str(int(self.test_case_info["test_cases"][str(test_case_id)]["output_size"] * 1.2))) - if self.language == "java": + if self.language == Language.JAVA: command += (" java " + self.exec_file_path) else: command += (" " + self.exec_file_path) # fixme 输出路径 command += (" 0<" + self.test_case_dir + str(test_case_id) + ".in" + - " 1>" + "/var/" + str(test_case_id) + ".out" + + " 1>" + "/var/judge/" + str(test_case_id) + ".out" + " 3>&2") return command @@ -111,37 +113,57 @@ class JudgeClient(object): elif name == "EXITCODE": result[translate[name]] = int(value) elif name == "EXCEED": - if result == "none": + if value == "none": result[translate[name]] = None else: result[translate[name]] = translate[value] return result def judge_one(self, test_case_id): - command = self.generate_command(test_case_id + 1) + # 运行lrun程序 接收返回值 + command = self.generate_command(test_case_id) status_code, output = commands.getstatusoutput(command) if status_code: raise JudgeClientException(output) - return output + run_result = self.parse_lrun_output(output) + + run_result["test_case_id"] = test_case_id + + # 如果返回值非0,代表非正常结束 + if run_result["exit_code"]: + run_result["result"] = Result.RUNTIME_ERROR + return run_result + + # 代表内存或者时间超过限制了 + if run_result["exceed"]: + if run_result["exceed"] == "memory": + run_result["result"] = Result.MEMORY_LIMIT_EXCEEDED + elif run_result["exceed"] in ["cpu_time", "real_time"]: + run_result["result"] = Result.TIME_LIMIT_EXCEEDED + else: + run_result["result"] = Result.SYSTEM_ERROR + return run_result + + # 下面就是代码正常运行了 + run_result["result"] = Result.ACCEPTED + return run_result def run(self): # 添加到任务队列 - for i in range(self.test_case_config["test_case_number"]): - self.thread_pool.append_job(self.judge_one, i) + for i in range(self.test_case_info["test_case_number"]): + self.thread_pool.append_job(self.judge_one, i + 1) self.thread_pool.join() self.thread_pool.stop() - # 先判断lrun的返回结果 看是否有超过限制的 在判断输出结果 - for i in range(self.test_case_config["test_case_number"]): - result = self.parse_lrun_output(self.result_queue.get(block=False)) - - # todo + for i in range(self.test_case_info["test_case_number"]): + print self.result_queue.get(block=False) -client = JudgeClient(language="c", - exec_file_path="/root/a.out", +client = JudgeClient(language=Language.C, + exec_file_path="/var/judge/a.out", max_cpu_time=1000, max_real_time=2000, max_memory=600000, - test_case_dir="/root/test_case/p1/") + test_case_dir="/var/test_case/1/") +client.run() diff --git a/judge/consts.py b/judge/consts.py new file mode 100644 index 0000000..a1edcbb --- /dev/null +++ b/judge/consts.py @@ -0,0 +1,17 @@ +# coding=utf-8 +class Result(object): + ACCEPTED = 0 + RUNTIME_ERROR = 1 + TIME_LIMIT_EXCEEDED = 2 + MEMORY_LIMIT_EXCEEDED = 3 + COMPILE_ERROR = 4 + FORMAT_ERROR = 5 + WRONG_ANSWER = 6 + SYSTEM_ERROR = 7 + WAITING = 8 + + +class Language(object): + C = 1 + CPP = 2 + JAVA = 3 diff --git a/judge/settings.py b/judge/settings.py index 43ca379..e647239 100644 --- a/judge/settings.py +++ b/judge/settings.py @@ -3,7 +3,13 @@ # 如果MAX_RUNNING_NUMBER大于等于5,那么这5组数据就会同时进行评测,然后返回结果。 # 如果MAX_RUNNING_NUMBER小于5,为3,那么就会同时运行前三组测试数据,然后再运行后两组数据 # 这样可以避免同时运行的程序过多导致的cpu占用太高 -MAX_RUNNING_NUMBER = 10 -USE_TMPFS = True -LRUN_UID = 1001 -LRUN_GID = 1002 \ No newline at end of file +max_running_number = 10 + +# 是否使用tmpfs来缓存程序输出。开启可以提高性能,在内存不足的情况下,可以关闭 +use_tmpfs = True + +# lrun运行用户的uid +lrun_uid = 1001 + +# lrun用户组gid +lrun_gid = 1002 \ No newline at end of file