Description:
big merge with dae
Commit status:
[Not Reviewed]
References:
merge default
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r189:45a8ea0792f3 - - 12 files changed: 257 inserted, 21 deleted

@@ -0,0 +1,66
1 + #!/usr/bin/env ruby
2 +
3 + problem_home = ENV['PROBLEM_HOME']
4 + require "#{problem_home}/script/test_dsl.rb"
5 +
6 + if ARGV.length < 2
7 + puts "Usage: check <language> <test-number> [<output-file>]"
8 + exit(0)
9 + end
10 +
11 + language = ARGV[0]
12 + test_num = ARGV[1].to_i
13 + if ARGV.length >= 3
14 + output_file_name = ARGV[2]
15 + else
16 + output_file_name = "output.txt"
17 + end
18 +
19 + load "#{problem_home}/test_cases/all_tests.cfg"
20 + problem = Problem.get_instance
21 +
22 + output_file = File.new(output_file_name, "r")
23 + answer_file = File.new("#{problem_home}/test_cases/#{test_num}/answer-#{test_num}.txt")
24 + result_file = File.new("check_result", "w")
25 +
26 + output_file_content = output_file.read
27 + answer_file_content = answer_file.read
28 +
29 + report_correct = lambda {
30 + result_file.write "Correct\n"
31 + result_file.write problem.get_score(test_num)
32 + result_file.write "\n"
33 + result_file.close
34 + exit(0)
35 + }
36 +
37 + report_wrong = lambda {
38 + result_file.write "Incorrect\n"
39 + result_file.write "0\n"
40 + result_file.close
41 + exit(0)
42 + }
43 +
44 + ##################
45 + # Your code here #
46 + ##################
47 +
48 + ########### THIS IS FOR CHECKING FLOAT with EPSILON error ##########
49 +
50 + EPSILON = 0.000001
51 +
52 + out_items = output_file_content.split
53 + ans_items = answer_file_content.split
54 +
55 + if out_items.length != ans_items.length
56 + report_wrong.call
57 + else
58 + out_items.length.times do |i|
59 + out_value = out_items[i].to_f
60 + ans_value = ans_items[i].to_f
61 + if (out_value - ans_value).abs > EPSILON * [out_value.abs,ans_value.abs].max
62 + report_wrong.call
63 + end
64 + end
65 + report_correct.call
66 + end
@@ -48,29 +48,32
48 using: (1) grader
48 using: (1) grader
49 (2) grader environment [mode] [options]
49 (2) grader environment [mode] [options]
50 (3) grader stop [all|pids-list]
50 (3) grader stop [all|pids-list]
51 (4) grader --help
51 (4) grader --help
52 (1) call grader with environment = 'exam', mode = 'queue'
52 (1) call grader with environment = 'exam', mode = 'queue'
53 (2) possible modes are: 'queue', 'test_request', 'prob', 'sub', 'contest', and 'autonew'
53 (2) possible modes are: 'queue', 'test_request', 'prob', 'sub', 'contest', and 'autonew'
54 queue: repeatedly check the task queue and grade any available tasks
54 queue: repeatedly check the task queue and grade any available tasks
55
55
56 prob: re-grade every user latest submission of the specific problem.
56 prob: re-grade every user latest submission of the specific problem.
57 the problem name must be specified by the next argument.
57 the problem name must be specified by the next argument.
58
58
59 additional options:
59 additional options:
60 + --all-sub re-grade every submissions instead of just the latest submission of each user.
60
61
61 - --all-sub re-grade every submissions instead of just the latest submission of each user.
62 sub: re-grader the specified submission.
62 sub: re-grader the specified submission.
63 The submission ID to be re-graded must be specified by the next argument.
63 The submission ID to be re-graded must be specified by the next argument.
64
64
65 + options:
66 + --err-log log error to a file in the log dir
67 +
65 (3) create stop-file to stop running grader in queue mode
68 (3) create stop-file to stop running grader in queue mode
66 (4) You are here.
69 (4) You are here.
67 USAGE
70 USAGE
68 end
71 end
69
72
70 def process_options_and_stop_file
73 def process_options_and_stop_file
71 # The list of options are:
74 # The list of options are:
72 # - stop [all|process ids]
75 # - stop [all|process ids]
73 # -
76 # -
74
77
75 # Process 'help' option
78 # Process 'help' option
76 if (ARGV.length==1) and (/help/.match(ARGV[0]))
79 if (ARGV.length==1) and (/help/.match(ARGV[0]))
@@ -125,24 +128,26
125 puts "Dry run currently works only for 'prob' or 'contest' modes."
128 puts "Dry run currently works only for 'prob' or 'contest' modes."
126 exit(0)
129 exit(0)
127 end
130 end
128
131
129 options[:report] = (ARGV.delete('--report') != nil)
132 options[:report] = (ARGV.delete('--report') != nil)
130 if options[:report] and (not ['prob','contest','autonew'].include? options[:mode])
133 if options[:report] and (not ['prob','contest','autonew'].include? options[:mode])
131 puts "Report currently works only for 'prob' or 'contest' modes."
134 puts "Report currently works only for 'prob' or 'contest' modes."
132 exit(0)
135 exit(0)
133 end
136 end
134
137
135 options[:all_sub] = (ARGV.delete('--all-sub') != nil)
138 options[:all_sub] = (ARGV.delete('--all-sub') != nil)
136
139
140 + options[:err_log] = (ARGV.delete('--err-log') != nil)
141 +
137 return options
142 return options
138 end
143 end
139
144
140 class ResultCollector
145 class ResultCollector
141 def initialize
146 def initialize
142 @results = {}
147 @results = {}
143 @problems = {}
148 @problems = {}
144 @users = {}
149 @users = {}
145 end
150 end
146
151
147 def after_save_hook(submission, grading_result)
152 def after_save_hook(submission, grading_result)
148 end
153 end
@@ -411,24 +416,31
411
416
412 # register grader process
417 # register grader process
413 if config.report_grader
418 if config.report_grader
414 grader_proc = GraderProcess.register(config.grader_hostname,
419 grader_proc = GraderProcess.register(config.grader_hostname,
415 Process.pid,
420 Process.pid,
416 grader_mode)
421 grader_mode)
417 else
422 else
418 grader_proc = nil
423 grader_proc = nil
419 end
424 end
420
425
421 #set loggin environment
426 #set loggin environment
422 ENV['GRADER_LOGGING'] = log_file_name
427 ENV['GRADER_LOGGING'] = log_file_name
428 + if options[:err_log]
429 + err_file_name = log_file_name + '.err'
430 + $stderr.reopen(err_file_name,"a")
431 + log "STDERR log to file [#{err_file_name}]"
432 + warn "start logging for grader PID #{Process.pid} on #{Time.now.in_time_zone}"
433 + end
434 +
423
435
424 # register exit handler to report inactive, and terminated
436 # register exit handler to report inactive, and terminated
425 at_exit do
437 at_exit do
426 if grader_proc!=nil
438 if grader_proc!=nil
427 grader_proc.report_inactive
439 grader_proc.report_inactive
428 grader_proc.terminate
440 grader_proc.terminate
429 end
441 end
430 end
442 end
431
443
432 #
444 #
433 # MAIN LOOP
445 # MAIN LOOP
434 #
446 #
@@ -109,26 +109,28
109 def talk(str)
109 def talk(str)
110 if @config.talkative
110 if @config.talkative
111 puts str
111 puts str
112 end
112 end
113 end
113 end
114
114
115 def call_judge(problem_home,language,grading_dir,fname)
115 def call_judge(problem_home,language,grading_dir,fname)
116 ENV['PROBLEM_HOME'] = problem_home
116 ENV['PROBLEM_HOME'] = problem_home
117 ENV['RUBYOPT'] = ''
117 ENV['RUBYOPT'] = ''
118
118
119 talk grading_dir
119 talk grading_dir
120 Dir.chdir grading_dir
120 Dir.chdir grading_dir
121 - cmd = "#{problem_home}/script/judge #{language} #{fname}"
121 + script_name = "#{problem_home}/script/judge"
122 + cmd = "#{script_name} #{language} #{fname}"
122 talk "CMD: #{cmd}"
123 talk "CMD: #{cmd}"
124 + warn "ERROR: file does not exists #{script_name}" unless File.exists? script_name
123 system(cmd)
125 system(cmd)
124 end
126 end
125
127
126 def get_std_script_dir
128 def get_std_script_dir
127 GRADER_ROOT + '/std-script'
129 GRADER_ROOT + '/std-script'
128 end
130 end
129
131
130 def copy_script(problem_home)
132 def copy_script(problem_home)
131 script_dir = "#{problem_home}/script"
133 script_dir = "#{problem_home}/script"
132 std_script_dir = get_std_script_dir
134 std_script_dir = get_std_script_dir
133
135
134 raise "engine: std-script directory not found" if !FileTest.exist?(std_script_dir)
136 raise "engine: std-script directory not found" if !FileTest.exist?(std_script_dir)
@@ -36,25 +36,25
36 @engine.grade(sub)
36 @engine.grade(sub)
37 end
37 end
38 else
38 else
39 last_sub = Submission.find_last_by_user_and_problem(u.id,problem.id)
39 last_sub = Submission.find_last_by_user_and_problem(u.id,problem.id)
40 if last_sub!=nil
40 if last_sub!=nil
41 @engine.grade(last_sub)
41 @engine.grade(last_sub)
42 end
42 end
43 end
43 end
44 end
44 end
45 end
45 end
46
46
47 def grade_submission(submission)
47 def grade_submission(submission)
48 - puts "Submission: #{submission.id} by #{submission.user.full_name}"
48 + puts "Submission: #{submission.id} by #{submission.try(:user).try(:full_name)}"
49 @engine.grade(submission)
49 @engine.grade(submission)
50 end
50 end
51
51
52 def grade_oldest_test_request
52 def grade_oldest_test_request
53 test_request = TestRequest.get_inqueue_and_change_status(Task::STATUS_GRADING)
53 test_request = TestRequest.get_inqueue_and_change_status(Task::STATUS_GRADING)
54 if test_request!=nil
54 if test_request!=nil
55 @grader_process.report_active(test_request) if @grader_process!=nil
55 @grader_process.report_active(test_request) if @grader_process!=nil
56
56
57 @engine.grade(test_request)
57 @engine.grade(test_request)
58 test_request.status_complete!
58 test_request.status_complete!
59 @grader_process.report_inactive(test_request) if @grader_process!=nil
59 @grader_process.report_inactive(test_request) if @grader_process!=nil
60 end
60 end
@@ -57,66 +57,84
57 def read_result(test_result_dir)
57 def read_result(test_result_dir)
58 cmp_msg_fname = "#{test_result_dir}/compiler_message"
58 cmp_msg_fname = "#{test_result_dir}/compiler_message"
59 if FileTest.exist?(cmp_msg_fname)
59 if FileTest.exist?(cmp_msg_fname)
60 cmp_file = File.open(cmp_msg_fname)
60 cmp_file = File.open(cmp_msg_fname)
61 cmp_msg = cmp_file.read
61 cmp_msg = cmp_file.read
62 cmp_file.close
62 cmp_file.close
63 else
63 else
64 cmp_msg = ""
64 cmp_msg = ""
65 end
65 end
66
66
67 result_fname = "#{test_result_dir}/result"
67 result_fname = "#{test_result_dir}/result"
68 comment_fname = "#{test_result_dir}/comment"
68 comment_fname = "#{test_result_dir}/comment"
69 + runstat_fname = "#{test_result_dir}/run_stat"
69 if FileTest.exist?(result_fname)
70 if FileTest.exist?(result_fname)
70 comment = ""
71 comment = ""
71 begin
72 begin
72 result_file = File.open(result_fname)
73 result_file = File.open(result_fname)
73 result = result_file.readline.to_i
74 result = result_file.readline.to_i
74 result_file.close
75 result_file.close
75 rescue
76 rescue
76 result = 0
77 result = 0
77 comment = "error reading result file."
78 comment = "error reading result file."
78 end
79 end
79
80
80 begin
81 begin
81 comment_file = File.open(comment_fname)
82 comment_file = File.open(comment_fname)
82 comment += comment_file.readline.chomp
83 comment += comment_file.readline.chomp
83 comment_file.close
84 comment_file.close
84 rescue
85 rescue
85 comment += ""
86 comment += ""
86 end
87 end
87
88
88 - return {:points => result,
89 + begin
89 - :comment => comment,
90 + runstat_file = File.open(runstat_fname)
90 - :cmp_msg => cmp_msg}
91 + max_runtime = runstat_file.readline.to_f
92 + peak_memory = runstat_file.readline.to_i
93 + rescue
94 + max_runtime = -1
95 + peak_memory = -1
96 + end
97 +
98 +
99 + return {points: result,
100 + comment: comment,
101 + cmp_msg: cmp_msg,
102 + max_runtime: max_runtime,
103 + peak_memory: peak_memory
104 + }
91 else
105 else
92 if FileTest.exist?("#{test_result_dir}/a.out")
106 if FileTest.exist?("#{test_result_dir}/a.out")
93 return {:points => 0,
107 return {:points => 0,
94 :comment => 'error during grading',
108 :comment => 'error during grading',
95 :cmp_msg => cmp_msg}
109 :cmp_msg => cmp_msg}
96 else
110 else
97 return {:points => 0,
111 return {:points => 0,
98 :comment => 'compilation error',
112 :comment => 'compilation error',
99 :cmp_msg => cmp_msg}
113 :cmp_msg => cmp_msg}
100 end
114 end
101 end
115 end
102 end
116 end
103
117
104 def save_result(submission,result)
118 def save_result(submission,result)
105 problem = submission.problem
119 problem = submission.problem
106 submission.graded_at = Time.now.gmtime
120 submission.graded_at = Time.now.gmtime
107 points = result[:points]
121 points = result[:points]
108 submission.points = points
122 submission.points = points
109 comment = @config.report_comment(result[:comment])
123 comment = @config.report_comment(result[:comment])
110
124
125 + submission.peak_memory = result[:peak_memory]
126 + submission.max_runtime = result[:max_runtime]
127 + submission.effective_code_length =submission.source.length
128 +
111 #
129 #
112 # TODO: FIX THIS MESSAGE
130 # TODO: FIX THIS MESSAGE
113 #
131 #
114 if problem == nil
132 if problem == nil
115 submission.grader_comment = 'PASSED: ' + comment + '(problem is nil)'
133 submission.grader_comment = 'PASSED: ' + comment + '(problem is nil)'
116 elsif points == problem.full_score
134 elsif points == problem.full_score
117 #submission.grader_comment = 'PASSED: ' + comment
135 #submission.grader_comment = 'PASSED: ' + comment
118 submission.grader_comment = comment
136 submission.grader_comment = comment
119 elsif result[:comment].chomp =~ /^[\[\]P]+$/
137 elsif result[:comment].chomp =~ /^[\[\]P]+$/
120 submission.grader_comment = 'PASSED: ' + comment + '(inconsistent score)'
138 submission.grader_comment = 'PASSED: ' + comment + '(inconsistent score)'
121 else
139 else
122 #submission.grader_comment = 'FAILED: ' + comment
140 #submission.grader_comment = 'FAILED: ' + comment
@@ -189,25 +189,25
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(.*)m/.match(running_stat_line)
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
@@ -17,28 +17,36
17 end
17 end
18 if ENV['GRADER_LOGGING']!=nil
18 if ENV['GRADER_LOGGING']!=nil
19 log_fname = ENV['GRADER_LOGGING']
19 log_fname = ENV['GRADER_LOGGING']
20 fp = File.open(log_fname,"a")
20 fp = File.open(log_fname,"a")
21 fp.puts("run: #{Time.new.strftime("%H:%M")} #{str}")
21 fp.puts("run: #{Time.new.strftime("%H:%M")} #{str}")
22 fp.close
22 fp.close
23 end
23 end
24 end
24 end
25
25
26 C_COMPILER = "/usr/bin/gcc"
26 C_COMPILER = "/usr/bin/gcc"
27 CPLUSPLUS_COMPILER = "/usr/bin/g++"
27 CPLUSPLUS_COMPILER = "/usr/bin/g++"
28 PASCAL_COMPILER = "/usr/bin/fpc"
28 PASCAL_COMPILER = "/usr/bin/fpc"
29 + JAVA_COMPILER = "/usr/bin/javac"
30 + RUBY_INTERPRETER = "/usr/bin/ruby"
31 + PYTHON_INTERPRETER = "/usr/bin/python"
32 + PYTHON_CHECKER = "/usr/bin/pyflakes"
33 + PHP_INTERPRETER = "/usr/bin/php"
29
34
30 C_OPTIONS = "-O2 -s -static -std=c99 -DCONTEST -lm -Wall"
35 C_OPTIONS = "-O2 -s -static -std=c99 -DCONTEST -lm -Wall"
31 - CPLUSPLUS_OPTIONS = "-O2 -s -static -DCONTEST -lm -Wall"
36 + CPLUSPLUS_OPTIONS = "-O2 -s -std=c++11 -static -DCONTEST -lm -Wall"
32 PASCAL_OPTIONS = "-O1 -XS -dCONTEST"
37 PASCAL_OPTIONS = "-O1 -XS -dCONTEST"
38 + JAVA_OPTIONS = ""
39 + PYTHON_OPTIONS = ""
40 + PHP_OPTIONS = "-l"
33
41
34 # Check for the correct number of arguments. Otherwise, print usage.
42 # Check for the correct number of arguments. Otherwise, print usage.
35 if ARGV.length == 0 or ARGV.length > 4
43 if ARGV.length == 0 or ARGV.length > 4
36 puts "Usage: compile <language> [<source-file>] [<output-file>] [<message-file>]"
44 puts "Usage: compile <language> [<source-file>] [<output-file>] [<message-file>]"
37 puts
45 puts
38 puts "<source-file> is defaulted to \"source\"."
46 puts "<source-file> is defaulted to \"source\"."
39 puts "<output-file> is defaulted to \"a.out\"."
47 puts "<output-file> is defaulted to \"a.out\"."
40 puts "<message-file> is defaulted to \"compiler_message\"."
48 puts "<message-file> is defaulted to \"compiler_message\"."
41 puts
49 puts
42 exit(127)
50 exit(127)
43 end
51 end
44
52
@@ -76,35 +84,102
76 end
84 end
77 exit(127)
85 exit(127)
78 end
86 end
79
87
80 if params[:prog_lang]=='cpp'
88 if params[:prog_lang]=='cpp'
81 params[:prog_lang] = 'c++'
89 params[:prog_lang] = 'c++'
82 end
90 end
83
91
84 # Compile.
92 # Compile.
85 case params[:prog_lang]
93 case params[:prog_lang]
86
94
87 when "c"
95 when "c"
88 - command = "#{C_COMPILER} #{params[:source_file]} -o #{params[:output_file]} #{C_OPTIONS} 2> #{params[:message_file]}"
96 + command = "#{C_COMPILER} #{params[:source_file]} -o #{params[:output_file]} #{C_OPTIONS}"
89 - system(command)
97 + system(command, err: params[:message_file])
90
98
91 when "c++"
99 when "c++"
92 - command = "#{CPLUSPLUS_COMPILER} #{params[:source_file]} -o #{params[:output_file]} #{CPLUSPLUS_OPTIONS} 2> #{params[:message_file]}"
100 + command = "#{CPLUSPLUS_COMPILER} #{params[:source_file]} -o #{params[:output_file]} #{CPLUSPLUS_OPTIONS}"
93 - system(command)
101 + system(command, err: params[:message_file])
94
102
95 when "pas"
103 when "pas"
96 - command = "#{PASCAL_COMPILER} #{params[:source_file]} -ooutpas #{PASCAL_OPTIONS} > #{params[:message_file]}"
104 + command = "#{PASCAL_COMPILER} #{params[:source_file]} -ooutpas #{PASCAL_OPTIONS}"
105 + system(command,out: params[:message_file])
106 + FileUtils.mv("output", params[:output_file])
107 +
108 + when "java"
109 + #rename the file to the public class name
110 +
111 + #get the class name
112 + classname = 'DUMMY'
113 + source = Array.new
114 + File.foreach(params[:source_file],'r:UTF-8') do |line|
115 + line.encode!('UTF-8','UTF-8',invalid: :replace, replace: '')
116 + md = /\s*public\s*class\s*(\w*)/.match(line)
117 + classname=md[1] if md
118 + source << line unless line =~ /\s*package\s*\w+\s*\;/
119 + end
120 + File.open("#{classname}.java","w") do |file|
121 + source.each do |s|
122 + file.puts s
123 + end
124 + end
125 + #system("cp #{params[:source_file]} #{classname}.java")
126 + command = "#{JAVA_COMPILER} -encoding utf8 #{classname}.java"
127 + system(command, err: params[:message_file])
128 + if File.exists?(classname + ".class")
129 + File.open(params[:output_file],"w") {|file| file.write("#{classname}")}
130 + end
131 + if classname == 'DUMMY'
132 + File.open(params[:message_file],"w") {|file| file.write("Cannot find any public class in the source code\n")}
133 + end
134 +
135 + when "ruby"
136 + command = "#{RUBY_INTERPRETER} -c #{params[:source_file]}"
137 + if system(command, err: params[:message_file])
138 + File.open(params[:output_file],"w") do |out_file|
139 + out_file.puts "#!#{RUBY_INTERPRETER}"
140 + File.open(params[:source_file],"r").each do |line|
141 + out_file.print line
142 + end
143 + end
144 + File.chmod(0755, params[:output_file])
145 + end
146 +
147 + when "python"
148 + command = "#{PYTHON_CHECKER} #{params[:source_file]}"
149 + if system(command, out: params[:message_file])
150 + #compile to python bytecode
151 + command = "#{PYTHON_INTERPRETER} -m py_compile #{params[:source_file]}"
152 + puts "compile: #{command}"
97 system(command)
153 system(command)
98 - FileUtils.mv("output", params[:output_file])
154 + puts "pwd: " + Dir.pwd
155 + Dir.new('.').each {|file| puts file}
156 + File.open(params[:output_file],"w") do |out_file|
157 + out_file.puts "#!#{PYTHON_INTERPRETER} #{params[:source_file]}c"
158 + end
159 + File.chmod(0755, params[:output_file])
160 + FileUtils.cp("#{params[:source_file]}c",params[:output_file])
161 + end
162 +
163 + when "php"
164 + command = "#{PHP_INTERPRETER} #{PHP_OPTIONS} #{params[:source_file]}"
165 + if system(command, err: params[:message_file])
166 + File.open(params[:output_file],"w") do |out_file|
167 + out_file.puts "#!#{PHP_INTERPRETER}"
168 + File.open(params[:source_file],"r").each do |line|
169 + out_file.print line
170 + end
171 + end
172 + File.chmod(0755, params[:output_file])
173 + end
99
174
100 else
175 else
101 talk("ERROR: Invalid language specified!")
176 talk("ERROR: Invalid language specified!")
102 open(params[:message_file],"w") do |f|
177 open(params[:message_file],"w") do |f|
103 f.puts "ERROR: Invalid language specified!"
178 f.puts "ERROR: Invalid language specified!"
104 end
179 end
105 exit(127)
180 exit(127)
106 end
181 end
107
182
108 # Report success or failure.
183 # Report success or failure.
109 if FileTest.exists? params[:output_file]
184 if FileTest.exists? params[:output_file]
110 talk "Compilation was successful!"
185 talk "Compilation was successful!"
@@ -22,55 +22,73
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)
35 + #puts "TIME: #{t}"
36 + if (result=/^(.*)r(.*)u(.*)s(.*)kbytes/.match(t))
37 + {:real => result[1], :user => result[2], :sys => result[3], :mem => result[4]}
38 + else
39 + #{:real => 0, :user => 0, :sys => 0}
40 + #puts "ERROR READING RUNNING TIME: #{t}"
41 + raise "Error reading running time: #{t}"
42 + end
43 + end
44 +
34 problem_home = ENV['PROBLEM_HOME']
45 problem_home = ENV['PROBLEM_HOME']
35 require "#{problem_home}/script/test_dsl.rb"
46 require "#{problem_home}/script/test_dsl.rb"
36 load "#{problem_home}/test_cases/all_tests.cfg"
47 load "#{problem_home}/test_cases/all_tests.cfg"
37 problem = Problem.get_instance
48 problem = Problem.get_instance
38
49
39 if problem.well_formed? == false
50 if problem.well_formed? == false
40 log "The problem specification is not well formed."
51 log "The problem specification is not well formed."
41 exit(127)
52 exit(127)
42 end
53 end
43
54
44 all_score = 0
55 all_score = 0
45 all_comment = ''
56 all_comment = ''
57 + peak_memory = -1
58 + max_runtime = -1
46 (1..(problem.runs.length-1)).each do |k|
59 (1..(problem.runs.length-1)).each do |k|
47 log "grade run #{k}"
60 log "grade run #{k}"
48 run = problem.runs[k]
61 run = problem.runs[k]
49 run_score = nil
62 run_score = nil
50 run_comment = ''
63 run_comment = ''
51 run_comment_short = ''
64 run_comment_short = ''
52 run.tests.each do |test_num|
65 run.tests.each do |test_num|
53 result_file_name = "#{test_num}/result"
66 result_file_name = "#{test_num}/result"
54 if not File.exists?(result_file_name)
67 if not File.exists?(result_file_name)
55 run_comment += "result file for test #{test_num} not found\n"
68 run_comment += "result file for test #{test_num} not found\n"
56 run_comment_short += RUN_ERROR_MARK
69 run_comment_short += RUN_ERROR_MARK
57 log "Cannot find the file #{test_num}/result!"
70 log "Cannot find the file #{test_num}/result!"
58 else
71 else
59 result_file = File.new(result_file_name, "r")
72 result_file = File.new(result_file_name, "r")
60 result_file_lines = result_file.readlines
73 result_file_lines = result_file.readlines
61 - if result_file_lines.length>=2
74 + if result_file_lines.length>=3
62 current_run_score = result_file_lines[1].to_i
75 current_run_score = result_file_lines[1].to_i
63 run_comment += result_file_lines[0]
76 run_comment += result_file_lines[0]
64 run_comment_short += char_comment(result_file_lines[0].chomp)
77 run_comment_short += char_comment(result_file_lines[0].chomp)
78 +
79 + #update max runtime & memory
80 + run_stat = extract_time result_file_lines[2]
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
65 else
83 else
66 current_run_score = 0
84 current_run_score = 0
67 run_comment += "result file for test #{test_num} error\n"
85 run_comment += "result file for test #{test_num} error\n"
68 run_comment_short += RUN_ERROR_MARK
86 run_comment_short += RUN_ERROR_MARK
69 log "Error in #{test_num}/result!"
87 log "Error in #{test_num}/result!"
70 end
88 end
71
89
72 # 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
73 # each test case
91 # each test case
74 if (run_score==nil) or (run_score>current_run_score)
92 if (run_score==nil) or (run_score>current_run_score)
75 run_score = current_run_score
93 run_score = current_run_score
76 end
94 end
@@ -95,12 +113,22
95 end
113 end
96 all_comment += run_comment_short
114 all_comment += run_comment_short
97 end
115 end
98
116
99 result_file = File.new("result", "w")
117 result_file = File.new("result", "w")
100 result_file.write all_score
118 result_file.write all_score
101 result_file.write "\n"
119 result_file.write "\n"
102 result_file.close
120 result_file.close
103
121
104 comment_file = File.new("comment", "w")
122 comment_file = File.new("comment", "w")
105 comment_file.write "#{all_comment}\n"
123 comment_file.write "#{all_comment}\n"
106 comment_file.close
124 comment_file.close
125 +
126 +
127 + File.open("run_stat","w") do |file|
128 + file.puts max_runtime
129 + file.puts peak_memory
130 + end
131 +
132 + puts "#{all_score} #{all_comment}"
133 + log "score = #{all_score}\ncomment = #{all_comment}"
134 + log "max_runtime = #{max_runtime}\npeak_memory = #{peak_memory}"
@@ -44,30 +44,31
44 # ARGV[2] --- test result directory
44 # ARGV[2] --- test result directory
45 # ARGV[3] --- sandbox directory
45 # ARGV[3] --- sandbox directory
46
46
47 if ARGV.length < 2 || ARGV.length > 4
47 if ARGV.length < 2 || ARGV.length > 4
48 puts "Usage: judge <language> <program-source> [<test-result-directory>] [<sandbox-directory>]"
48 puts "Usage: judge <language> <program-source> [<test-result-directory>] [<sandbox-directory>]"
49 puts " <sandbox-directory> is defaulted to ./sandbox"
49 puts " <sandbox-directory> is defaulted to ./sandbox"
50 puts " <test-result-directory> is defaulted to ./test-result"
50 puts " <test-result-directory> is defaulted to ./test-result"
51 puts "WARNING: The judge script will forcefully create the (implicitly and explicitly) specified directories and remove anything inside it."
51 puts "WARNING: The judge script will forcefully create the (implicitly and explicitly) specified directories and remove anything inside it."
52 exit(127)
52 exit(127)
53 end
53 end
54
54
55 language = ARGV[0]
55 language = ARGV[0]
56 - if language != "c" && language != "c++" && language != "pas"
56 + if language != "c" && language != "c++" && language != "pas" && language != "java" && language != "ruby" && language != "python" && language != "php"
57 log "You specified a language that is not supported: #{language}."
57 log "You specified a language that is not supported: #{language}."
58 exit(127)
58 exit(127)
59 end
59 end
60
60
61 source_file = ARGV[1]
61 source_file = ARGV[1]
62 + ENV['SOURCE_NAME'] = source_file
62 if File.exist?(source_file) == false
63 if File.exist?(source_file) == false
63 log "The source file does not exist."
64 log "The source file does not exist."
64 exit(127)
65 exit(127)
65 end
66 end
66
67
67 log "Making test result and sandbox directories..."
68 log "Making test result and sandbox directories..."
68
69
69 current_dir = FileUtils.pwd
70 current_dir = FileUtils.pwd
70 current_dir.strip!
71 current_dir.strip!
71
72
72 if ARGV.length >= 3
73 if ARGV.length >= 3
73 test_result_dir = ARGV[2]
74 test_result_dir = ARGV[2]
@@ -101,47 +102,51
101 execute("#{problem_home}/script/compile #{language} #{source_file}", "Compilation error!")
102 execute("#{problem_home}/script/compile #{language} #{source_file}", "Compilation error!")
102 compile_message = open("compiler_message").read
103 compile_message = open("compiler_message").read
103 compile_message.strip!
104 compile_message.strip!
104 call_and_log("Cannot move the compiler message to #{test_result_dir}.") {
105 call_and_log("Cannot move the compiler message to #{test_result_dir}.") {
105 FileUtils.mv("compiler_message", test_result_dir)
106 FileUtils.mv("compiler_message", test_result_dir)
106 }
107 }
107 if !FileTest.exist?("a.out")
108 if !FileTest.exist?("a.out")
108 log "Cannot compile the source code. See message in #{test_result_dir}/compile_message"
109 log "Cannot compile the source code. See message in #{test_result_dir}/compile_message"
109 exit(127)
110 exit(127)
110 else
111 else
111 call_and_log("Cannot move the compiled program to #{test_result_dir}") {
112 call_and_log("Cannot move the compiled program to #{test_result_dir}") {
112 FileUtils.mv("a.out",test_result_dir)
113 FileUtils.mv("a.out",test_result_dir)
114 + if language == "java" then Dir["*.class"].each { |file| FileUtils.mv(file,test_result_dir)} end
115 + if language == "python" then Dir["*.pyc"].each { |file| FileUtils.mv(file,test_result_dir)} end
113 }
116 }
114 FileUtils.rm_rf("#{sandbox_dir}/.")
117 FileUtils.rm_rf("#{sandbox_dir}/.")
115 end
118 end
116
119
117 require "#{problem_home}/script/test_dsl.rb"
120 require "#{problem_home}/script/test_dsl.rb"
118 load "#{problem_home}/test_cases/all_tests.cfg"
121 load "#{problem_home}/test_cases/all_tests.cfg"
119 problem = Problem.get_instance
122 problem = Problem.get_instance
120
123
121 if problem.well_formed? == false
124 if problem.well_formed? == false
122 log "The problem specification is not well formed."
125 log "The problem specification is not well formed."
123 exit(127)
126 exit(127)
124 end
127 end
125
128
126 # Doing the testing.
129 # Doing the testing.
127 (1..(problem.num_tests)).each do |test_num|
130 (1..(problem.num_tests)).each do |test_num|
128
131
129 $stdout.print "[#{test_num}]"
132 $stdout.print "[#{test_num}]"
130 $stdout.flush
133 $stdout.flush
131
134
132 log "Test number: #{test_num}"
135 log "Test number: #{test_num}"
133
136
134 call_and_log("Cannot copy the compiled program into #{sandbox_dir}") {
137 call_and_log("Cannot copy the compiled program into #{sandbox_dir}") {
135 FileUtils.cp("#{test_result_dir}/a.out", sandbox_dir, :preserve => true)
138 FileUtils.cp("#{test_result_dir}/a.out", sandbox_dir, :preserve => true)
139 + if language == "java" then Dir["#{test_result_dir}/*.class"].each { |file| FileUtils.cp(file,sandbox_dir)} end
140 + if language == "python" then Dir["#{test_result_dir}/*.pyc"].each { |file| FileUtils.cp(file,sandbox_dir)} end
136 }
141 }
137
142
138 begin
143 begin
139 execute("#{problem_home}/script/run #{language} #{test_num}", "Error occured during execution of the run script")
144 execute("#{problem_home}/script/run #{language} #{test_num} ", "Error occured during execution of the run script")
140 rescue
145 rescue
141 # do nothing
146 # do nothing
142 end
147 end
143
148
144 call_and_log("Cannot create directory #{test_result_dir}/#{test_num}") {
149 call_and_log("Cannot create directory #{test_result_dir}/#{test_num}") {
145 FileUtils.mkdir "#{test_result_dir}/#{test_num}"
150 FileUtils.mkdir "#{test_result_dir}/#{test_num}"
146 }
151 }
147 call_and_log("Cannot copy the result file into #{test_result_dir}/#{test_num}") {
152 call_and_log("Cannot copy the result file into #{test_result_dir}/#{test_num}") {
@@ -34,28 +34,31
34 exit(127)
34 exit(127)
35 end
35 end
36
36
37 language = ARGV[0]
37 language = ARGV[0]
38 test_num = ARGV[1].to_i
38 test_num = ARGV[1].to_i
39 if ARGV.length > 2
39 if ARGV.length > 2
40 program_name = ARGV[2]
40 program_name = ARGV[2]
41 else
41 else
42 program_name = "a.out"
42 program_name = "a.out"
43 end
43 end
44
44
45 problem_home = ENV['PROBLEM_HOME']
45 problem_home = ENV['PROBLEM_HOME']
46 + source_name = ENV['SOURCE_NAME']
46 require "#{problem_home}/script/test_dsl.rb"
47 require "#{problem_home}/script/test_dsl.rb"
47 load "#{problem_home}/test_cases/all_tests.cfg"
48 load "#{problem_home}/test_cases/all_tests.cfg"
48 problem = Problem.get_instance
49 problem = Problem.get_instance
49
50
51 + sandbox_dir = Dir.getwd
52 +
50 if problem.well_formed? == false
53 if problem.well_formed? == false
51 log "The problem specification is not well formed."
54 log "The problem specification is not well formed."
52 exit(127)
55 exit(127)
53 end
56 end
54
57
55 # Check if the test number is okay.
58 # Check if the test number is okay.
56 if test_num <= 0 || test_num > problem.num_tests
59 if test_num <= 0 || test_num > problem.num_tests
57 log "You have specified a wrong test number."
60 log "You have specified a wrong test number."
58 exit(127)
61 exit(127)
59 end
62 end
60
63
61 #####################################
64 #####################################
@@ -72,34 +75,60
72 # Copy the input file.
75 # Copy the input file.
73 #`cp #{problem_home}/test_cases/#{test_num}/#{input_file_name} .`
76 #`cp #{problem_home}/test_cases/#{test_num}/#{input_file_name} .`
74
77
75 # check if box is there, if not, compile it!
78 # check if box is there, if not, compile it!
76 if !File.exists?("#{problem_home}/script/box")
79 if !File.exists?("#{problem_home}/script/box")
77 log "WARNING: Compiling box: to increase efficiency, it should be compile manually"
80 log "WARNING: Compiling box: to increase efficiency, it should be compile manually"
78 compile_box("#{problem_home}/script/box.cc",
81 compile_box("#{problem_home}/script/box.cc",
79 "#{problem_home}/script/box")
82 "#{problem_home}/script/box")
80 end
83 end
81
84
82 # Hide PROBLEM_HOME
85 # Hide PROBLEM_HOME
83 ENV['PROBLEM_HOME'] = nil
86 ENV['PROBLEM_HOME'] = nil
87 + ENV['SOURCE_NAME'] = nil
84
88
85 # Run the program.
89 # Run the program.
86 #run_command = "/usr/bin/time -f \"#{time_output_format}\" 2>run_result #{problem_home}/script/box_new -a 2 -f -t #{time_limit} -m #{mem_limit} -i #{input_file_name} -o output.txt #{program_name}"
90 #run_command = "/usr/bin/time -f \"#{time_output_format}\" 2>run_result #{problem_home}/script/box_new -a 2 -f -t #{time_limit} -m #{mem_limit} -i #{input_file_name} -o output.txt #{program_name}"
91 + #
87
92
88 - run_command = "#{problem_home}/script/box -a 2 -f -T -t #{time_limit} -m #{mem_limit} -i #{input_file_name} -o output.txt #{program_name} 2>run_result"
93 + JAVA_OPTION = "-s set_robust_list -s futex -s clone -s getppid -s clone -s wait4 -p /usr/bin/ -p ./"
94 + RUBY_OPTION = "-p /usr/lib64/ -p /usr/local/lib64/ -p /usr/local/lib/ -p /lib64/ -p /dev/urandom -p #{sandbox_dir}/#{program_name} -p #{sandbox_dir}/ -s set_robust_list -s sched_getaffinity -s clock_gettime -s sigaltstack -s pipe2 -s clone -s futex -s openat -s pipe"
95 + PYTHON_OPTION = "-p /usr/lib64/ -p /usr/local/lib64/ -p /usr/local/lib/ -p /usr/bin/ -p /lib64/ -p #{sandbox_dir}/#{program_name} -p ./#{program_name} -p #{sandbox_dir}/#{source_name} -s set_robust_list -s openat -s recvmsg -s connect -s socket -s sendto -s futex -E PYTHONNOUSERSITE=yes"
96 + PHP_OPTION = "-p /usr/lib64/ -p/lib64/ -p /usr/bin/ -p #{sandbox_dir}/#{program_name} -p ./#{program_name} -p /usr/share/ -s setfsuid -s setfsgid -s openat -s set_robust_list -s futex -s clone -s socket -s connect"
97 +
98 + case language
99 + when "java"
100 + # for java, extract the classname
101 + # wne have to add additional systemcall and we don't check the mem limit (dunno how to fix...)
102 + classname = 'DUMMY'
103 + File.open(program_name,"r").each do |line|
104 + classname = line
105 + end
106 + #for java, we cannot really check the memory limit...
107 + run_command = "#{problem_home}/script/box -a 3 -f -T -t #{time_limit} #{JAVA_OPTION} -i #{input_file_name} -o output.txt /usr/bin/java -A -Xmx#{mem_limit}k -A #{classname} "
108 + when "ruby"
109 + run_command = "#{problem_home}/script/box -a 2 -f -T -t #{time_limit*=2} -m #{mem_limit} #{RUBY_OPTION} -i #{input_file_name} -o output.txt /usr/bin/ruby #{program_name} "
110 + when "python"
111 + run_command = "#{problem_home}/script/box -a 2 -f -T -t #{time_limit*=2} -m #{mem_limit} #{PYTHON_OPTION} -i #{input_file_name} -o output.txt /usr/bin/python #{program_name} "
112 + when "php"
113 + run_command = "#{problem_home}/script/box -a 2 -f -T -t #{time_limit*=2} -m #{[128*1024,mem_limit].max} #{PHP_OPTION} -i #{input_file_name} -o output.txt /usr/bin/php -A -d -A memory_limit=#{mem_limit}k -A #{program_name} "
114 + else # for c++, pascal, we do the normal checking
115 + run_command = "#{problem_home}/script/box -a 2 -f -T -t #{time_limit} -m #{mem_limit} -i #{input_file_name} -o output.txt #{program_name} "
116 + end
117 +
89
118
90 log "Running test #{test_num}..."
119 log "Running test #{test_num}..."
91 log run_command
120 log run_command
92 log
121 log
93 - system(run_command)
122 + system(run_command,err: 'run_result')
94
123
95 # Restore PROBLEM_HOME
124 # Restore PROBLEM_HOME
96 ENV['PROBLEM_HOME'] = problem_home
125 ENV['PROBLEM_HOME'] = problem_home
97
126
98 # Create the result file.
127 # Create the result file.
99 result_file = File.new("result", "w")
128 result_file = File.new("result", "w")
100 comment_file = File.new("comment", "w")
129 comment_file = File.new("comment", "w")
101
130
102 # Check if the program actually produced any output.
131 # Check if the program actually produced any output.
103 run_result_file = File.new("run_result", "r")
132 run_result_file = File.new("run_result", "r")
104 run_result = run_result_file.readlines
133 run_result = run_result_file.readlines
105 run_result_file.close
134 run_result_file.close
@@ -123,30 +152,31
123 # added for debuggin --- jittat
152 # added for debuggin --- jittat
124 comment_file.write "--run-result--\n"
153 comment_file.write "--run-result--\n"
125 run_result.each do |l|
154 run_result.each do |l|
126 comment_file.write l
155 comment_file.write l
127 end
156 end
128
157
129 comment_file.close
158 comment_file.close
130
159
131 log "Done!"
160 log "Done!"
132 exit(0)
161 exit(0)
133 }
162 }
134
163
164 +
135 if run_result[0][0,2] != "OK"
165 if run_result[0][0,2] != "OK"
136 log "There was a runtime error."
166 log "There was a runtime error."
137 report.call(run_result[0], 0, "No comment.\n")
167 report.call(run_result[0], 0, "No comment.\n")
138 end
168 end
139
169
140 - if running_time[:user].to_f + running_time[:sys].to_f > time_limit
170 + if running_time[:user].to_f > time_limit
141 log "Time limit exceeded."
171 log "Time limit exceeded."
142 report.call("Time limit exceeded", 0, "No comment.\n")
172 report.call("Time limit exceeded", 0, "No comment.\n")
143 end
173 end
144
174
145 # Run 'check' to evaluate the output.
175 # Run 'check' to evaluate the output.
146 #puts "There was no runtime error. Proceed to checking the output."
176 #puts "There was no runtime error. Proceed to checking the output."
147 check_command = "#{problem_home}/script/check #{language} #{test_num}"
177 check_command = "#{problem_home}/script/check #{language} #{test_num}"
148 log "Checking the output..."
178 log "Checking the output..."
149 log check_command
179 log check_command
150 if not system(check_command)
180 if not system(check_command)
151 log "Problem with check script"
181 log "Problem with check script"
152 report.call("Incorrect",0,"Check script error.\n")
182 report.call("Incorrect",0,"Check script error.\n")
@@ -1,13 +1,13
1 - #!/usr/bin/ruby
1 + #!/usr/bin/env ruby
2
2
3 problem_home = ENV['PROBLEM_HOME']
3 problem_home = ENV['PROBLEM_HOME']
4 require "#{problem_home}/script/test_dsl.rb"
4 require "#{problem_home}/script/test_dsl.rb"
5
5
6 if ARGV.length < 2
6 if ARGV.length < 2
7 puts "Usage: check <language> <test-number> [<output-file>]"
7 puts "Usage: check <language> <test-number> [<output-file>]"
8 exit(0)
8 exit(0)
9 end
9 end
10
10
11 language = ARGV[0]
11 language = ARGV[0]
12 test_num = ARGV[1].to_i
12 test_num = ARGV[1].to_i
13 if ARGV.length >= 3
13 if ARGV.length >= 3
@@ -1,13 +1,13
1 - #!/usr/bin/ruby
1 + #!/usr/bin/env ruby
2
2
3 problem_home = ENV['PROBLEM_HOME']
3 problem_home = ENV['PROBLEM_HOME']
4 require "#{problem_home}/script/test_dsl.rb"
4 require "#{problem_home}/script/test_dsl.rb"
5
5
6 if ARGV.length < 2
6 if ARGV.length < 2
7 puts "Usage: check <language> <test-number> [<output-file>]"
7 puts "Usage: check <language> <test-number> [<output-file>]"
8 exit(0)
8 exit(0)
9 end
9 end
10
10
11 language = ARGV[0]
11 language = ARGV[0]
12 test_num = ARGV[1].to_i
12 test_num = ARGV[1].to_i
13 if ARGV.length >= 3
13 if ARGV.length >= 3
You need to be logged in to leave comments. Login now