Skip to content

Commit d5a3a24

Browse files
committed
Implement submission memfd output
1 parent 315ede5 commit d5a3a24

File tree

3 files changed

+51
-13
lines changed

3 files changed

+51
-13
lines changed

dmoj/graders/interactive.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ def close(self) -> None:
104104

105105
class InteractiveGrader(StandardGrader):
106106
check: CheckerOutput
107+
memfd_output = False
107108

108109
def _launch_process(self, case, input_file=None):
109110
super()._launch_process(case, input_file=None)

dmoj/graders/standard.py

Lines changed: 49 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,32 @@
11
import logging
22
import subprocess
3+
from typing import Any
34

45
from dmoj.checkers import CheckerOutput
56
from dmoj.cptbox import TracedPopen
67
from dmoj.cptbox.lazy_bytes import LazyBytes
8+
from dmoj.cptbox.utils import MemoryIO, MmapableIO
79
from dmoj.error import OutputLimitExceeded
810
from dmoj.executors import executors
911
from dmoj.executors.base_executor import BaseExecutor
1012
from dmoj.graders.base import BaseGrader
11-
from dmoj.problem import TestCase
13+
from dmoj.judge import JudgeWorker
14+
from dmoj.problem import Problem, TestCase
1215
from dmoj.result import CheckerResult, Result
1316

1417
log = logging.getLogger('dmoj.graders')
1518

1619

1720
class StandardGrader(BaseGrader):
21+
_stdout_io: MmapableIO
22+
_stderr_io: MmapableIO
23+
_orig_fsize: int
24+
memfd_output: bool = True
25+
26+
def __init__(self, judge: 'JudgeWorker', problem: Problem, language: str, source: bytes) -> None:
27+
super().__init__(judge, problem, language, source)
28+
self._orig_fsize = self.binary.fsize
29+
1830
def grade(self, case: TestCase) -> Result:
1931
result = Result(case)
2032

@@ -83,34 +95,59 @@ def check_result(self, case: TestCase, result: Result) -> CheckerOutput:
8395
return check
8496

8597
def _launch_process(self, case: TestCase, input_file=None) -> None:
98+
stdout: Any
99+
stderr: Any
100+
101+
if self.memfd_output:
102+
stdout = self._stdout_io = MemoryIO()
103+
stderr = self._stderr_io = MemoryIO()
104+
self.binary.fsize = max(self._orig_fsize, case.config.output_limit_length + 1024, 1048576)
105+
else:
106+
stdout = subprocess.PIPE
107+
stderr = subprocess.PIPE
108+
86109
self._current_proc = self.binary.launch(
87110
time=self.problem.time_limit,
88111
memory=self.problem.memory_limit,
89112
symlinks=case.config.symlinks,
90113
stdin=input_file or subprocess.PIPE,
91-
stdout=subprocess.PIPE,
92-
stderr=subprocess.PIPE,
114+
stdout=stdout,
115+
stderr=stderr,
93116
wall_time=case.config.wall_time_factor * self.problem.time_limit,
94117
)
95118

96119
def _interact_with_process(self, case: TestCase, result: Result) -> bytes:
97120
process = self._current_proc
98121
assert process is not None
99-
try:
100-
result.proc_output, error = process.communicate(
101-
None, outlimit=case.config.output_limit_length, errlimit=1048576
102-
)
103-
except OutputLimitExceeded:
104-
error = b''
105-
process.kill()
106-
finally:
122+
123+
if self.memfd_output:
107124
process.wait()
125+
126+
result.proc_output = self._stdout_io.to_bytes()
127+
self._stdout_io.close()
128+
129+
if len(result.proc_output) > case.config.output_limit_length:
130+
process.mark_ole()
131+
132+
error = self._stderr_io.to_bytes()
133+
self._stderr_io.close()
134+
else:
135+
try:
136+
result.proc_output, error = process.communicate(
137+
None, outlimit=case.config.output_limit_length, errlimit=1048576
138+
)
139+
except OutputLimitExceeded:
140+
error = b''
141+
process.kill()
142+
finally:
143+
process.wait()
108144
return error
109145

110146
def _generate_binary(self) -> BaseExecutor:
111-
return executors[self.language].Executor(
147+
executor = executors[self.language].Executor(
112148
self.problem.id,
113149
self.source,
114150
hints=self.problem.config.hints or [],
115151
unbuffered=self.problem.config.unbuffered,
116152
)
153+
return executor

dmoj/result.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class Result:
3131
'OLE': 'yellow',
3232
'IE': 'red',
3333
}
34-
CODE_DISPLAY_ORDER = ('IE', 'TLE', 'MLE', 'OLE', 'RTE', 'IR', 'WA', 'SC')
34+
CODE_DISPLAY_ORDER = ('IE', 'OLE', 'TLE', 'MLE', 'RTE', 'IR', 'WA', 'SC')
3535

3636
def __init__(
3737
self,

0 commit comments

Comments
 (0)