From 0f026aa18074a2467464060c658b14cc05d334a2 Mon Sep 17 00:00:00 2001 From: Paul Pan Date: Sat, 27 Apr 2024 22:02:14 +0800 Subject: [PATCH] feat: support golang --- internal/service/runner/compile.go | 2 +- internal/service/runner/new_problem.go | 3 +- internal/service/runner/problem_config.go | 48 +++++++++++-------- internal/service/runner/run_judge.go | 7 +-- .../framework/template/default/go.Makefile | 2 +- resource/runner/framework/template/go.mk | 3 +- resource/runner/problem/example/README.md | 38 ++++++++++++--- resource/runner/problem/example/config.json | 23 +++++++-- resource/runner/problem/example/std/ans.go | 9 ++++ 9 files changed, 97 insertions(+), 38 deletions(-) create mode 100644 resource/runner/problem/example/std/ans.go diff --git a/internal/service/runner/compile.go b/internal/service/runner/compile.go index 7670f8a..f8b8411 100644 --- a/internal/service/runner/compile.go +++ b/internal/service/runner/compile.go @@ -53,7 +53,7 @@ func (s *service) Compile(meta *JudgeMeta) (*JudgeStatus, e.Status) { }, Runtime: RuntimeArgs{ Rootfs: RootfsFullDir, - Pid: int64(meta.Cfg.Lang.Runtime.Compile.NProcLimit + 2), // bash + make + Pid: int64(utils.If(meta.Cfg.Lang.Runtime.Compile.NProcLimit == 0, 0, meta.Cfg.Lang.Runtime.Compile.NProcLimit+2)), // bash + make Memory: uint64(meta.Cfg.Lang.Runtime.Compile.MemoryLimit * 1024 * 1024), Timeout: time.Duration((meta.Cfg.Lang.Runtime.Compile.TimeLimit+1000)/1000) * time.Second, }, diff --git a/internal/service/runner/new_problem.go b/internal/service/runner/new_problem.go index ed3d833..82092d8 100644 --- a/internal/service/runner/new_problem.go +++ b/internal/service/runner/new_problem.go @@ -6,6 +6,7 @@ import ( "git.0x7f.app/WOJ/woj-server/pkg/down" "git.0x7f.app/WOJ/woj-server/pkg/file" "git.0x7f.app/WOJ/woj-server/pkg/unzip" + "git.0x7f.app/WOJ/woj-server/pkg/utils" "go.uber.org/zap" "os" "path/filepath" @@ -58,7 +59,7 @@ func (s *service) PrebuildProblem(meta *JudgeMeta, config *Config, force bool) e }, Runtime: RuntimeArgs{ Rootfs: RootfsFullDir, - Pid: int64(config.Prebuild.NProcLimit + 3), // sh + bash + make + Pid: int64(utils.If(config.Prebuild.NProcLimit == 0, 0, config.Prebuild.NProcLimit+3)), // sh + bash + make Memory: uint64(config.Prebuild.MemoryLimit * 1024 * 1024), Timeout: time.Duration((config.Prebuild.TimeLimit+1000)/1000) * time.Second, }, diff --git a/internal/service/runner/problem_config.go b/internal/service/runner/problem_config.go index 7e0b77c..87a7997 100644 --- a/internal/service/runner/problem_config.go +++ b/internal/service/runner/problem_config.go @@ -15,37 +15,42 @@ var ( }{ "c": {""}, "cpp": {""}, - "rust": {""}, + "go": {""}, "python3": {"/usr/bin/python3"}, "pypy3": {"/usr/bin/pypy3"}, + "rust": {""}, } ) type ConfigRuntime struct { - TimeLimit int `json:"TimeLimit"` // in ms - MemoryLimit int `json:"MemoryLimit"` // in mb - NProcLimit int `json:"NProcLimit"` - WriteFileLimit int `json:"WriteFileLimit"` // in mb + TimeLimit int `json:"TimeLimit"` // in ms + MemoryLimit int `json:"MemoryLimit"` // in mb + SoftMemoryLimit int `json:"SoftMemoryLimit"` // in mb + NProcLimit int `json:"NProcLimit"` + WriteFileLimit int `json:"WriteFileLimit"` // in mb } var ( DefaultPrebuildRuntime = ConfigRuntime{ - TimeLimit: 300000, - MemoryLimit: 256, - NProcLimit: 64, - WriteFileLimit: 1, + TimeLimit: 300000, + MemoryLimit: 256, + SoftMemoryLimit: 256, + NProcLimit: 64, + WriteFileLimit: 1024, } DefaultCompileRuntime = ConfigRuntime{ - TimeLimit: 60000, - MemoryLimit: 256, - NProcLimit: 64, - WriteFileLimit: 64, + TimeLimit: 60000, + MemoryLimit: 256, + SoftMemoryLimit: 256, + NProcLimit: 64, + WriteFileLimit: 64, } DefaultCheckRuntime = ConfigRuntime{ - TimeLimit: 60000, - MemoryLimit: 128, - NProcLimit: 64, - WriteFileLimit: 16, + TimeLimit: 60000, + MemoryLimit: 128, + SoftMemoryLimit: 128, + NProcLimit: 64, + WriteFileLimit: 16, } ) @@ -56,11 +61,16 @@ func (c *ConfigRuntime) Validate() error { if c.MemoryLimit <= 0 { return errors.New("memory limit <= 0") } + if c.SoftMemoryLimit <= 0 { + // default to memory limit + c.SoftMemoryLimit = c.MemoryLimit + } if c.NProcLimit <= 0 { - return errors.New("nproc limit <= 0") + c.NProcLimit = 0 } if c.WriteFileLimit <= 0 { - return errors.New("write file limit <= 0") + // default to 1mb + c.WriteFileLimit = 1 } return nil } diff --git a/internal/service/runner/run_judge.go b/internal/service/runner/run_judge.go index 7725d24..6146474 100644 --- a/internal/service/runner/run_judge.go +++ b/internal/service/runner/run_judge.go @@ -22,7 +22,7 @@ type ProblemRunResults map[int]*ProblemRunResult func (s *service) SandboxArgsBuilder(meta *JudgeMeta, id int) string { var args []string - args = append(args, fmt.Sprintf("--memory_limit=%d", meta.Cfg.Lang.Runtime.Run.MemoryLimit)) + args = append(args, fmt.Sprintf("--memory_limit=%d", meta.Cfg.Lang.Runtime.Run.SoftMemoryLimit)) args = append(args, fmt.Sprintf("--nproc_limit=%d", meta.Cfg.Lang.Runtime.Run.NProcLimit)) args = append(args, fmt.Sprintf("--time_limit=%d", meta.Cfg.Lang.Runtime.Run.TimeLimit)) args = append(args, fmt.Sprintf("--fsize_limit=%d", meta.Cfg.Lang.Runtime.Run.WriteFileLimit)) @@ -55,8 +55,9 @@ func (s *service) ProblemRun(meta *JudgeMeta) ProblemRunResults { runtimeArgs := RuntimeArgs{ Rootfs: RootfsRunDir, // sh, woj_launcher:program, woj_launcher:killer, woj_launcher:stat - Pid: int64(meta.Cfg.Lang.Runtime.Run.NProcLimit + 4), - Memory: uint64(meta.Cfg.Lang.Runtime.Run.MemoryLimit * 1024 * 1024), + Pid: int64(utils.If(meta.Cfg.Lang.Runtime.Run.NProcLimit == 0, 0, meta.Cfg.Lang.Runtime.Run.NProcLimit+4)), + // use SoftMemoryLimit when run, judge with MemoryLimit + Memory: uint64(meta.Cfg.Lang.Runtime.Run.SoftMemoryLimit * 1024 * 1024), // woj-sandbox killer will add 1 more second, here we add 1 also Timeout: time.Duration((meta.Cfg.Lang.Runtime.Run.TimeLimit+1000)/1000+1+1) * time.Second, } diff --git a/resource/runner/framework/template/default/go.Makefile b/resource/runner/framework/template/default/go.Makefile index 4eb0b9e..392e349 100644 --- a/resource/runner/framework/template/default/go.Makefile +++ b/resource/runner/framework/template/default/go.Makefile @@ -1,7 +1,7 @@ include ${TEMPLATE}/go.mk ${TEMPLATE}/Judger.mk compile: - @$(GO) build $(GO_BUILD_FLAGS) -o $(PREFIX)/user/$(USER_PROG).out $(PREFIX)/user/$(USER_PROG).$(LANG) + @env GOCACHE=$(GOCACHE) $(GO) build $(GO_BUILD_FLAGS) -o $(PREFIX)/user/$(USER_PROG).out $(PREFIX)/user/$(USER_PROG).$(LANG) judge: $($(CMP)) $(PREFIX)/problem/data/input/$(TEST_NUM).input $(PREFIX)/user/$(TEST_NUM).out.usr $(PREFIX)/problem/data/output/$(TEST_NUM).output $(PREFIX)/user/$(TEST_NUM).judge -appes diff --git a/resource/runner/framework/template/go.mk b/resource/runner/framework/template/go.mk index 5083376..99b38d3 100644 --- a/resource/runner/framework/template/go.mk +++ b/resource/runner/framework/template/go.mk @@ -1,2 +1,3 @@ GO=/usr/bin/go -GO_BUILD_FLAGS=-trimpath \ No newline at end of file +GO_BUILD_FLAGS=-trimpath +GOCACHE=/tmp/go-build \ No newline at end of file diff --git a/resource/runner/problem/example/README.md b/resource/runner/problem/example/README.md index 6f65c31..0c81965 100644 --- a/resource/runner/problem/example/README.md +++ b/resource/runner/problem/example/README.md @@ -34,12 +34,28 @@ "Judge" : {"Type": "custom", "Script": "custom.Makefile", "Cmp": ""}, // 运行时配置:时间(ms) 内存(MB) 进/线程数目 "Runtime": { - // 编译阶段,可选,默认值见下 - "Compile": {"TimeLimit": 60000, "MemoryLimit": 256, "NProcLimit": 64}, + // 编译阶段,可选,若缺失整个字段则替换为如下默认值 + "Compile": { + "TimeLimit" : 60000, + "MemoryLimit" : 256, + // NProcLimit 为可选字段,不填默认为 0 + "NProcLimit" : 64, + // WriteFileLimit 为可选字段,不填默认为 1 + "WriteFileLimit": 64 + }, // 运行阶段,必选 - "Run" : {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}, - // 答案检查阶段,可选,默认值见下 - "Check" : {"TimeLimit": 60000, "MemoryLimit": 128, "NProcLimit": 64} + "Run" : { + "TimeLimit" : 1000, + "MemoryLimit" : 16, + // SoftMemoryLimit 为可选字段,不填默认为 MemoryLimit + // SoftMemoryLimit 仅适用于运行时沙箱设置,实际判断内存超标时使用 MemoryLimit + "SoftMemoryLimit": 16, + "NProcLimit" : 1, + // WriteFileLimit 为可选字段,不填默认为 1 + "WriteFileLimit" : 1 + }, + // 答案检查阶段,可选,规则与 Compile 相同 + "Check" : {"TimeLimit": 60000, "MemoryLimit": 128, "NProcLimit": 64, "WriteFileLimit": 16} } }, { @@ -73,10 +89,18 @@ "Runtime": { "Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1} } + }, + { + "Lang" : "go", + "Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"}, + "Runtime": { + // Go 运行时会申请大量内存与线程 + "Run": {"TimeLimit": 1000, "MemoryLimit": 16, "SoftMemoryLimit": 1024, "NProcLimit": 0} + } } ], - // 题目构建阶段,用于生成测试数据等,可选,默认值见下 - "Prebuild" : {"TimeLimit": 300000, "MemoryLimit": 256, "NProcLimit": 64}, + // 题目构建阶段,用于生成测试数据等,可选,规则与 Compile 相同 + "Prebuild" : {"TimeLimit": 300000, "MemoryLimit": 256, "NProcLimit": 64, "WriteFileLimit": 1024}, // 评测点信息,总分应当为 100 分 "Tasks" : [ // 第一个评测点,分值 10 分,使用 ./data/{input,output}/1.{input,output} 为测试数据 diff --git a/resource/runner/problem/example/config.json b/resource/runner/problem/example/config.json index ea808b8..bef8b44 100644 --- a/resource/runner/problem/example/config.json +++ b/resource/runner/problem/example/config.json @@ -4,9 +4,15 @@ "Lang" : "c", "Judge" : {"Type": "custom", "Script": "custom.Makefile", "Cmp": ""}, "Runtime": { - "Compile": {"TimeLimit": 60000, "MemoryLimit": 256, "NProcLimit": 64}, - "Run" : {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1}, - "Check" : {"TimeLimit": 60000, "MemoryLimit": 128, "NProcLimit": 64} + "Compile": {"TimeLimit": 60000, "MemoryLimit": 256, "NProcLimit": 64, "WriteFileLimit": 64}, + "Run" : { + "TimeLimit" : 1000, + "MemoryLimit" : 16, + "SoftMemoryLimit": 16, + "NProcLimit" : 1, + "WriteFileLimit" : 1 + }, + "Check" : {"TimeLimit": 60000, "MemoryLimit": 128, "NProcLimit": 64, "WriteFileLimit": 16} } }, { @@ -27,7 +33,7 @@ "Lang" : "pypy3", "Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"}, "Runtime": { - "Run": {"TimeLimit": 1000, "MemoryLimit": 70, "NProcLimit": 1} + "Run": {"TimeLimit": 1000, "MemoryLimit": 80, "NProcLimit": 1} } }, { @@ -36,9 +42,16 @@ "Runtime": { "Run": {"TimeLimit": 1000, "MemoryLimit": 16, "NProcLimit": 1} } + }, + { + "Lang" : "go", + "Judge" : {"Type": "default", "Script": "", "Cmp": "NCMP"}, + "Runtime": { + "Run": {"TimeLimit": 1000, "MemoryLimit": 16, "SoftMemoryLimit": 1024, "NProcLimit": 0} + } } ], - "Prebuild" : {"TimeLimit": 300000, "MemoryLimit": 256, "NProcLimit": 64}, + "Prebuild" : {"TimeLimit": 300000, "MemoryLimit": 256, "NProcLimit": 64, "WriteFileLimit": 1024}, "Tasks" : [ {"Id": 1, "Points": 10}, {"Id": 2, "Points": 20}, diff --git a/resource/runner/problem/example/std/ans.go b/resource/runner/problem/example/std/ans.go new file mode 100644 index 0000000..bc2d04d --- /dev/null +++ b/resource/runner/problem/example/std/ans.go @@ -0,0 +1,9 @@ +package main + +import "fmt" + +func main() { + a, b := 0, 0 + _, _ = fmt.Scan(&a, &b) + fmt.Println(a + b) +}