feat: judger: limit memory usage and add more docs

This commit is contained in:
Paul Pan 2023-12-23 19:50:32 +08:00
parent 976f2700ef
commit 212511d7b4
Signed by: Paul
GPG Key ID: D639BDF5BA578AF4
10 changed files with 65 additions and 26 deletions

View File

@ -5,7 +5,7 @@
```
.
├── config.json # 题目配置信息
├── description.md # (not used) 题目描述必须通过 API 提交给系统
├── description.md # (optional) 题目描述,必须通过 API 提交,使用 import 脚本时将读取该文件
├── data # 数据目录
│ ├── input # 输入数据
│ │ ├── (x).input # 第 x 组输入数据
@ -32,11 +32,12 @@
"NProcLimit": 1 // 进(线)程 限制
},
"Languages": [
// 支持的语言
// c 语言,使用自定义评测脚本,脚本为 ./judge/XYZ.Makefile
{"Lang": "c", "Type": "custom", "Script": "XYZ.Makefile", "Cmp": ""},
// c++ 语言,使用默认评测脚本,答案比对方式为 NCMP(testlib)
{"Lang": "cpp", "Type": "default", "Script": "", "Cmp": "NCMP"}
], // 支持的语言
],
"Tasks": [
// 评测点信息
{"Id": 1, "Points": 10}, // 第一个评测点,分值 25 分,使用 ./data/{input,output}/1.{input,output} 为测试数据
@ -51,7 +52,7 @@
1. 默认评测脚本目前只支持 `c` 语言和 `cpp`,参见 `../../framework/template/default/{c,cpp}.Makefile`
2. 自定义评测脚本参见 `./judge/XYZ.Makefile`
3. `prebuild.Makefile`: 题目初始化脚本,用于编译辅助程序、生成数据等。如果存在改文件,系统会在题目分发到判机后自动执行,否则跳过改步骤
3. `prebuild.Makefile`: 题目初始化脚本,用于编译辅助程序、生成数据等。如果存在该文件,系统会在题目分发到判机后自动执行,否则跳过该步骤
## 注意事项

View File

@ -3,15 +3,36 @@ include ${TEMPLATE}/c.mk ${TEMPLATE}/Judger.mk
# 评测分四个阶段
# 1. prebuild: 用于提前生成测试数据、评测器、spj等工具runner 只执行一次
# 只有 ./data, ./judge 目录可见
# 详细信息见 XYZ.Makefile
# 2. compile: 用于编译用户提交的程序
# 只有 ./user/$(USER_PROG).$(LANG) 和 ./judge 目录可见
# 目录映射情况:
# /woj/problem
# ├── judge 映射到题目目录的 ./judge <-- Readonly
# └── user 映射到题目目录的 ./user <-- 用户提交的程序在这里,命名:$(USER_PROG).$(LANG)
# 环境变量:
# USER_PROG=... <-- 一段随机字符串
# LANG=... <-- 用户提交的程序的语言,如 c, cpp
# 其余通用环境变量,详见 ubuntu-full.Dockerfile
# 执行限制:
# 目前版本硬编码限制:时间 60s内存 256mb
# 3. run: 运行用户程序
# 只有 ./data/input/*.input 和 ./user/$(USER_PROG).out 可见
# 用户输出存放于 ./user/?.out.usr
# 使用 woj-sandbox 运行,等效于 $(PREFIX)/user/$(USER_PROG).out < $(PREFIX)/data/input/$(TEST_NUM).input > $(PREFIX)/user/$(TEST_NUM).out.usr
# 4. judge: 用于判定输出结果 环境变量 TEST_NUM 表示当前测试点编号
# 所有目录 ./data ./judge ./user 可见
# 4. judge: 用于判定输出结果 环境变量 TEST_NUM 表示当前测试点编号,每个测试点都会执行一次
# 目录映射情况:
# /woj/problem
# ├── data 映射到题目目录的 ./data <-- Readonly
# ├── judge 映射到题目目录的 ./judge <-- Readonly
# └── user
# ├── $(TEST_NUM).out.usr <-- 用户程序在 $(TEST_NUM) 上的输出
# └── $(TEST_NUM).judge <-- 评测结果写在这里,格式要求为 testlib 的 XML 格式
# 环境变量:
# TEST_NUM=... <-- 当前测试点编号
# CMP=... <-- 在 config.json 中配置的比较器,如 NCMP
# 其余通用环境变量,详见 ubuntu-full.Dockerfile
# 执行限制:
# 目前版本硬编码限制:时间 60s内存 256mb
compile:
$(CC) $(CFLAGS) -o $(PREFIX)/user/$(USER_PROG).out $(PREFIX)/user/$(USER_PROG).$(LANG) $(PREFIX)/judge/gadget.c

View File

@ -2,6 +2,17 @@ include ${TEMPLATE}/c.mk ${TEMPLATE}/Judger.mk
# 当题目被下载到 runner 后,会自动执行 prebuild 阶段,判题时不会再次执行
# prebuild 阶段环境信息
# 目录映射情况:
# /woj/problem
# ├── data 映射到题目目录的 ./data
# └── judge 映射到题目目录的 ./judge
# 环境变量:
# PREFIX=/woj/problem
# 其余通用环境变量,详见 ubuntu-full.Dockerfile
# 执行限制:
# 目前版本硬编码限制:时间 300s内存 1g
prebuild:
# 生成测试数据生成工具
clang++ -I$(TESTLIB) -Ofast -o $(PREFIX)/judge/gen.out $(PREFIX)/judge/gen.cpp

View File

@ -1,9 +1,12 @@
#!/usr/bin/env bash
. common.sh
SCRIPT_PATH=$(cd "$(dirname "$0")" && pwd)
. "$SCRIPT_PATH/common.sh"
function docker_run() {
local timeout=${TIMEOUT:-10}
local network=${NETWORK:-"none"}
local memory=${MEMORY:-"256m"}
local log_file=${LOG_FILE:-"/dev/stderr"}
local log_limit=${LOG_LIMIT:-4K}
log_info "$DOCKER run with timeout $timeout"
@ -12,7 +15,7 @@ function docker_run() {
sleep "$timeout"
$DOCKER kill "$CONTAINER_NAME"
) &
$DOCKER run --rm --name "$CONTAINER_NAME" "$@" 2>&1 | head -c "$log_limit" >"$log_file"
$DOCKER run --rm --name "$CONTAINER_NAME" --network "$network" --memory "$memory" "$@" 2>&1 | head -c "$log_limit" >"$log_file"
pkill -P $$
$DOCKER kill "$CONTAINER_NAME" >/dev/null 2>&1
return 0

View File

@ -1,6 +1,7 @@
#!/usr/bin/env bash
. common.sh
SCRIPT_PATH=$(cd "$(dirname "$0")" && pwd)
. "$SCRIPT_PATH/common.sh"
cd "$(dirname "$0")"/../ || exit 1

View File

@ -1,6 +1,7 @@
#!/usr/bin/env bash
. common.sh
SCRIPT_PATH=$(cd "$(dirname "$0")" && pwd)
. "$SCRIPT_PATH/common.sh"
# get_problem_info
# extract language info and limits

View File

@ -1,8 +1,8 @@
#!/usr/bin/env bash
WORKSPACE=$(cd "$(dirname "$0")"/.. && pwd)
. "$WORKSPACE"/scripts/run_timeout.sh
. "$WORKSPACE"/scripts/common.sh
. "$WORKSPACE"/scripts/docker_run.sh
. "$WORKSPACE"/scripts/problem.sh
if [ "$1" == "" ] || [ ! -d "$WORKSPACE/problem/$1" ] || [ "$2" == "" ] || [ ! -d "$WORKSPACE/user/$2" ] || [ -z "$3" ]; then

View File

@ -1,8 +1,8 @@
#!/usr/bin/env bash
WORKSPACE=$(cd "$(dirname "$0")"/.. && pwd)
. "$WORKSPACE"/scripts/run_timeout.sh
. "$WORKSPACE"/scripts/common.sh
. "$WORKSPACE"/scripts/docker_run.sh
. "$WORKSPACE"/scripts/problem.sh
if [ "$1" == "" ] || [ ! -d "$WORKSPACE/problem/$1" ] || [ "$2" == "" ] || [ ! -d "$WORKSPACE/user/$2" ] || [ -z "$3" ]; then

View File

@ -1,8 +1,8 @@
#!/usr/bin/env bash
WORKSPACE=$(cd "$(dirname "$0")"/.. && pwd)
. "$WORKSPACE"/scripts/run_timeout.sh
. "$WORKSPACE"/scripts/common.sh
. "$WORKSPACE"/scripts/docker_run.sh
if [ "$1" == "" ] || [ ! -d "$WORKSPACE/problem/$1" ]; then
log_warn "Usage: $0 <problem> <timeout>"
@ -22,6 +22,7 @@ if [ ! -f "$WORKSPACE/problem/$1/judge/prebuild.Makefile" ]; then
fi
export TIMEOUT=${2:-300}
export MEMORY="1g"
docker_run \
-v "$WORKSPACE/problem/$1/data":/woj/problem/data \
-v "$WORKSPACE/problem/$1/judge":/woj/problem/judge \

View File

@ -1,8 +1,8 @@
#!/usr/bin/env bash
WORKSPACE=$(cd "$(dirname "$0")"/.. && pwd)
. "$WORKSPACE"/scripts/run_timeout.sh
. "$WORKSPACE"/scripts/common.sh
. "$WORKSPACE"/scripts/docker_run.sh
. "$WORKSPACE"/scripts/problem.sh
if [ "$1" == "" ] || [ ! -d "$WORKSPACE/problem/$1" ] || [ "$2" == "" ] || [ ! -d "$WORKSPACE/user/$2" ] || [ -z "$3" ]; then