1
1
# Modified version of https://sinol3.dasie.mimuw.edu.pl/oij/jury/package/-/blob/master/runner.py
2
2
# Author of the original code: Bartosz Kostka <[email protected] >
3
3
# Version 0.6 (2021-08-29)
4
+ import subprocess
4
5
5
6
from sinol_make .commands .run .structs import ExecutionResult , ResultChange , ValidationResult , ExecutionData
6
7
from sinol_make .helpers .parsers import add_compilation_arguments
@@ -184,22 +185,34 @@ def compile(self, solution):
184
185
return False
185
186
186
187
187
- def execute_oiejq (self , command , result_file , output_file , answer_file , time_limit , memory_limit ):
188
- timeout_exit_code = os .system (command )
188
+ def execute_oiejq (self , command , input_file_path , answer_file_path ,
189
+ time_limit , memory_limit ):
190
+ env = os .environ .copy ()
191
+ env ["MEM_LIMIT" ] = f'{ memory_limit } K'
192
+ env ["MEASURE_MEM" ] = "1"
193
+ with open (input_file_path , "r" ) as input_file :
194
+ process = subprocess .Popen (command , shell = True , stdin = input_file , stdout = subprocess .PIPE , stderr = subprocess .PIPE , env = env )
195
+ process .wait ()
196
+ timeout_exit_code = process .returncode
197
+ lines = process .stderr .read ().decode ("utf-8" ).splitlines ()
198
+ output = process .stdout .read ().decode ("utf-8" ).splitlines ()
199
+
189
200
result = ExecutionResult (None , None , None )
190
- with open (result_file ) as r :
191
- for line in r :
192
- line = line .strip ()
193
- if ": " in line :
194
- (key , value ) = line .split (": " )[:2 ]
195
- if key == "Time" :
196
- result .Time = self .parse_time (value )
197
- elif key == "Memory" :
198
- result .Memory = self .parse_memory (value )
199
- else :
200
- setattr (result , key , value )
201
201
202
- if timeout_exit_code == 35072 :
202
+ for line in lines :
203
+ line = line .strip ()
204
+ if ": " in line :
205
+ (key , value ) = line .split (": " )[:2 ]
206
+ if key == "Time" :
207
+ result .Time = self .parse_time (value )
208
+ elif key == "Memory" :
209
+ result .Memory = self .parse_memory (value )
210
+ else :
211
+ setattr (result , key , value )
212
+
213
+ # If timeout kills the process, the exit code should be 137.
214
+ # But on Arch Linux it returns the negative value of the signal that killed the process.
215
+ if timeout_exit_code == 137 or timeout_exit_code == - 9 :
203
216
result .Status = "TL"
204
217
elif getattr (result , "Time" ) is not None and result .Time > time_limit :
205
218
result .Status = "TL"
@@ -212,20 +225,24 @@ def execute_oiejq(self, command, result_file, output_file, answer_file, time_lim
212
225
result .Status = "TL"
213
226
elif result .Memory > memory_limit :
214
227
result .Status = "ML"
215
- elif os .system ("diff -q -Z %s %s >/dev/null"
216
- % (output_file , answer_file )):
228
+ elif not util .lines_diff (output , open (answer_file_path ).readlines ()):
217
229
result .Status = "WA"
218
230
else :
219
231
result .Status = result .Status [:2 ]
220
232
221
233
return result
222
234
223
235
224
- def execute_time (self , command , result_file , output_file , answer_file , time_limit , memory_limit ):
225
- timeout_exit_code = os .system (command )
236
+ def execute_time (self , command , result_file_path , input_file_path , answer_file_path ,
237
+ time_limit , memory_limit ):
238
+ with open (input_file_path , "r" ) as input_file :
239
+ process = subprocess .Popen (command , stdin = input_file , stdout = subprocess .PIPE , stderr = subprocess .DEVNULL )
240
+ process .wait ()
241
+ timeout_exit_code = process .returncode
242
+ output = process .stdout .read ().decode ("utf-8" ).splitlines ()
226
243
227
244
result = ExecutionResult (None , None , None )
228
- lines = open (result_file ).readlines ()
245
+ lines = open (result_file_path ).readlines ()
229
246
program_exit_code = None
230
247
if len (lines ) == 3 :
231
248
"""
@@ -254,7 +271,7 @@ def execute_time(self, command, result_file, output_file, answer_file, time_limi
254
271
result .Status = "TL"
255
272
elif result .Memory > memory_limit :
256
273
result .Status = "ML"
257
- elif os . system ( "diff -q -Z %s %s >/dev/null" % ( output_file , answer_file )):
274
+ elif not util . lines_diff ( output , open ( answer_file_path ). readlines ( )):
258
275
result .Status = "WA"
259
276
else :
260
277
result .Status = "OK"
@@ -269,17 +286,13 @@ def run_solution(self, data_for_execution: ExecutionData):
269
286
270
287
(name , executable , test , time_limit , memory_limit , timetool_path ) = data_for_execution
271
288
file_no_ext = os .path .join (self .EXECUTIONS_DIR , name , self .extract_test_id (test ))
272
- output_file = file_no_ext + ".out"
273
289
result_file = file_no_ext + ".res"
274
290
hard_time_limit_in_s = math .ceil (2 * time_limit / 1000.0 )
275
291
276
292
if self .args .time_tool == 'oiejq' :
277
- command = "MEM_LIMIT=%sK MEASURE_MEM=true timeout -k %ds -s SIGKILL %ds %s %s <%s >%s 2>%s" \
278
- % (memory_limit , hard_time_limit_in_s ,
279
- hard_time_limit_in_s , timetool_path ,
280
- executable , test , output_file , result_file )
293
+ command = f'timeout -k { hard_time_limit_in_s } s -s SIGKILL { hard_time_limit_in_s } s "{ timetool_path } " "{ executable } "'
281
294
282
- return self .execute_oiejq (command , result_file , output_file , self .get_output_file (test ), time_limit , memory_limit )
295
+ return self .execute_oiejq (command , test , self .get_output_file (test ), time_limit , memory_limit )
283
296
elif self .args .time_tool == 'time' :
284
297
if sys .platform == 'darwin' :
285
298
timeout_name = 'gtimeout'
@@ -290,9 +303,9 @@ def run_solution(self, data_for_execution: ExecutionData):
290
303
elif sys .platform == 'win32' or sys .platform == 'cygwin' :
291
304
raise Exception ("Measuring time with GNU time on Windows is not supported." )
292
305
293
- command = f'{ timeout_name } -k { hard_time_limit_in_s } s { hard_time_limit_in_s } s ' \
294
- f'{ time_name } -f " %U\\ n%M\\ n%x" -o { result_file } { executable } < { test } > { output_file } 2>/dev/null'
295
- return self .execute_time (command , result_file , output_file , self .get_output_file (test ), time_limit , memory_limit )
306
+ command = [ f'{ timeout_name } ' , '-k' , f' { hard_time_limit_in_s } s' , f' { hard_time_limit_in_s } s' ,
307
+ f'{ time_name } ' , '-f' , ' %U\\ n%M\\ n%x' , '-o' , result_file , executable ]
308
+ return self .execute_time (command , result_file , test , self .get_output_file (test ), time_limit , memory_limit )
296
309
297
310
298
311
def update_group_status (self , group_status , new_status ):
0 commit comments