From b1ea7d9591ac722b8f4422cf3b941dbfe535a60e Mon Sep 17 00:00:00 2001 From: jon-lee Date: Sat, 24 May 2025 02:45:38 +0800 Subject: [PATCH] fix(diff): bugs on diff stdin and numerics (#16) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix problems in https://focs.ji.sjtu.edu.cn/git/JOJ/JOJ3-config-generator/issues/15 Co-authored-by: Boming Zhang Reviewed-on: https://focs.ji.sjtu.edu.cn/git/JOJ/JOJ3-config-generator/pulls/16 Reviewed-by: 张泊明518370910136 Co-authored-by: jon-lee Co-committed-by: jon-lee --- joj3_config_generator/models/const.py | 2 + joj3_config_generator/models/result.py | 9 ++- joj3_config_generator/models/task.py | 11 +++- joj3_config_generator/transformers/task.py | 24 +++++-- tests/convert/diff/case0.out | 0 tests/convert/diff/case1.out | 0 tests/convert/diff/case2.out | 0 tests/convert/diff/task.json | 75 ++++++++-------------- tests/convert/diff/task.toml | 9 ++- 9 files changed, 71 insertions(+), 59 deletions(-) create mode 100644 tests/convert/diff/case0.out create mode 100644 tests/convert/diff/case1.out create mode 100644 tests/convert/diff/case2.out diff --git a/joj3_config_generator/models/const.py b/joj3_config_generator/models/const.py index 33de35b..491371f 100644 --- a/joj3_config_generator/models/const.py +++ b/joj3_config_generator/models/const.py @@ -6,6 +6,8 @@ DEFAULT_CPU_LIMIT = Time("1s") DEFAULT_MEMORY_LIMIT = Memory("256m") DEFAULT_FILE_LIMIT = Memory("32m") DEFAULT_CASE_SCORE = 5 +DEFAULT_CLOCK_LIMIT_MULTIPLIER = 2 +DEFAULT_PROC_LIMIT = 50 JOJ3_CONFIG_ROOT = Path("/home/tt/.config/joj") TEAPOT_CONFIG_ROOT = Path("/home/tt/.config/teapot") diff --git a/joj3_config_generator/models/result.py b/joj3_config_generator/models/result.py index 4f964b8..733a6a6 100644 --- a/joj3_config_generator/models/result.py +++ b/joj3_config_generator/models/result.py @@ -3,9 +3,11 @@ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union from pydantic import BaseModel, ConfigDict, Field, field_validator from joj3_config_generator.models.const import ( + DEFAULT_CLOCK_LIMIT_MULTIPLIER, DEFAULT_CPU_LIMIT, DEFAULT_FILE_LIMIT, DEFAULT_MEMORY_LIMIT, + DEFAULT_PROC_LIMIT, ) @@ -49,10 +51,13 @@ class Cmd(BaseModel): stdout: Union[Collector, StreamOut] = Collector(name="stdout") stderr: Union[Collector, StreamOut] = Collector(name="stderr") cpu_limit: int = Field(DEFAULT_CPU_LIMIT, serialization_alias="cpuLimit") - clock_limit: int = Field(2 * DEFAULT_CPU_LIMIT, serialization_alias="clockLimit") + clock_limit: int = Field( + DEFAULT_CLOCK_LIMIT_MULTIPLIER * DEFAULT_CPU_LIMIT, + serialization_alias="clockLimit", + ) memory_limit: int = Field(DEFAULT_MEMORY_LIMIT, serialization_alias="memoryLimit") stack_limit: int = Field(0, serialization_alias="stackLimit") - proc_limit: int = Field(50, serialization_alias="procLimit") + proc_limit: int = Field(DEFAULT_PROC_LIMIT, serialization_alias="procLimit") cpu_rate_limit: int = Field(0, serialization_alias="cpuRateLimit") cpu_set_limit: str = Field("", serialization_alias="cpuSetLimit") copy_in: Dict[str, InputFile] = Field({}, serialization_alias="copyIn") diff --git a/joj3_config_generator/models/task.py b/joj3_config_generator/models/task.py index 4e99358..a946551 100644 --- a/joj3_config_generator/models/task.py +++ b/joj3_config_generator/models/task.py @@ -7,6 +7,7 @@ from pydantic import BaseModel, ConfigDict, Field, field_validator, model_valida from joj3_config_generator.models.common import Memory, Time from joj3_config_generator.models.const import ( + DEFAULT_CASE_SCORE, DEFAULT_CPU_LIMIT, DEFAULT_FILE_LIMIT, DEFAULT_MEMORY_LIMIT, @@ -51,6 +52,7 @@ class Outputs(BaseModel): class ParserDiff(BaseModel): output: Outputs = Outputs() + default_score: int = DEFAULT_CASE_SCORE class Files(BaseModel): @@ -125,9 +127,14 @@ class Stage(BaseModel): @classmethod def gather_cases(cls: Type["Stage"], values: Dict[str, Any]) -> Dict[str, Any]: cases = {k: v for k, v in values.items() if k.startswith("case")} - for key in cases: + limit = values.get("limit", {}) + parsed_cases = {} + for key, case in cases.items(): + case_with_limit = {**limit, **case.get("limit", {})} + case_for_parsing = {**case, "limit": case_with_limit} + parsed_cases[key] = case_for_parsing values.pop(key) - values["cases"] = {k: v for k, v in cases.items()} + values["cases"] = parsed_cases return values diff --git a/joj3_config_generator/transformers/task.py b/joj3_config_generator/transformers/task.py index e1b98ca..9ecb7a5 100644 --- a/joj3_config_generator/transformers/task.py +++ b/joj3_config_generator/transformers/task.py @@ -4,10 +4,15 @@ from functools import partial from pathlib import Path from typing import Any, Callable, Dict, List, Set, Tuple -from joj3_config_generator.models import const, result, task +from joj3_config_generator.models import result, task from joj3_config_generator.models.common import Memory, Time -from joj3_config_generator.models.const import JOJ3_CONFIG_ROOT +from joj3_config_generator.models.const import ( + DEFAULT_CLOCK_LIMIT_MULTIPLIER, + DEFAULT_PROC_LIMIT, + JOJ3_CONFIG_ROOT, +) from joj3_config_generator.models.task import Parser as ParserEnum +from joj3_config_generator.utils.logger import logger def get_conf_stage( @@ -194,9 +199,9 @@ def fix_diff( ), args=shlex.split(case_stage.command) if case_stage.command else None, cpu_limit=case_stage.limit.cpu, - clock_limit=2 * case_stage.limit.cpu, + clock_limit=DEFAULT_CLOCK_LIMIT_MULTIPLIER * case_stage.limit.cpu, memory_limit=case_stage.limit.mem, - proc_limit=50, + proc_limit=DEFAULT_PROC_LIMIT, ) if cmd.args == executor.with_.default.args: cmd.args = None @@ -224,13 +229,17 @@ def fix_diff( parser_cases.append(parser_case) for case in default_cases: cmd = result.OptionalCmd( - stdin=result.LocalFile(src=str(base_dir / f"{case}.in")) + stdin=result.LocalFile(src=str(base_dir / f"{case}.in")), + cpu_limit=None, + clock_limit=None, + memory_limit=None, + proc_limit=None, ) stage_cases.append(cmd) parser_case = result.DiffCasesConfig( outputs=[ result.DiffOutputConfig( - score=const.DEFAULT_CASE_SCORE, + score=task_stage.diff.default_score, file_name="stdout", answer_path=str(base_dir / f"{case}.out"), ) @@ -246,6 +255,9 @@ def get_testcases( ) -> Set[str]: # basedir here should be task_conf.root / task_conf.path testcases = set() for testcases_path in (task_root / task_path).parent.glob("**/*.in"): + if not testcases_path.with_suffix(".out").exists(): + logger.warning(f"Testcase {testcases_path} has no corresponding .out file") + continue testcases.add( str( testcases_path.relative_to((task_root / task_path).parent) diff --git a/tests/convert/diff/case0.out b/tests/convert/diff/case0.out new file mode 100644 index 0000000..e69de29 diff --git a/tests/convert/diff/case1.out b/tests/convert/diff/case1.out new file mode 100644 index 0000000..e69de29 diff --git a/tests/convert/diff/case2.out b/tests/convert/diff/case2.out new file mode 100644 index 0000000..e69de29 diff --git a/tests/convert/diff/task.json b/tests/convert/diff/task.json index 63a4607..3b902b5 100644 --- a/tests/convert/diff/task.json +++ b/tests/convert/diff/task.json @@ -29,17 +29,17 @@ }, "stdout": { "name": "stdout", - "max": 33554432, + "max": 10485760, "pipe": true }, "stderr": { "name": "stderr", - "max": 33554432, + "max": 10485760, "pipe": true }, - "cpuLimit": 1000000000, - "clockLimit": 2000000000, - "memoryLimit": 68157440, + "cpuLimit": 3000000000, + "clockLimit": 6000000000, + "memoryLimit": 10485760, "stackLimit": 0, "procLimit": 50, "cpuRateLimit": 0, @@ -71,6 +71,8 @@ "stdin": { "src": "/home/tt/.config/joj/diff/case0.in" }, + "cpuLimit": 1000000000, + "clockLimit": 2000000000, "memoryLimit": 2097152 }, { @@ -87,35 +89,26 @@ { "stdin": { "src": "/home/tt/.config/joj/diff/case9.in" - }, - "memoryLimit": 268435456 - }, - { - "stdin": { - "src": "/home/tt/.config/joj/diff/task1/subtask1/case11.in" - }, - "memoryLimit": 268435456 - }, - { - "stdin": { - "src": "/home/tt/.config/joj/diff/task1/subtask1/case10.in" - }, - "memoryLimit": 268435456 - }, - { - "stdin": { - "src": "/home/tt/.config/joj/diff/task1/case5.in" - }, - "memoryLimit": 268435456 - }, - { - "stdin": { - "src": "/home/tt/.config/joj/diff/case2.in" } }, { "stdin": { - "src": "/home/tt/.config/joj/diff/case3.in" + "src": "/home/tt/.config/joj/diff/task1/subtask1/case11.in" + } + }, + { + "stdin": { + "src": "/home/tt/.config/joj/diff/task1/subtask1/case10.in" + } + }, + { + "stdin": { + "src": "/home/tt/.config/joj/diff/task1/case5.in" + } + }, + { + "stdin": { + "src": "/home/tt/.config/joj/diff/case2.in" } }, { @@ -222,7 +215,7 @@ { "outputs": [ { - "score": 5, + "score": 100, "fileName": "stdout", "answerPath": "/home/tt/.config/joj/diff/case2.out", "forceQuitOnDiff": false, @@ -234,19 +227,7 @@ { "outputs": [ { - "score": 5, - "fileName": "stdout", - "answerPath": "/home/tt/.config/joj/diff/case3.out", - "forceQuitOnDiff": false, - "alwaysHide": false, - "compareSpace": false - } - ] - }, - { - "outputs": [ - { - "score": 5, + "score": 100, "fileName": "stdout", "answerPath": "/home/tt/.config/joj/diff/task1/case4.out", "forceQuitOnDiff": false, @@ -258,7 +239,7 @@ { "outputs": [ { - "score": 5, + "score": 100, "fileName": "stdout", "answerPath": "/home/tt/.config/joj/diff/task2/case6.out", "forceQuitOnDiff": false, @@ -270,7 +251,7 @@ { "outputs": [ { - "score": 5, + "score": 100, "fileName": "stdout", "answerPath": "/home/tt/.config/joj/diff/task2/case7.out", "forceQuitOnDiff": false, @@ -282,7 +263,7 @@ { "outputs": [ { - "score": 5, + "score": 100, "fileName": "stdout", "answerPath": "/home/tt/.config/joj/diff/task2/case8.out", "forceQuitOnDiff": false, diff --git a/tests/convert/diff/task.toml b/tests/convert/diff/task.toml index 4272f97..2f50c35 100644 --- a/tests/convert/diff/task.toml +++ b/tests/convert/diff/task.toml @@ -8,13 +8,17 @@ release.begin_time = 2024-12-29 23:59:59+08:00 name = "[joj] ex2-asan" command="./h7/build/ex2-asan -a" files.import = [ "h7/build/ex2-asan" ] -limit.mem = "65m" +limit.cpu = "3s" +limit.mem = "10m" +limit.stdout = "10m" +limit.stderr = "10m" parsers = [ "diff", "result-detail" ] result-detail.exitstatus = true result-detail.stderr = true -# will be removed as long as the name is fixed +diff.default_score = 100 + case0.diff.output.score = 5 case0.limit.cpu = "1s" case0.limit.mem = "2m" @@ -29,6 +33,7 @@ case1.diff.output.ignore_spaces = true case1.command = "./h7/build/ex2" case9.diff.output.score = 1232131 +case9.limit.mem = "10m" case11.diff.output.score = 92321