Description:
change memory resolution in report to kbytes
Commit status:
[Not Reviewed]
References:
Diff options:
Comments:
0 Commit comments
0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
r164:447fdbbeac2c - - 3 files changed: 4 inserted, 4 deleted
@@ -9,246 +9,246 | |||||
|
9 | begin |
|
9 | begin |
|
10 | FileUtils.ln_s(src, des) |
|
10 | FileUtils.ln_s(src, des) |
|
11 | rescue NotImplementedError |
|
11 | rescue NotImplementedError |
|
12 | FileUtils.cp(src,des) |
|
12 | FileUtils.cp(src,des) |
|
13 | end |
|
13 | end |
|
14 | end |
|
14 | end |
|
15 |
|
15 | ||
|
16 | def self.call_and_log(error_message) |
|
16 | def self.call_and_log(error_message) |
|
17 | begin |
|
17 | begin |
|
18 | yield |
|
18 | yield |
|
19 | rescue |
|
19 | rescue |
|
20 | msg = "ERROR: #{error_message}" |
|
20 | msg = "ERROR: #{error_message}" |
|
21 | raise msg |
|
21 | raise msg |
|
22 | end |
|
22 | end |
|
23 | end |
|
23 | end |
|
24 |
|
24 | ||
|
25 | # |
|
25 | # |
|
26 | # A TestRequestRoomMaker is a helper object for Engine |
|
26 | # A TestRequestRoomMaker is a helper object for Engine |
|
27 | # - finds grading room: in user_result_dir/(user)/test_request/ ... |
|
27 | # - finds grading room: in user_result_dir/(user)/test_request/ ... |
|
28 | # - prepare problem configuration for grading --- basically it copy |
|
28 | # - prepare problem configuration for grading --- basically it copy |
|
29 | # all config files, and copy user's input into the testcase |
|
29 | # all config files, and copy user's input into the testcase |
|
30 | # directory. First, it finds the template from problem template |
|
30 | # directory. First, it finds the template from problem template |
|
31 | # directory; if it can't find a template, it'll use the template |
|
31 | # directory; if it can't find a template, it'll use the template |
|
32 | # from default template. |
|
32 | # from default template. |
|
33 | class TestRequestRoomMaker |
|
33 | class TestRequestRoomMaker |
|
34 | def initialize |
|
34 | def initialize |
|
35 | @config = Grader::Configuration.get_instance |
|
35 | @config = Grader::Configuration.get_instance |
|
36 | end |
|
36 | end |
|
37 |
|
37 | ||
|
38 | def produce_grading_room(test_request) |
|
38 | def produce_grading_room(test_request) |
|
39 | grading_room = grading_room_dir(test_request) |
|
39 | grading_room = grading_room_dir(test_request) |
|
40 | FileUtils.mkdir_p(grading_room) |
|
40 | FileUtils.mkdir_p(grading_room) |
|
41 |
|
41 | ||
|
42 | # |
|
42 | # |
|
43 | # Also copy additional submitted file to this directory as well. |
|
43 | # Also copy additional submitted file to this directory as well. |
|
44 | # The program would see this file only if it is copied |
|
44 | # The program would see this file only if it is copied |
|
45 | # to the sandbox directory later. The run script should do it. |
|
45 | # to the sandbox directory later. The run script should do it. |
|
46 | # |
|
46 | # |
|
47 | if FileTest.exists?("#{test_request.input_file_name}.files") |
|
47 | if FileTest.exists?("#{test_request.input_file_name}.files") |
|
48 | FileUtils.cp_r("#{test_request.input_file_name}.files/.", |
|
48 | FileUtils.cp_r("#{test_request.input_file_name}.files/.", |
|
49 | "#{grading_room}") |
|
49 | "#{grading_room}") |
|
50 | end |
|
50 | end |
|
51 |
|
51 | ||
|
52 | grading_room |
|
52 | grading_room |
|
53 | end |
|
53 | end |
|
54 |
|
54 | ||
|
55 | def find_problem_home(test_request) |
|
55 | def find_problem_home(test_request) |
|
56 | problem_name = test_request.problem_name |
|
56 | problem_name = test_request.problem_name |
|
57 |
|
57 | ||
|
58 | template_dir = "#{@config.test_request_problem_templates_dir}/" + problem_name |
|
58 | template_dir = "#{@config.test_request_problem_templates_dir}/" + problem_name |
|
59 |
|
59 | ||
|
60 | raise "Test Request: error template not found" if !File.exists?(template_dir) |
|
60 | raise "Test Request: error template not found" if !File.exists?(template_dir) |
|
61 |
|
61 | ||
|
62 | problem_home = problem_home_dir(test_request) |
|
62 | problem_home = problem_home_dir(test_request) |
|
63 | FileUtils.mkdir_p(problem_home) |
|
63 | FileUtils.mkdir_p(problem_home) |
|
64 |
|
64 | ||
|
65 | copy_problem_template(template_dir,problem_home) |
|
65 | copy_problem_template(template_dir,problem_home) |
|
66 | link_input_file(test_request,problem_home) |
|
66 | link_input_file(test_request,problem_home) |
|
67 |
|
67 | ||
|
68 | problem_home |
|
68 | problem_home |
|
69 | end |
|
69 | end |
|
70 |
|
70 | ||
|
71 | def save_source(test_request,source_name) |
|
71 | def save_source(test_request,source_name) |
|
72 | dir = self.produce_grading_room(test_request) |
|
72 | dir = self.produce_grading_room(test_request) |
|
73 | submission = test_request.submission |
|
73 | submission = test_request.submission |
|
74 | f = File.open("#{dir}/#{source_name}","w") |
|
74 | f = File.open("#{dir}/#{source_name}","w") |
|
75 | f.write(submission.source) |
|
75 | f.write(submission.source) |
|
76 | f.close |
|
76 | f.close |
|
77 | end |
|
77 | end |
|
78 |
|
78 | ||
|
79 | def clean_up(test_request) |
|
79 | def clean_up(test_request) |
|
80 | problem_home = problem_home_dir(test_request) |
|
80 | problem_home = problem_home_dir(test_request) |
|
81 | remove_data_files(problem_home) |
|
81 | remove_data_files(problem_home) |
|
82 | end |
|
82 | end |
|
83 |
|
83 | ||
|
84 | protected |
|
84 | protected |
|
85 | def grading_room_dir(test_request) |
|
85 | def grading_room_dir(test_request) |
|
86 | problem_name = test_request.problem_name |
|
86 | problem_name = test_request.problem_name |
|
87 | user = test_request.user |
|
87 | user = test_request.user |
|
88 | grading_room = "#{@config.user_result_dir}" + |
|
88 | grading_room = "#{@config.user_result_dir}" + |
|
89 | "/#{user.login}/test_request" + |
|
89 | "/#{user.login}/test_request" + |
|
90 | "/#{problem_name}/#{test_request.id}" |
|
90 | "/#{problem_name}/#{test_request.id}" |
|
91 | grading_room |
|
91 | grading_room |
|
92 | end |
|
92 | end |
|
93 |
|
93 | ||
|
94 | def problem_home_dir(test_request) |
|
94 | def problem_home_dir(test_request) |
|
95 | problem_name = test_request.problem_name |
|
95 | problem_name = test_request.problem_name |
|
96 | user = test_request.user |
|
96 | user = test_request.user |
|
97 | "#{@config.user_result_dir}" + |
|
97 | "#{@config.user_result_dir}" + |
|
98 | "/#{user.login}/test_request/#{problem_name}" |
|
98 | "/#{user.login}/test_request/#{problem_name}" |
|
99 | end |
|
99 | end |
|
100 |
|
100 | ||
|
101 | def copy_problem_template(template_dir,problem_home) |
|
101 | def copy_problem_template(template_dir,problem_home) |
|
102 | Grader::call_and_log("Test Request: cannot copy problem template") { |
|
102 | Grader::call_and_log("Test Request: cannot copy problem template") { |
|
103 | FileUtils.cp_r("#{template_dir}/.","#{problem_home}") |
|
103 | FileUtils.cp_r("#{template_dir}/.","#{problem_home}") |
|
104 | } |
|
104 | } |
|
105 | end |
|
105 | end |
|
106 |
|
106 | ||
|
107 | def link_input_file(test_request, problem_home) |
|
107 | def link_input_file(test_request, problem_home) |
|
108 | input_fname = "#{test_request.input_file_name}" |
|
108 | input_fname = "#{test_request.input_file_name}" |
|
109 | if !File.exists?(input_fname) |
|
109 | if !File.exists?(input_fname) |
|
110 | raise "Test Request: input file not found." |
|
110 | raise "Test Request: input file not found." |
|
111 | end |
|
111 | end |
|
112 |
|
112 | ||
|
113 | input_fname_problem_home = "#{problem_home}/test_cases/1/input-1.txt" |
|
113 | input_fname_problem_home = "#{problem_home}/test_cases/1/input-1.txt" |
|
114 | if File.exists?(input_fname_problem_home) |
|
114 | if File.exists?(input_fname_problem_home) |
|
115 | FileUtils.rm([input_fname_problem_home], :force => true) |
|
115 | FileUtils.rm([input_fname_problem_home], :force => true) |
|
116 | end |
|
116 | end |
|
117 |
|
117 | ||
|
118 | Grader::link_or_copy("#{input_fname}", "#{input_fname_problem_home}") |
|
118 | Grader::link_or_copy("#{input_fname}", "#{input_fname_problem_home}") |
|
119 | end |
|
119 | end |
|
120 |
|
120 | ||
|
121 | def remove_data_files(problem_home) |
|
121 | def remove_data_files(problem_home) |
|
122 | if File.exists?("#{problem_home}/test_cases/1/input-1.txt") |
|
122 | if File.exists?("#{problem_home}/test_cases/1/input-1.txt") |
|
123 | Grader::call_and_log("Test Request: cannot remove data files") { |
|
123 | Grader::call_and_log("Test Request: cannot remove data files") { |
|
124 | FileUtils.rm Dir.glob("#{problem_home}/test_cases/1/*") |
|
124 | FileUtils.rm Dir.glob("#{problem_home}/test_cases/1/*") |
|
125 | } |
|
125 | } |
|
126 | end |
|
126 | end |
|
127 | end |
|
127 | end |
|
128 |
|
128 | ||
|
129 | end |
|
129 | end |
|
130 |
|
130 | ||
|
131 | class TestRequestReporter |
|
131 | class TestRequestReporter |
|
132 | def initialize |
|
132 | def initialize |
|
133 | @config = Grader::Configuration.get_instance |
|
133 | @config = Grader::Configuration.get_instance |
|
134 | end |
|
134 | end |
|
135 |
|
135 | ||
|
136 | def report(test_request,test_result_dir) |
|
136 | def report(test_request,test_result_dir) |
|
137 | save_result(test_request,read_result(test_result_dir)) |
|
137 | save_result(test_request,read_result(test_result_dir)) |
|
138 | end |
|
138 | end |
|
139 |
|
139 | ||
|
140 | def report_error(test_request, msg) |
|
140 | def report_error(test_request, msg) |
|
141 | save_result(test_request, {:running_stat => { |
|
141 | save_result(test_request, {:running_stat => { |
|
142 | :msg => "#{msg}", |
|
142 | :msg => "#{msg}", |
|
143 | :running_time => nil, |
|
143 | :running_time => nil, |
|
144 | :exit_status => "Some error occured. Program did not run", |
|
144 | :exit_status => "Some error occured. Program did not run", |
|
145 | :memory_usage => nil |
|
145 | :memory_usage => nil |
|
146 | }}) |
|
146 | }}) |
|
147 | end |
|
147 | end |
|
148 |
|
148 | ||
|
149 | protected |
|
149 | protected |
|
150 | def read_result(test_result_dir) |
|
150 | def read_result(test_result_dir) |
|
151 | # TODO: |
|
151 | # TODO: |
|
152 | cmp_msg_fname = "#{test_result_dir}/compiler_message" |
|
152 | cmp_msg_fname = "#{test_result_dir}/compiler_message" |
|
153 | cmp_file = File.open(cmp_msg_fname) |
|
153 | cmp_file = File.open(cmp_msg_fname) |
|
154 | cmp_msg = cmp_file.read |
|
154 | cmp_msg = cmp_file.read |
|
155 | cmp_file.close |
|
155 | cmp_file.close |
|
156 |
|
156 | ||
|
157 | result_file_name = "#{test_result_dir}/1/result" |
|
157 | result_file_name = "#{test_result_dir}/1/result" |
|
158 |
|
158 | ||
|
159 | if File.exists?(result_file_name) |
|
159 | if File.exists?(result_file_name) |
|
160 | output_file_name = "#{test_result_dir}/1/output.txt" |
|
160 | output_file_name = "#{test_result_dir}/1/output.txt" |
|
161 | results = [] |
|
161 | results = [] |
|
162 | File.open("#{test_result_dir}/1/result") do |f| |
|
162 | File.open("#{test_result_dir}/1/result") do |f| |
|
163 | results = f.readlines |
|
163 | results = f.readlines |
|
164 | end |
|
164 | end |
|
165 | stat = extract_running_stat(results) |
|
165 | stat = extract_running_stat(results) |
|
166 |
|
166 | ||
|
167 | return { |
|
167 | return { |
|
168 | :output_file_name => output_file_name, |
|
168 | :output_file_name => output_file_name, |
|
169 | :running_stat => stat, |
|
169 | :running_stat => stat, |
|
170 | :comment => "", |
|
170 | :comment => "", |
|
171 | :cmp_msg => cmp_msg} |
|
171 | :cmp_msg => cmp_msg} |
|
172 | else |
|
172 | else |
|
173 | return { |
|
173 | return { |
|
174 | :running_stat => nil, |
|
174 | :running_stat => nil, |
|
175 | :comment => "Compilation error", |
|
175 | :comment => "Compilation error", |
|
176 | :cmp_msg => cmp_msg} |
|
176 | :cmp_msg => cmp_msg} |
|
177 | end |
|
177 | end |
|
178 | end |
|
178 | end |
|
179 |
|
179 | ||
|
180 | def extract_running_stat(results) |
|
180 | def extract_running_stat(results) |
|
181 | running_stat_line = results[-1] |
|
181 | running_stat_line = results[-1] |
|
182 |
|
182 | ||
|
183 | # extract exit status line |
|
183 | # extract exit status line |
|
184 | run_stat = "" |
|
184 | run_stat = "" |
|
185 | if !(/[Cc]orrect/.match(results[0])) |
|
185 | if !(/[Cc]orrect/.match(results[0])) |
|
186 | run_stat = results[0].chomp |
|
186 | run_stat = results[0].chomp |
|
187 | else |
|
187 | else |
|
188 | run_stat = 'Program exited normally' |
|
188 | run_stat = 'Program exited normally' |
|
189 | end |
|
189 | end |
|
190 |
|
190 | ||
|
191 | # extract running time |
|
191 | # extract running time |
|
192 | if res = /r(.*)u(.*)s/.match(running_stat_line) |
|
192 | if res = /r(.*)u(.*)s/.match(running_stat_line) |
|
193 | seconds = (res[1].to_f + res[2].to_f) |
|
193 | seconds = (res[1].to_f + res[2].to_f) |
|
194 | time_stat = "Time used: #{seconds} sec." |
|
194 | time_stat = "Time used: #{seconds} sec." |
|
195 | else |
|
195 | else |
|
196 | seconds = nil |
|
196 | seconds = nil |
|
197 | time_stat = "Time used: n/a sec." |
|
197 | time_stat = "Time used: n/a sec." |
|
198 | end |
|
198 | end |
|
199 |
|
199 | ||
|
200 | # extract memory usage |
|
200 | # extract memory usage |
|
201 |
- if res = /s(.*) |
|
201 | + if res = /s(.*)kbytes/.match(running_stat_line) |
|
202 | memory_used = res[1].to_i |
|
202 | memory_used = res[1].to_i |
|
203 | else |
|
203 | else |
|
204 | memory_used = -1 |
|
204 | memory_used = -1 |
|
205 | end |
|
205 | end |
|
206 |
|
206 | ||
|
207 | return { |
|
207 | return { |
|
208 | :msg => "#{run_stat}\n#{time_stat}", |
|
208 | :msg => "#{run_stat}\n#{time_stat}", |
|
209 | :running_time => seconds, |
|
209 | :running_time => seconds, |
|
210 | :exit_status => run_stat, |
|
210 | :exit_status => run_stat, |
|
211 | :memory_usage => memory_used |
|
211 | :memory_usage => memory_used |
|
212 | } |
|
212 | } |
|
213 | end |
|
213 | end |
|
214 |
|
214 | ||
|
215 | def save_result(test_request,result) |
|
215 | def save_result(test_request,result) |
|
216 | if result[:output_file_name]!=nil |
|
216 | if result[:output_file_name]!=nil |
|
217 | test_request.output_file_name = link_output_file(test_request, |
|
217 | test_request.output_file_name = link_output_file(test_request, |
|
218 | result[:output_file_name]) |
|
218 | result[:output_file_name]) |
|
219 | end |
|
219 | end |
|
220 | test_request.graded_at = Time.now |
|
220 | test_request.graded_at = Time.now |
|
221 | test_request.compiler_message = (result[:cmp_msg] or '') |
|
221 | test_request.compiler_message = (result[:cmp_msg] or '') |
|
222 | test_request.grader_comment = (result[:comment] or '') |
|
222 | test_request.grader_comment = (result[:comment] or '') |
|
223 | if result[:running_stat]!=nil |
|
223 | if result[:running_stat]!=nil |
|
224 | test_request.running_stat = (result[:running_stat][:msg] or '') |
|
224 | test_request.running_stat = (result[:running_stat][:msg] or '') |
|
225 | test_request.running_time = (result[:running_stat][:running_time] or nil) |
|
225 | test_request.running_time = (result[:running_stat][:running_time] or nil) |
|
226 | test_request.exit_status = result[:running_stat][:exit_status] |
|
226 | test_request.exit_status = result[:running_stat][:exit_status] |
|
227 | test_request.memory_usage = result[:running_stat][:memory_usage] |
|
227 | test_request.memory_usage = result[:running_stat][:memory_usage] |
|
228 | else |
|
228 | else |
|
229 | test_request.running_stat = '' |
|
229 | test_request.running_stat = '' |
|
230 | end |
|
230 | end |
|
231 | test_request.save |
|
231 | test_request.save |
|
232 | end |
|
232 | end |
|
233 |
|
233 | ||
|
234 | protected |
|
234 | protected |
|
235 | def link_output_file(test_request, fname) |
|
235 | def link_output_file(test_request, fname) |
|
236 | target_file_name = random_output_file_name(test_request.user, |
|
236 | target_file_name = random_output_file_name(test_request.user, |
|
237 | test_request.problem) |
|
237 | test_request.problem) |
|
238 | FileUtils.mkdir_p(File.dirname(target_file_name)) |
|
238 | FileUtils.mkdir_p(File.dirname(target_file_name)) |
|
239 | Grader::link_or_copy("#{fname}", "#{target_file_name}") |
|
239 | Grader::link_or_copy("#{fname}", "#{target_file_name}") |
|
240 | return target_file_name |
|
240 | return target_file_name |
|
241 | end |
|
241 | end |
|
242 |
|
242 | ||
|
243 | def random_output_file_name(user,problem) |
|
243 | def random_output_file_name(user,problem) |
|
244 | problem_name = TestRequest.name_of(problem) |
|
244 | problem_name = TestRequest.name_of(problem) |
|
245 | begin |
|
245 | begin |
|
246 | tmpname = "#{@config.test_request_output_base_dir}" + |
|
246 | tmpname = "#{@config.test_request_output_base_dir}" + |
|
247 | "/#{user.login}/#{problem_name}/#{rand(10000)}" |
|
247 | "/#{user.login}/#{problem_name}/#{rand(10000)}" |
|
248 | end while File.exists?(tmpname) |
|
248 | end while File.exists?(tmpname) |
|
249 | tmpname |
|
249 | tmpname |
|
250 | end |
|
250 | end |
|
251 |
|
251 | ||
|
252 | end |
|
252 | end |
|
253 |
|
253 | ||
|
254 | end |
|
254 | end |
@@ -1,404 +1,404 | |||||
|
1 | /* |
|
1 | /* |
|
2 | * A Simple Sandbox for Moe |
|
2 | * A Simple Sandbox for Moe |
|
3 | * |
|
3 | * |
|
4 | * (c) 2001--2010 Martin Mares <mj@ucw.cz> |
|
4 | * (c) 2001--2010 Martin Mares <mj@ucw.cz> |
|
5 | */ |
|
5 | */ |
|
6 |
|
6 | ||
|
7 | #define _LARGEFILE64_SOURCE |
|
7 | #define _LARGEFILE64_SOURCE |
|
8 | #define _GNU_SOURCE |
|
8 | #define _GNU_SOURCE |
|
9 |
|
9 | ||
|
10 | /* Generated automatically by ./configure, please don't touch manually. */ |
|
10 | /* Generated automatically by ./configure, please don't touch manually. */ |
|
11 | #define CONFIG_BOX_KERNEL_AMD64 1 |
|
11 | #define CONFIG_BOX_KERNEL_AMD64 1 |
|
12 | #define CONFIG_BOX_USER_AMD64 1 |
|
12 | #define CONFIG_BOX_USER_AMD64 1 |
|
13 | #define CONFIG_DIR "cf" |
|
13 | #define CONFIG_DIR "cf" |
|
14 | #define CONFIG_DIRECT_IO 1 |
|
14 | #define CONFIG_DIRECT_IO 1 |
|
15 | #define CONFIG_ISOLATE_BOX_DIR "/tmp/box" |
|
15 | #define CONFIG_ISOLATE_BOX_DIR "/tmp/box" |
|
16 | #define CONFIG_ISOLATE_CGROUP_ROOT "/sys/fs/cgroup" |
|
16 | #define CONFIG_ISOLATE_CGROUP_ROOT "/sys/fs/cgroup" |
|
17 | #define CONFIG_ISOLATE_FIRST_GID 60000 |
|
17 | #define CONFIG_ISOLATE_FIRST_GID 60000 |
|
18 | #define CONFIG_ISOLATE_FIRST_UID 60000 |
|
18 | #define CONFIG_ISOLATE_FIRST_UID 60000 |
|
19 | #define CONFIG_ISOLATE_NUM_BOXES 100 |
|
19 | #define CONFIG_ISOLATE_NUM_BOXES 100 |
|
20 | #define CONFIG_LARGE_FILES 1 |
|
20 | #define CONFIG_LARGE_FILES 1 |
|
21 | #define CONFIG_LFS 1 |
|
21 | #define CONFIG_LFS 1 |
|
22 | #define CONFIG_LINUX 1 |
|
22 | #define CONFIG_LINUX 1 |
|
23 | #define CONFIG_LOCAL 1 |
|
23 | #define CONFIG_LOCAL 1 |
|
24 | #define CONFIG_UCW_PARTMAP_IS_MMAP 1 |
|
24 | #define CONFIG_UCW_PARTMAP_IS_MMAP 1 |
|
25 | #define CONFIG_UCW_PERL 1 |
|
25 | #define CONFIG_UCW_PERL 1 |
|
26 | #define CONFIG_UCW_POOL_IS_MMAP 1 |
|
26 | #define CONFIG_UCW_POOL_IS_MMAP 1 |
|
27 | #define CONFIG_UCW_RADIX_SORTER_BITS 10 |
|
27 | #define CONFIG_UCW_RADIX_SORTER_BITS 10 |
|
28 | #define CONFIG_UCW_SHELL_UTILS 1 |
|
28 | #define CONFIG_UCW_SHELL_UTILS 1 |
|
29 | #define CPU_64BIT_POINTERS 1 |
|
29 | #define CPU_64BIT_POINTERS 1 |
|
30 | #define CPU_ALLOW_UNALIGNED 1 |
|
30 | #define CPU_ALLOW_UNALIGNED 1 |
|
31 | #define CPU_AMD64 1 |
|
31 | #define CPU_AMD64 1 |
|
32 | #define CPU_ARCH "default" |
|
32 | #define CPU_ARCH "default" |
|
33 | #define CPU_LITTLE_ENDIAN 1 |
|
33 | #define CPU_LITTLE_ENDIAN 1 |
|
34 | #define CPU_PAGE_SIZE 4096 |
|
34 | #define CPU_PAGE_SIZE 4096 |
|
35 | #define CPU_STRUCT_ALIGN 8 |
|
35 | #define CPU_STRUCT_ALIGN 8 |
|
36 | #define CWARNS_OFF " -Wno-pointer-sign" |
|
36 | #define CWARNS_OFF " -Wno-pointer-sign" |
|
37 | #define HAVE_ASCII_DOC "none" |
|
37 | #define HAVE_ASCII_DOC "none" |
|
38 | #define INSTALL_BIN_DIR "bin" |
|
38 | #define INSTALL_BIN_DIR "bin" |
|
39 | #define INSTALL_CONFIG_DIR "cf" |
|
39 | #define INSTALL_CONFIG_DIR "cf" |
|
40 | #define INSTALL_DOC_DIR "share/doc" |
|
40 | #define INSTALL_DOC_DIR "share/doc" |
|
41 | #define INSTALL_INCLUDE_DIR "include" |
|
41 | #define INSTALL_INCLUDE_DIR "include" |
|
42 | #define INSTALL_LIB_DIR "lib" |
|
42 | #define INSTALL_LIB_DIR "lib" |
|
43 | #define INSTALL_LOG_DIR "log" |
|
43 | #define INSTALL_LOG_DIR "log" |
|
44 | #define INSTALL_MAN_DIR "share/man" |
|
44 | #define INSTALL_MAN_DIR "share/man" |
|
45 | #define INSTALL_PERL_DIR "lib/perl5" |
|
45 | #define INSTALL_PERL_DIR "lib/perl5" |
|
46 | #define INSTALL_PKGCONFIG_DIR "lib/pkgconfig" |
|
46 | #define INSTALL_PKGCONFIG_DIR "lib/pkgconfig" |
|
47 | #define INSTALL_PREFIX |
|
47 | #define INSTALL_PREFIX |
|
48 | #define INSTALL_RUN_DIR "run" |
|
48 | #define INSTALL_RUN_DIR "run" |
|
49 | #define INSTALL_SBIN_DIR "sbin" |
|
49 | #define INSTALL_SBIN_DIR "sbin" |
|
50 | #define INSTALL_SHARE_DIR "share" |
|
50 | #define INSTALL_SHARE_DIR "share" |
|
51 | #define INSTALL_STATE_DIR "lib" |
|
51 | #define INSTALL_STATE_DIR "lib" |
|
52 | #define INSTALL_USR_PREFIX |
|
52 | #define INSTALL_USR_PREFIX |
|
53 | #define INSTALL_VAR_PREFIX |
|
53 | #define INSTALL_VAR_PREFIX |
|
54 | #define SHERLOCK_VERSION "3.99.2" |
|
54 | #define SHERLOCK_VERSION "3.99.2" |
|
55 | #define SHERLOCK_VERSION_CODE 3099002 |
|
55 | #define SHERLOCK_VERSION_CODE 3099002 |
|
56 | #define SONAME_PREFIX "lib/" |
|
56 | #define SONAME_PREFIX "lib/" |
|
57 | #define UCW_VERSION "3.99.2" |
|
57 | #define UCW_VERSION "3.99.2" |
|
58 | #define UCW_VERSION_CODE 3099002 |
|
58 | #define UCW_VERSION_CODE 3099002 |
|
59 |
|
59 | ||
|
60 | #include <errno.h> |
|
60 | #include <errno.h> |
|
61 | #include <stdio.h> |
|
61 | #include <stdio.h> |
|
62 | #include <fcntl.h> |
|
62 | #include <fcntl.h> |
|
63 | #include <stdlib.h> |
|
63 | #include <stdlib.h> |
|
64 | #include <string.h> |
|
64 | #include <string.h> |
|
65 | #include <stdarg.h> |
|
65 | #include <stdarg.h> |
|
66 | #include <stdint.h> |
|
66 | #include <stdint.h> |
|
67 | #include <unistd.h> |
|
67 | #include <unistd.h> |
|
68 | #include <getopt.h> |
|
68 | #include <getopt.h> |
|
69 | #include <time.h> |
|
69 | #include <time.h> |
|
70 | #include <sys/wait.h> |
|
70 | #include <sys/wait.h> |
|
71 | #include <sys/user.h> |
|
71 | #include <sys/user.h> |
|
72 | #include <sys/time.h> |
|
72 | #include <sys/time.h> |
|
73 | #include <sys/ptrace.h> |
|
73 | #include <sys/ptrace.h> |
|
74 | #include <sys/signal.h> |
|
74 | #include <sys/signal.h> |
|
75 | #include <sys/sysinfo.h> |
|
75 | #include <sys/sysinfo.h> |
|
76 | #include <sys/resource.h> |
|
76 | #include <sys/resource.h> |
|
77 | #include <sys/utsname.h> |
|
77 | #include <sys/utsname.h> |
|
78 | //#include <linux/ptrace.h> |
|
78 | //#include <linux/ptrace.h> |
|
79 |
|
79 | ||
|
80 | #if defined(CONFIG_BOX_KERNEL_AMD64) && !defined(CONFIG_BOX_USER_AMD64) |
|
80 | #if defined(CONFIG_BOX_KERNEL_AMD64) && !defined(CONFIG_BOX_USER_AMD64) |
|
81 | #include <asm/unistd_32.h> |
|
81 | #include <asm/unistd_32.h> |
|
82 | #define NATIVE_NR_execve 59 /* 64-bit execve */ |
|
82 | #define NATIVE_NR_execve 59 /* 64-bit execve */ |
|
83 | #else |
|
83 | #else |
|
84 | #include <asm/unistd.h> |
|
84 | #include <asm/unistd.h> |
|
85 | #define NATIVE_NR_execve __NR_execve |
|
85 | #define NATIVE_NR_execve __NR_execve |
|
86 | #endif |
|
86 | #endif |
|
87 |
|
87 | ||
|
88 | #define NONRET __attribute__((noreturn)) |
|
88 | #define NONRET __attribute__((noreturn)) |
|
89 | #define UNUSED __attribute__((unused)) |
|
89 | #define UNUSED __attribute__((unused)) |
|
90 | #define ARRAY_SIZE(a) (int)(sizeof(a)/sizeof(a[0])) |
|
90 | #define ARRAY_SIZE(a) (int)(sizeof(a)/sizeof(a[0])) |
|
91 |
|
91 | ||
|
92 | static int filter_syscalls; /* 0=off, 1=liberal, 2=totalitarian */ |
|
92 | static int filter_syscalls; /* 0=off, 1=liberal, 2=totalitarian */ |
|
93 | static int timeout; /* milliseconds */ |
|
93 | static int timeout; /* milliseconds */ |
|
94 | static int wall_timeout; |
|
94 | static int wall_timeout; |
|
95 | static int extra_timeout; |
|
95 | static int extra_timeout; |
|
96 | static int pass_environ; |
|
96 | static int pass_environ; |
|
97 | static int file_access; |
|
97 | static int file_access; |
|
98 | static int verbose; |
|
98 | static int verbose; |
|
99 | static int memory_limit; |
|
99 | static int memory_limit; |
|
100 | static int stack_limit; |
|
100 | static int stack_limit; |
|
101 | static char *redir_stdin, *redir_stdout, *redir_stderr; |
|
101 | static char *redir_stdin, *redir_stdout, *redir_stderr; |
|
102 | static char *set_cwd; |
|
102 | static char *set_cwd; |
|
103 |
|
103 | ||
|
104 | static pid_t box_pid; |
|
104 | static pid_t box_pid; |
|
105 | static int is_ptraced; |
|
105 | static int is_ptraced; |
|
106 | static volatile int timer_tick; |
|
106 | static volatile int timer_tick; |
|
107 | static struct timeval start_time; |
|
107 | static struct timeval start_time; |
|
108 | static int ticks_per_sec; |
|
108 | static int ticks_per_sec; |
|
109 | static int exec_seen; |
|
109 | static int exec_seen; |
|
110 | static int partial_line; |
|
110 | static int partial_line; |
|
111 |
|
111 | ||
|
112 | static int mem_peak_kb; |
|
112 | static int mem_peak_kb; |
|
113 | static int total_ms, wall_ms, sys_ms; |
|
113 | static int total_ms, wall_ms, sys_ms; |
|
114 |
|
114 | ||
|
115 | static void die(char *msg, ...) NONRET; |
|
115 | static void die(char *msg, ...) NONRET; |
|
116 | static void sample_mem_peak(void); |
|
116 | static void sample_mem_peak(void); |
|
117 |
|
117 | ||
|
118 | /*** Meta-files ***/ |
|
118 | /*** Meta-files ***/ |
|
119 |
|
119 | ||
|
120 | static FILE *metafile; |
|
120 | static FILE *metafile; |
|
121 |
|
121 | ||
|
122 | static void |
|
122 | static void |
|
123 | meta_open(const char *name) |
|
123 | meta_open(const char *name) |
|
124 | { |
|
124 | { |
|
125 | if (!strcmp(name, "-")) |
|
125 | if (!strcmp(name, "-")) |
|
126 | { |
|
126 | { |
|
127 | metafile = stdout; |
|
127 | metafile = stdout; |
|
128 | return; |
|
128 | return; |
|
129 | } |
|
129 | } |
|
130 | metafile = fopen(name, "w"); |
|
130 | metafile = fopen(name, "w"); |
|
131 | if (!metafile) |
|
131 | if (!metafile) |
|
132 | die("Failed to open metafile '%s'",name); |
|
132 | die("Failed to open metafile '%s'",name); |
|
133 | } |
|
133 | } |
|
134 |
|
134 | ||
|
135 | static void |
|
135 | static void |
|
136 | meta_close(void) |
|
136 | meta_close(void) |
|
137 | { |
|
137 | { |
|
138 | if (metafile && metafile != stdout) |
|
138 | if (metafile && metafile != stdout) |
|
139 | fclose(metafile); |
|
139 | fclose(metafile); |
|
140 | } |
|
140 | } |
|
141 |
|
141 | ||
|
142 | static void __attribute__((format(printf,1,2))) |
|
142 | static void __attribute__((format(printf,1,2))) |
|
143 | meta_printf(const char *fmt, ...) |
|
143 | meta_printf(const char *fmt, ...) |
|
144 | { |
|
144 | { |
|
145 | if (!metafile) |
|
145 | if (!metafile) |
|
146 | return; |
|
146 | return; |
|
147 |
|
147 | ||
|
148 | va_list args; |
|
148 | va_list args; |
|
149 | va_start(args, fmt); |
|
149 | va_start(args, fmt); |
|
150 | vfprintf(metafile, fmt, args); |
|
150 | vfprintf(metafile, fmt, args); |
|
151 | va_end(args); |
|
151 | va_end(args); |
|
152 | } |
|
152 | } |
|
153 |
|
153 | ||
|
154 |
|
154 | ||
|
155 | static void print_running_stat(double wall_time, |
|
155 | static void print_running_stat(double wall_time, |
|
156 | double user_time, |
|
156 | double user_time, |
|
157 | double system_time, |
|
157 | double system_time, |
|
158 | int mem_usage) |
|
158 | int mem_usage) |
|
159 | { |
|
159 | { |
|
160 | //total is user |
|
160 | //total is user |
|
161 | //wall is wall |
|
161 | //wall is wall |
|
162 | // |
|
162 | // |
|
163 |
- fprintf(stderr,"%.4lfr%.4lfu%.4lfs%d |
|
163 | + fprintf(stderr,"%.4lfr%.4lfu%.4lfs%dkbytes\n", |
|
164 | wall_time, user_time, system_time, mem_usage); |
|
164 | wall_time, user_time, system_time, mem_usage); |
|
165 | } |
|
165 | } |
|
166 |
|
166 | ||
|
167 | static void |
|
167 | static void |
|
168 | final_stats(struct rusage *rus) |
|
168 | final_stats(struct rusage *rus) |
|
169 | { |
|
169 | { |
|
170 | struct timeval total, now, wall; |
|
170 | struct timeval total, now, wall; |
|
171 | timeradd(&rus->ru_utime, &rus->ru_stime, &total); |
|
171 | timeradd(&rus->ru_utime, &rus->ru_stime, &total); |
|
172 | total_ms = total.tv_sec*1000 + total.tv_usec/1000; |
|
172 | total_ms = total.tv_sec*1000 + total.tv_usec/1000; |
|
173 | gettimeofday(&now, NULL); |
|
173 | gettimeofday(&now, NULL); |
|
174 | timersub(&now, &start_time, &wall); |
|
174 | timersub(&now, &start_time, &wall); |
|
175 | wall_ms = wall.tv_sec*1000 + wall.tv_usec/1000; |
|
175 | wall_ms = wall.tv_sec*1000 + wall.tv_usec/1000; |
|
176 | sys_ms = rus->ru_stime.tv_sec * 1000 + rus->ru_stime.tv_usec / 1000; |
|
176 | sys_ms = rus->ru_stime.tv_sec * 1000 + rus->ru_stime.tv_usec / 1000; |
|
177 |
|
177 | ||
|
178 | meta_printf("time:%d.%03d\n", total_ms/1000, total_ms%1000); |
|
178 | meta_printf("time:%d.%03d\n", total_ms/1000, total_ms%1000); |
|
179 | meta_printf("time-wall:%d.%03d\n", wall_ms/1000, wall_ms%1000); |
|
179 | meta_printf("time-wall:%d.%03d\n", wall_ms/1000, wall_ms%1000); |
|
180 | meta_printf("mem:%llu\n", (unsigned long long) mem_peak_kb * 1024); |
|
180 | meta_printf("mem:%llu\n", (unsigned long long) mem_peak_kb * 1024); |
|
181 | } |
|
181 | } |
|
182 |
|
182 | ||
|
183 | /*** Messages and exits ***/ |
|
183 | /*** Messages and exits ***/ |
|
184 |
|
184 | ||
|
185 | static void NONRET |
|
185 | static void NONRET |
|
186 | box_exit(int rc) |
|
186 | box_exit(int rc) |
|
187 | { |
|
187 | { |
|
188 | if (box_pid > 0) |
|
188 | if (box_pid > 0) |
|
189 | { |
|
189 | { |
|
190 | sample_mem_peak(); |
|
190 | sample_mem_peak(); |
|
191 | if (is_ptraced) |
|
191 | if (is_ptraced) |
|
192 | ptrace(PTRACE_KILL, box_pid); |
|
192 | ptrace(PTRACE_KILL, box_pid); |
|
193 | kill(-box_pid, SIGKILL); |
|
193 | kill(-box_pid, SIGKILL); |
|
194 | kill(box_pid, SIGKILL); |
|
194 | kill(box_pid, SIGKILL); |
|
195 | meta_printf("killed:1\n"); |
|
195 | meta_printf("killed:1\n"); |
|
196 |
|
196 | ||
|
197 | struct rusage rus; |
|
197 | struct rusage rus; |
|
198 | int p, stat; |
|
198 | int p, stat; |
|
199 | do |
|
199 | do |
|
200 | p = wait4(box_pid, &stat, 0, &rus); |
|
200 | p = wait4(box_pid, &stat, 0, &rus); |
|
201 | while (p < 0 && errno == EINTR); |
|
201 | while (p < 0 && errno == EINTR); |
|
202 | if (p < 0) |
|
202 | if (p < 0) |
|
203 | fprintf(stderr, "UGH: Lost track of the process (%m)\n"); |
|
203 | fprintf(stderr, "UGH: Lost track of the process (%m)\n"); |
|
204 | else { |
|
204 | else { |
|
205 | final_stats(&rus); |
|
205 | final_stats(&rus); |
|
206 | } |
|
206 | } |
|
207 | } |
|
207 | } |
|
208 | print_running_stat( |
|
208 | print_running_stat( |
|
209 | (double)wall_ms/1000, |
|
209 | (double)wall_ms/1000, |
|
210 | (double)total_ms/1000, |
|
210 | (double)total_ms/1000, |
|
211 | (double)sys_ms/1000, |
|
211 | (double)sys_ms/1000, |
|
212 |
- |
|
212 | + mem_peak_kb); |
|
213 | meta_close(); |
|
213 | meta_close(); |
|
214 | exit(rc); |
|
214 | exit(rc); |
|
215 | } |
|
215 | } |
|
216 |
|
216 | ||
|
217 | static void |
|
217 | static void |
|
218 | flush_line(void) |
|
218 | flush_line(void) |
|
219 | { |
|
219 | { |
|
220 | if (partial_line) |
|
220 | if (partial_line) |
|
221 | fputc('\n', stderr); |
|
221 | fputc('\n', stderr); |
|
222 | partial_line = 0; |
|
222 | partial_line = 0; |
|
223 | } |
|
223 | } |
|
224 |
|
224 | ||
|
225 | /* Report an error of the sandbox itself */ |
|
225 | /* Report an error of the sandbox itself */ |
|
226 | static void NONRET __attribute__((format(printf,1,2))) |
|
226 | static void NONRET __attribute__((format(printf,1,2))) |
|
227 | die(char *msg, ...) |
|
227 | die(char *msg, ...) |
|
228 | { |
|
228 | { |
|
229 | va_list args; |
|
229 | va_list args; |
|
230 | va_start(args, msg); |
|
230 | va_start(args, msg); |
|
231 | flush_line(); |
|
231 | flush_line(); |
|
232 | char buf[1024]; |
|
232 | char buf[1024]; |
|
233 | vsnprintf(buf, sizeof(buf), msg, args); |
|
233 | vsnprintf(buf, sizeof(buf), msg, args); |
|
234 | meta_printf("status:XX\nmessage:%s\n", buf); |
|
234 | meta_printf("status:XX\nmessage:%s\n", buf); |
|
235 | fputs(buf, stderr); |
|
235 | fputs(buf, stderr); |
|
236 | fputc('\n', stderr); |
|
236 | fputc('\n', stderr); |
|
237 | box_exit(2); |
|
237 | box_exit(2); |
|
238 | } |
|
238 | } |
|
239 |
|
239 | ||
|
240 | /* Report an error of the program inside the sandbox */ |
|
240 | /* Report an error of the program inside the sandbox */ |
|
241 | static void NONRET __attribute__((format(printf,1,2))) |
|
241 | static void NONRET __attribute__((format(printf,1,2))) |
|
242 | err(char *msg, ...) |
|
242 | err(char *msg, ...) |
|
243 | { |
|
243 | { |
|
244 | va_list args; |
|
244 | va_list args; |
|
245 | va_start(args, msg); |
|
245 | va_start(args, msg); |
|
246 | flush_line(); |
|
246 | flush_line(); |
|
247 | if (msg[0] && msg[1] && msg[2] == ':' && msg[3] == ' ') |
|
247 | if (msg[0] && msg[1] && msg[2] == ':' && msg[3] == ' ') |
|
248 | { |
|
248 | { |
|
249 | meta_printf("status:%c%c\n", msg[0], msg[1]); |
|
249 | meta_printf("status:%c%c\n", msg[0], msg[1]); |
|
250 | msg += 4; |
|
250 | msg += 4; |
|
251 | } |
|
251 | } |
|
252 | char buf[1024]; |
|
252 | char buf[1024]; |
|
253 | vsnprintf(buf, sizeof(buf), msg, args); |
|
253 | vsnprintf(buf, sizeof(buf), msg, args); |
|
254 | meta_printf("message:%s\n", buf); |
|
254 | meta_printf("message:%s\n", buf); |
|
255 | fputs(buf, stderr); |
|
255 | fputs(buf, stderr); |
|
256 | fputc('\n', stderr); |
|
256 | fputc('\n', stderr); |
|
257 | box_exit(1); |
|
257 | box_exit(1); |
|
258 | } |
|
258 | } |
|
259 |
|
259 | ||
|
260 | /* Write a message, but only if in verbose mode */ |
|
260 | /* Write a message, but only if in verbose mode */ |
|
261 | static void __attribute__((format(printf,1,2))) |
|
261 | static void __attribute__((format(printf,1,2))) |
|
262 | msg(char *msg, ...) |
|
262 | msg(char *msg, ...) |
|
263 | { |
|
263 | { |
|
264 | va_list args; |
|
264 | va_list args; |
|
265 | va_start(args, msg); |
|
265 | va_start(args, msg); |
|
266 | if (verbose) |
|
266 | if (verbose) |
|
267 | { |
|
267 | { |
|
268 | int len = strlen(msg); |
|
268 | int len = strlen(msg); |
|
269 | if (len > 0) |
|
269 | if (len > 0) |
|
270 | partial_line = (msg[len-1] != '\n'); |
|
270 | partial_line = (msg[len-1] != '\n'); |
|
271 | vfprintf(stderr, msg, args); |
|
271 | vfprintf(stderr, msg, args); |
|
272 | fflush(stderr); |
|
272 | fflush(stderr); |
|
273 | } |
|
273 | } |
|
274 | va_end(args); |
|
274 | va_end(args); |
|
275 | } |
|
275 | } |
|
276 |
|
276 | ||
|
277 | static void * |
|
277 | static void * |
|
278 | xmalloc(size_t size) |
|
278 | xmalloc(size_t size) |
|
279 | { |
|
279 | { |
|
280 | void *p = malloc(size); |
|
280 | void *p = malloc(size); |
|
281 | if (!p) |
|
281 | if (!p) |
|
282 | die("Out of memory"); |
|
282 | die("Out of memory"); |
|
283 | return p; |
|
283 | return p; |
|
284 | } |
|
284 | } |
|
285 |
|
285 | ||
|
286 | /*** Syscall rules ***/ |
|
286 | /*** Syscall rules ***/ |
|
287 |
|
287 | ||
|
288 | static const char * const syscall_names[] = { |
|
288 | static const char * const syscall_names[] = { |
|
289 |
|
289 | ||
|
290 | /* Syscall table automatically generated by mk-syscall-table */ |
|
290 | /* Syscall table automatically generated by mk-syscall-table */ |
|
291 |
|
291 | ||
|
292 | /* 0 */ [ __NR_read ] = "read", |
|
292 | /* 0 */ [ __NR_read ] = "read", |
|
293 | /* 1 */ [ __NR_write ] = "write", |
|
293 | /* 1 */ [ __NR_write ] = "write", |
|
294 | /* 2 */ [ __NR_open ] = "open", |
|
294 | /* 2 */ [ __NR_open ] = "open", |
|
295 | /* 3 */ [ __NR_close ] = "close", |
|
295 | /* 3 */ [ __NR_close ] = "close", |
|
296 | /* 4 */ [ __NR_stat ] = "stat", |
|
296 | /* 4 */ [ __NR_stat ] = "stat", |
|
297 | /* 5 */ [ __NR_fstat ] = "fstat", |
|
297 | /* 5 */ [ __NR_fstat ] = "fstat", |
|
298 | /* 6 */ [ __NR_lstat ] = "lstat", |
|
298 | /* 6 */ [ __NR_lstat ] = "lstat", |
|
299 | /* 7 */ [ __NR_poll ] = "poll", |
|
299 | /* 7 */ [ __NR_poll ] = "poll", |
|
300 | /* 8 */ [ __NR_lseek ] = "lseek", |
|
300 | /* 8 */ [ __NR_lseek ] = "lseek", |
|
301 | /* 9 */ [ __NR_mmap ] = "mmap", |
|
301 | /* 9 */ [ __NR_mmap ] = "mmap", |
|
302 | /* 10 */ [ __NR_mprotect ] = "mprotect", |
|
302 | /* 10 */ [ __NR_mprotect ] = "mprotect", |
|
303 | /* 11 */ [ __NR_munmap ] = "munmap", |
|
303 | /* 11 */ [ __NR_munmap ] = "munmap", |
|
304 | /* 12 */ [ __NR_brk ] = "brk", |
|
304 | /* 12 */ [ __NR_brk ] = "brk", |
|
305 | /* 13 */ [ __NR_rt_sigaction ] = "rt_sigaction", |
|
305 | /* 13 */ [ __NR_rt_sigaction ] = "rt_sigaction", |
|
306 | /* 14 */ [ __NR_rt_sigprocmask ] = "rt_sigprocmask", |
|
306 | /* 14 */ [ __NR_rt_sigprocmask ] = "rt_sigprocmask", |
|
307 | /* 15 */ [ __NR_rt_sigreturn ] = "rt_sigreturn", |
|
307 | /* 15 */ [ __NR_rt_sigreturn ] = "rt_sigreturn", |
|
308 | /* 16 */ [ __NR_ioctl ] = "ioctl", |
|
308 | /* 16 */ [ __NR_ioctl ] = "ioctl", |
|
309 | /* 17 */ [ __NR_pread64 ] = "pread64", |
|
309 | /* 17 */ [ __NR_pread64 ] = "pread64", |
|
310 | /* 18 */ [ __NR_pwrite64 ] = "pwrite64", |
|
310 | /* 18 */ [ __NR_pwrite64 ] = "pwrite64", |
|
311 | /* 19 */ [ __NR_readv ] = "readv", |
|
311 | /* 19 */ [ __NR_readv ] = "readv", |
|
312 | /* 20 */ [ __NR_writev ] = "writev", |
|
312 | /* 20 */ [ __NR_writev ] = "writev", |
|
313 | /* 21 */ [ __NR_access ] = "access", |
|
313 | /* 21 */ [ __NR_access ] = "access", |
|
314 | /* 22 */ [ __NR_pipe ] = "pipe", |
|
314 | /* 22 */ [ __NR_pipe ] = "pipe", |
|
315 | /* 23 */ [ __NR_select ] = "select", |
|
315 | /* 23 */ [ __NR_select ] = "select", |
|
316 | /* 24 */ [ __NR_sched_yield ] = "sched_yield", |
|
316 | /* 24 */ [ __NR_sched_yield ] = "sched_yield", |
|
317 | /* 25 */ [ __NR_mremap ] = "mremap", |
|
317 | /* 25 */ [ __NR_mremap ] = "mremap", |
|
318 | /* 26 */ [ __NR_msync ] = "msync", |
|
318 | /* 26 */ [ __NR_msync ] = "msync", |
|
319 | /* 27 */ [ __NR_mincore ] = "mincore", |
|
319 | /* 27 */ [ __NR_mincore ] = "mincore", |
|
320 | /* 28 */ [ __NR_madvise ] = "madvise", |
|
320 | /* 28 */ [ __NR_madvise ] = "madvise", |
|
321 | /* 29 */ [ __NR_shmget ] = "shmget", |
|
321 | /* 29 */ [ __NR_shmget ] = "shmget", |
|
322 | /* 30 */ [ __NR_shmat ] = "shmat", |
|
322 | /* 30 */ [ __NR_shmat ] = "shmat", |
|
323 | /* 31 */ [ __NR_shmctl ] = "shmctl", |
|
323 | /* 31 */ [ __NR_shmctl ] = "shmctl", |
|
324 | /* 32 */ [ __NR_dup ] = "dup", |
|
324 | /* 32 */ [ __NR_dup ] = "dup", |
|
325 | /* 33 */ [ __NR_dup2 ] = "dup2", |
|
325 | /* 33 */ [ __NR_dup2 ] = "dup2", |
|
326 | /* 34 */ [ __NR_pause ] = "pause", |
|
326 | /* 34 */ [ __NR_pause ] = "pause", |
|
327 | /* 35 */ [ __NR_nanosleep ] = "nanosleep", |
|
327 | /* 35 */ [ __NR_nanosleep ] = "nanosleep", |
|
328 | /* 36 */ [ __NR_getitimer ] = "getitimer", |
|
328 | /* 36 */ [ __NR_getitimer ] = "getitimer", |
|
329 | /* 37 */ [ __NR_alarm ] = "alarm", |
|
329 | /* 37 */ [ __NR_alarm ] = "alarm", |
|
330 | /* 38 */ [ __NR_setitimer ] = "setitimer", |
|
330 | /* 38 */ [ __NR_setitimer ] = "setitimer", |
|
331 | /* 39 */ [ __NR_getpid ] = "getpid", |
|
331 | /* 39 */ [ __NR_getpid ] = "getpid", |
|
332 | /* 40 */ [ __NR_sendfile ] = "sendfile", |
|
332 | /* 40 */ [ __NR_sendfile ] = "sendfile", |
|
333 | /* 41 */ [ __NR_socket ] = "socket", |
|
333 | /* 41 */ [ __NR_socket ] = "socket", |
|
334 | /* 42 */ [ __NR_connect ] = "connect", |
|
334 | /* 42 */ [ __NR_connect ] = "connect", |
|
335 | /* 43 */ [ __NR_accept ] = "accept", |
|
335 | /* 43 */ [ __NR_accept ] = "accept", |
|
336 | /* 44 */ [ __NR_sendto ] = "sendto", |
|
336 | /* 44 */ [ __NR_sendto ] = "sendto", |
|
337 | /* 45 */ [ __NR_recvfrom ] = "recvfrom", |
|
337 | /* 45 */ [ __NR_recvfrom ] = "recvfrom", |
|
338 | /* 46 */ [ __NR_sendmsg ] = "sendmsg", |
|
338 | /* 46 */ [ __NR_sendmsg ] = "sendmsg", |
|
339 | /* 47 */ [ __NR_recvmsg ] = "recvmsg", |
|
339 | /* 47 */ [ __NR_recvmsg ] = "recvmsg", |
|
340 | /* 48 */ [ __NR_shutdown ] = "shutdown", |
|
340 | /* 48 */ [ __NR_shutdown ] = "shutdown", |
|
341 | /* 49 */ [ __NR_bind ] = "bind", |
|
341 | /* 49 */ [ __NR_bind ] = "bind", |
|
342 | /* 50 */ [ __NR_listen ] = "listen", |
|
342 | /* 50 */ [ __NR_listen ] = "listen", |
|
343 | /* 51 */ [ __NR_getsockname ] = "getsockname", |
|
343 | /* 51 */ [ __NR_getsockname ] = "getsockname", |
|
344 | /* 52 */ [ __NR_getpeername ] = "getpeername", |
|
344 | /* 52 */ [ __NR_getpeername ] = "getpeername", |
|
345 | /* 53 */ [ __NR_socketpair ] = "socketpair", |
|
345 | /* 53 */ [ __NR_socketpair ] = "socketpair", |
|
346 | /* 54 */ [ __NR_setsockopt ] = "setsockopt", |
|
346 | /* 54 */ [ __NR_setsockopt ] = "setsockopt", |
|
347 | /* 55 */ [ __NR_getsockopt ] = "getsockopt", |
|
347 | /* 55 */ [ __NR_getsockopt ] = "getsockopt", |
|
348 | /* 56 */ [ __NR_clone ] = "clone", |
|
348 | /* 56 */ [ __NR_clone ] = "clone", |
|
349 | /* 57 */ [ __NR_fork ] = "fork", |
|
349 | /* 57 */ [ __NR_fork ] = "fork", |
|
350 | /* 58 */ [ __NR_vfork ] = "vfork", |
|
350 | /* 58 */ [ __NR_vfork ] = "vfork", |
|
351 | /* 59 */ [ __NR_execve ] = "execve", |
|
351 | /* 59 */ [ __NR_execve ] = "execve", |
|
352 | /* 60 */ [ __NR_exit ] = "exit", |
|
352 | /* 60 */ [ __NR_exit ] = "exit", |
|
353 | /* 61 */ [ __NR_wait4 ] = "wait4", |
|
353 | /* 61 */ [ __NR_wait4 ] = "wait4", |
|
354 | /* 62 */ [ __NR_kill ] = "kill", |
|
354 | /* 62 */ [ __NR_kill ] = "kill", |
|
355 | /* 63 */ [ __NR_uname ] = "uname", |
|
355 | /* 63 */ [ __NR_uname ] = "uname", |
|
356 | /* 64 */ [ __NR_semget ] = "semget", |
|
356 | /* 64 */ [ __NR_semget ] = "semget", |
|
357 | /* 65 */ [ __NR_semop ] = "semop", |
|
357 | /* 65 */ [ __NR_semop ] = "semop", |
|
358 | /* 66 */ [ __NR_semctl ] = "semctl", |
|
358 | /* 66 */ [ __NR_semctl ] = "semctl", |
|
359 | /* 67 */ [ __NR_shmdt ] = "shmdt", |
|
359 | /* 67 */ [ __NR_shmdt ] = "shmdt", |
|
360 | /* 68 */ [ __NR_msgget ] = "msgget", |
|
360 | /* 68 */ [ __NR_msgget ] = "msgget", |
|
361 | /* 69 */ [ __NR_msgsnd ] = "msgsnd", |
|
361 | /* 69 */ [ __NR_msgsnd ] = "msgsnd", |
|
362 | /* 70 */ [ __NR_msgrcv ] = "msgrcv", |
|
362 | /* 70 */ [ __NR_msgrcv ] = "msgrcv", |
|
363 | /* 71 */ [ __NR_msgctl ] = "msgctl", |
|
363 | /* 71 */ [ __NR_msgctl ] = "msgctl", |
|
364 | /* 72 */ [ __NR_fcntl ] = "fcntl", |
|
364 | /* 72 */ [ __NR_fcntl ] = "fcntl", |
|
365 | /* 73 */ [ __NR_flock ] = "flock", |
|
365 | /* 73 */ [ __NR_flock ] = "flock", |
|
366 | /* 74 */ [ __NR_fsync ] = "fsync", |
|
366 | /* 74 */ [ __NR_fsync ] = "fsync", |
|
367 | /* 75 */ [ __NR_fdatasync ] = "fdatasync", |
|
367 | /* 75 */ [ __NR_fdatasync ] = "fdatasync", |
|
368 | /* 76 */ [ __NR_truncate ] = "truncate", |
|
368 | /* 76 */ [ __NR_truncate ] = "truncate", |
|
369 | /* 77 */ [ __NR_ftruncate ] = "ftruncate", |
|
369 | /* 77 */ [ __NR_ftruncate ] = "ftruncate", |
|
370 | /* 78 */ [ __NR_getdents ] = "getdents", |
|
370 | /* 78 */ [ __NR_getdents ] = "getdents", |
|
371 | /* 79 */ [ __NR_getcwd ] = "getcwd", |
|
371 | /* 79 */ [ __NR_getcwd ] = "getcwd", |
|
372 | /* 80 */ [ __NR_chdir ] = "chdir", |
|
372 | /* 80 */ [ __NR_chdir ] = "chdir", |
|
373 | /* 81 */ [ __NR_fchdir ] = "fchdir", |
|
373 | /* 81 */ [ __NR_fchdir ] = "fchdir", |
|
374 | /* 82 */ [ __NR_rename ] = "rename", |
|
374 | /* 82 */ [ __NR_rename ] = "rename", |
|
375 | /* 83 */ [ __NR_mkdir ] = "mkdir", |
|
375 | /* 83 */ [ __NR_mkdir ] = "mkdir", |
|
376 | /* 84 */ [ __NR_rmdir ] = "rmdir", |
|
376 | /* 84 */ [ __NR_rmdir ] = "rmdir", |
|
377 | /* 85 */ [ __NR_creat ] = "creat", |
|
377 | /* 85 */ [ __NR_creat ] = "creat", |
|
378 | /* 86 */ [ __NR_link ] = "link", |
|
378 | /* 86 */ [ __NR_link ] = "link", |
|
379 | /* 87 */ [ __NR_unlink ] = "unlink", |
|
379 | /* 87 */ [ __NR_unlink ] = "unlink", |
|
380 | /* 88 */ [ __NR_symlink ] = "symlink", |
|
380 | /* 88 */ [ __NR_symlink ] = "symlink", |
|
381 | /* 89 */ [ __NR_readlink ] = "readlink", |
|
381 | /* 89 */ [ __NR_readlink ] = "readlink", |
|
382 | /* 90 */ [ __NR_chmod ] = "chmod", |
|
382 | /* 90 */ [ __NR_chmod ] = "chmod", |
|
383 | /* 91 */ [ __NR_fchmod ] = "fchmod", |
|
383 | /* 91 */ [ __NR_fchmod ] = "fchmod", |
|
384 | /* 92 */ [ __NR_chown ] = "chown", |
|
384 | /* 92 */ [ __NR_chown ] = "chown", |
|
385 | /* 93 */ [ __NR_fchown ] = "fchown", |
|
385 | /* 93 */ [ __NR_fchown ] = "fchown", |
|
386 | /* 94 */ [ __NR_lchown ] = "lchown", |
|
386 | /* 94 */ [ __NR_lchown ] = "lchown", |
|
387 | /* 95 */ [ __NR_umask ] = "umask", |
|
387 | /* 95 */ [ __NR_umask ] = "umask", |
|
388 | /* 96 */ [ __NR_gettimeofday ] = "gettimeofday", |
|
388 | /* 96 */ [ __NR_gettimeofday ] = "gettimeofday", |
|
389 | /* 97 */ [ __NR_getrlimit ] = "getrlimit", |
|
389 | /* 97 */ [ __NR_getrlimit ] = "getrlimit", |
|
390 | /* 98 */ [ __NR_getrusage ] = "getrusage", |
|
390 | /* 98 */ [ __NR_getrusage ] = "getrusage", |
|
391 | /* 99 */ [ __NR_sysinfo ] = "sysinfo", |
|
391 | /* 99 */ [ __NR_sysinfo ] = "sysinfo", |
|
392 | /* 100 */ [ __NR_times ] = "times", |
|
392 | /* 100 */ [ __NR_times ] = "times", |
|
393 | /* 101 */ [ __NR_ptrace ] = "ptrace", |
|
393 | /* 101 */ [ __NR_ptrace ] = "ptrace", |
|
394 | /* 102 */ [ __NR_getuid ] = "getuid", |
|
394 | /* 102 */ [ __NR_getuid ] = "getuid", |
|
395 | /* 103 */ [ __NR_syslog ] = "syslog", |
|
395 | /* 103 */ [ __NR_syslog ] = "syslog", |
|
396 | /* 104 */ [ __NR_getgid ] = "getgid", |
|
396 | /* 104 */ [ __NR_getgid ] = "getgid", |
|
397 | /* 105 */ [ __NR_setuid ] = "setuid", |
|
397 | /* 105 */ [ __NR_setuid ] = "setuid", |
|
398 | /* 106 */ [ __NR_setgid ] = "setgid", |
|
398 | /* 106 */ [ __NR_setgid ] = "setgid", |
|
399 | /* 107 */ [ __NR_geteuid ] = "geteuid", |
|
399 | /* 107 */ [ __NR_geteuid ] = "geteuid", |
|
400 | /* 108 */ [ __NR_getegid ] = "getegid", |
|
400 | /* 108 */ [ __NR_getegid ] = "getegid", |
|
401 | /* 109 */ [ __NR_setpgid ] = "setpgid", |
|
401 | /* 109 */ [ __NR_setpgid ] = "setpgid", |
|
402 | /* 110 */ [ __NR_getppid ] = "getppid", |
|
402 | /* 110 */ [ __NR_getppid ] = "getppid", |
|
403 | /* 111 */ [ __NR_getpgrp ] = "getpgrp", |
|
403 | /* 111 */ [ __NR_getpgrp ] = "getpgrp", |
|
404 | /* 112 */ [ __NR_setsid ] = "setsid", |
|
404 | /* 112 */ [ __NR_setsid ] = "setsid", |
@@ -1,133 +1,133 | |||||
|
1 | #!/usr/bin/env ruby |
|
1 | #!/usr/bin/env ruby |
|
2 |
|
2 | ||
|
3 | CORRECT_MARK = 'P' |
|
3 | CORRECT_MARK = 'P' |
|
4 | INCORRECT_MARK = '-' |
|
4 | INCORRECT_MARK = '-' |
|
5 | TIMEOUT_MARK = 'T' |
|
5 | TIMEOUT_MARK = 'T' |
|
6 | RUN_ERROR_MARK = 'x' |
|
6 | RUN_ERROR_MARK = 'x' |
|
7 |
|
7 | ||
|
8 | def log(str='') |
|
8 | def log(str='') |
|
9 | if ENV['TALKATIVE']!=nil |
|
9 | if ENV['TALKATIVE']!=nil |
|
10 | puts str |
|
10 | puts str |
|
11 | end |
|
11 | end |
|
12 | if ENV['GRADER_LOGGING']!=nil |
|
12 | if ENV['GRADER_LOGGING']!=nil |
|
13 | log_fname = ENV['GRADER_LOGGING'] |
|
13 | log_fname = ENV['GRADER_LOGGING'] |
|
14 | fp = File.open(log_fname,"a") |
|
14 | fp = File.open(log_fname,"a") |
|
15 | fp.puts("grade: #{Time.new.strftime("%H:%M")} #{str}") |
|
15 | fp.puts("grade: #{Time.new.strftime("%H:%M")} #{str}") |
|
16 | fp.close |
|
16 | fp.close |
|
17 | end |
|
17 | end |
|
18 | end |
|
18 | end |
|
19 |
|
19 | ||
|
20 | def char_comment(comment) |
|
20 | def char_comment(comment) |
|
21 | if comment =~ /[Ii]ncorrect/ |
|
21 | if comment =~ /[Ii]ncorrect/ |
|
22 | INCORRECT_MARK |
|
22 | INCORRECT_MARK |
|
23 | elsif comment =~ /[Cc]orrect/ |
|
23 | elsif comment =~ /[Cc]orrect/ |
|
24 | CORRECT_MARK |
|
24 | CORRECT_MARK |
|
25 | elsif comment =~ /[Tt]ime/ |
|
25 | elsif comment =~ /[Tt]ime/ |
|
26 | TIMEOUT_MARK |
|
26 | TIMEOUT_MARK |
|
27 | elsif res = /^[Cc]omment:(.*)$/.match(comment) |
|
27 | elsif res = /^[Cc]omment:(.*)$/.match(comment) |
|
28 | res[1] |
|
28 | res[1] |
|
29 | else |
|
29 | else |
|
30 | RUN_ERROR_MARK # these are run time errors |
|
30 | RUN_ERROR_MARK # these are run time errors |
|
31 | end |
|
31 | end |
|
32 | end |
|
32 | end |
|
33 |
|
33 | ||
|
34 | def extract_time(t) |
|
34 | def extract_time(t) |
|
35 | puts "TIME: #{t}" |
|
35 | puts "TIME: #{t}" |
|
36 |
- if (result=/^(.*)r(.*)u(.*)s(.*) |
|
36 | + if (result=/^(.*)r(.*)u(.*)s(.*)kbytes/.match(t)) |
|
37 | {:real => result[1], :user => result[2], :sys => result[3], :mem => result[4]} |
|
37 | {:real => result[1], :user => result[2], :sys => result[3], :mem => result[4]} |
|
38 | else |
|
38 | else |
|
39 | #{:real => 0, :user => 0, :sys => 0} |
|
39 | #{:real => 0, :user => 0, :sys => 0} |
|
40 | #puts "ERROR READING RUNNING TIME: #{t}" |
|
40 | #puts "ERROR READING RUNNING TIME: #{t}" |
|
41 | raise "Error reading running time: #{t}" |
|
41 | raise "Error reading running time: #{t}" |
|
42 | end |
|
42 | end |
|
43 | end |
|
43 | end |
|
44 |
|
44 | ||
|
45 | problem_home = ENV['PROBLEM_HOME'] |
|
45 | problem_home = ENV['PROBLEM_HOME'] |
|
46 | require "#{problem_home}/script/test_dsl.rb" |
|
46 | require "#{problem_home}/script/test_dsl.rb" |
|
47 | load "#{problem_home}/test_cases/all_tests.cfg" |
|
47 | load "#{problem_home}/test_cases/all_tests.cfg" |
|
48 | problem = Problem.get_instance |
|
48 | problem = Problem.get_instance |
|
49 |
|
49 | ||
|
50 | if problem.well_formed? == false |
|
50 | if problem.well_formed? == false |
|
51 | log "The problem specification is not well formed." |
|
51 | log "The problem specification is not well formed." |
|
52 | exit(127) |
|
52 | exit(127) |
|
53 | end |
|
53 | end |
|
54 |
|
54 | ||
|
55 | all_score = 0 |
|
55 | all_score = 0 |
|
56 | all_comment = '' |
|
56 | all_comment = '' |
|
57 | peak_memory = -1 |
|
57 | peak_memory = -1 |
|
58 | max_runtime = -1 |
|
58 | max_runtime = -1 |
|
59 | (1..(problem.runs.length-1)).each do |k| |
|
59 | (1..(problem.runs.length-1)).each do |k| |
|
60 | log "grade run #{k}" |
|
60 | log "grade run #{k}" |
|
61 | run = problem.runs[k] |
|
61 | run = problem.runs[k] |
|
62 | run_score = nil |
|
62 | run_score = nil |
|
63 | run_comment = '' |
|
63 | run_comment = '' |
|
64 | run_comment_short = '' |
|
64 | run_comment_short = '' |
|
65 | run.tests.each do |test_num| |
|
65 | run.tests.each do |test_num| |
|
66 | result_file_name = "#{test_num}/result" |
|
66 | result_file_name = "#{test_num}/result" |
|
67 | if not File.exists?(result_file_name) |
|
67 | if not File.exists?(result_file_name) |
|
68 | run_comment += "result file for test #{test_num} not found\n" |
|
68 | run_comment += "result file for test #{test_num} not found\n" |
|
69 | run_comment_short += RUN_ERROR_MARK |
|
69 | run_comment_short += RUN_ERROR_MARK |
|
70 | log "Cannot find the file #{test_num}/result!" |
|
70 | log "Cannot find the file #{test_num}/result!" |
|
71 | else |
|
71 | else |
|
72 | result_file = File.new(result_file_name, "r") |
|
72 | result_file = File.new(result_file_name, "r") |
|
73 | result_file_lines = result_file.readlines |
|
73 | result_file_lines = result_file.readlines |
|
74 | if result_file_lines.length>=3 |
|
74 | if result_file_lines.length>=3 |
|
75 | current_run_score = result_file_lines[1].to_i |
|
75 | current_run_score = result_file_lines[1].to_i |
|
76 | run_comment += result_file_lines[0] |
|
76 | run_comment += result_file_lines[0] |
|
77 | run_comment_short += char_comment(result_file_lines[0].chomp) |
|
77 | run_comment_short += char_comment(result_file_lines[0].chomp) |
|
78 |
|
78 | ||
|
79 | #update max runtime & memory |
|
79 | #update max runtime & memory |
|
80 | run_stat = extract_time result_file_lines[2] |
|
80 | run_stat = extract_time result_file_lines[2] |
|
81 | peak_memory = [peak_memory,run_stat[:mem].to_i].max |
|
81 | peak_memory = [peak_memory,run_stat[:mem].to_i].max |
|
82 | max_runtime = [max_runtime,run_stat[:user].to_f + run_stat[:sys].to_f].max |
|
82 | max_runtime = [max_runtime,run_stat[:user].to_f + run_stat[:sys].to_f].max |
|
83 | else |
|
83 | else |
|
84 | current_run_score = 0 |
|
84 | current_run_score = 0 |
|
85 | run_comment += "result file for test #{test_num} error\n" |
|
85 | run_comment += "result file for test #{test_num} error\n" |
|
86 | run_comment_short += RUN_ERROR_MARK |
|
86 | run_comment_short += RUN_ERROR_MARK |
|
87 | log "Error in #{test_num}/result!" |
|
87 | log "Error in #{test_num}/result!" |
|
88 | end |
|
88 | end |
|
89 |
|
89 | ||
|
90 | # the score of this run should be the minimum of the score for |
|
90 | # the score of this run should be the minimum of the score for |
|
91 | # each test case |
|
91 | # each test case |
|
92 | if (run_score==nil) or (run_score>current_run_score) |
|
92 | if (run_score==nil) or (run_score>current_run_score) |
|
93 | run_score = current_run_score |
|
93 | run_score = current_run_score |
|
94 | end |
|
94 | end |
|
95 | result_file.close |
|
95 | result_file.close |
|
96 | end |
|
96 | end |
|
97 | end |
|
97 | end |
|
98 |
|
98 | ||
|
99 | run_result_file = File.new("result-#{k}", "w") |
|
99 | run_result_file = File.new("result-#{k}", "w") |
|
100 | run_result_file.write run_score |
|
100 | run_result_file.write run_score |
|
101 | run_result_file.write "\n" |
|
101 | run_result_file.write "\n" |
|
102 | run_result_file.close |
|
102 | run_result_file.close |
|
103 |
|
103 | ||
|
104 | run_comment_file = File.new("comment-#{k}", "w") |
|
104 | run_comment_file = File.new("comment-#{k}", "w") |
|
105 | run_comment_file.write "#{run_comment}\n" |
|
105 | run_comment_file.write "#{run_comment}\n" |
|
106 | run_comment_file.close |
|
106 | run_comment_file.close |
|
107 |
|
107 | ||
|
108 | all_score = all_score + run_score |
|
108 | all_score = all_score + run_score |
|
109 |
|
109 | ||
|
110 | # append comment for test run with many test cases |
|
110 | # append comment for test run with many test cases |
|
111 | if run.tests.length > 1 |
|
111 | if run.tests.length > 1 |
|
112 | run_comment_short = '[' + run_comment_short + ']' |
|
112 | run_comment_short = '[' + run_comment_short + ']' |
|
113 | end |
|
113 | end |
|
114 | all_comment += run_comment_short |
|
114 | all_comment += run_comment_short |
|
115 | end |
|
115 | end |
|
116 |
|
116 | ||
|
117 | result_file = File.new("result", "w") |
|
117 | result_file = File.new("result", "w") |
|
118 | result_file.write all_score |
|
118 | result_file.write all_score |
|
119 | result_file.write "\n" |
|
119 | result_file.write "\n" |
|
120 | result_file.close |
|
120 | result_file.close |
|
121 |
|
121 | ||
|
122 | comment_file = File.new("comment", "w") |
|
122 | comment_file = File.new("comment", "w") |
|
123 | comment_file.write "#{all_comment}\n" |
|
123 | comment_file.write "#{all_comment}\n" |
|
124 | comment_file.close |
|
124 | comment_file.close |
|
125 |
|
125 | ||
|
126 |
|
126 | ||
|
127 | File.open("run_stat","w") do |file| |
|
127 | File.open("run_stat","w") do |file| |
|
128 | file.puts max_runtime |
|
128 | file.puts max_runtime |
|
129 | file.puts peak_memory |
|
129 | file.puts peak_memory |
|
130 | end |
|
130 | end |
|
131 |
|
131 | ||
|
132 | log "score = #{all_score}\ncomment = #{all_comment}" |
|
132 | log "score = #{all_score}\ncomment = #{all_comment}" |
|
133 | log "max_runtime = #{max_runtime}\npeak_memory = #{peak_memory}" |
|
133 | log "max_runtime = #{max_runtime}\npeak_memory = #{peak_memory}" |
You need to be logged in to leave comments.
Login now