Description:
[web] analysis mode git-svn-id: http://theory.cpe.ku.ac.th/grader/web/trunk@265 6386c4cd-e34a-4fa8-8920-d93eb39b512e
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r134:d2c58c857008 - - 6 files changed: 240 inserted, 1 deleted

@@ -0,0 +1,18
1 + %td
2 + = test_case[:num]
3 + %td{:style => 'padding-left: 5px; padding-right: 5px'}
4 + = test_case[:msg]
5 + - if test_case[:run_stat]!=nil
6 + %td{:style => 'padding-left: 5px; padding-right: 5px'}
7 + = test_case[:run_stat][:exit_status]
8 + %td{:style => 'padding-left: 5px; padding-right: 3px; text-align: center'}
9 + = test_case[:run_stat][:running_time]
10 + %td{:style => 'padding-left: 5px; padding-right: 10px; text-align: right'}
11 + = number_with_delimiter(test_case[:run_stat][:memory_usage])
12 + %td{:style => 'padding-left: 5px; padding-right: 5px'}
13 + = link_to "output (#{number_to_human_size(test_case[:output_size])})", :action => 'load_output', :id => @submission.id, :num => test_case[:num] if test_case[:output]
14 + - else
15 + %td
16 + %td
17 + %td
18 + %td
@@ -0,0 +1,41
1 + = user_title_bar(@user)
2 +
3 + %h2
4 + Grading Result for Task
5 + = @submission.problem.full_name
6 +
7 + %p
8 + = "Submission: #{@submission.number}"
9 + %br/
10 + = "Submitted at: #{format_short_time(@submission.submitted_at)}"
11 + %br/
12 + = "Graded at #{format_short_time(@submission.graded_at)} "
13 + %br/
14 + = "score: #{(@submission.points*100/@submission.problem.full_score).to_i} " if Configuration['ui.show_score']
15 + = " ["
16 + %tt
17 + = @submission.grader_comment
18 + = "]"
19 +
20 + %table.info
21 + %tr.info-head
22 + %th Runs
23 + %th Cases
24 + %th Result
25 + %th Exit
26 + %th Time (s)
27 + %th Memory (KB)
28 + %th Output
29 + - r = 0
30 + - @test_runs.each do |test_run|
31 + - r += 1
32 + - case_count = test_run.length
33 + - first_case = true
34 + - test_run.each do |test_case|
35 + %tr{:class => ((r%2==0) ? "info-even" : "info-odd")}
36 + - if first_case
37 + %td{:rowspan => case_count}
38 + = r
39 + - first_case = false
40 + = render :partial => 'test_case_result', :locals => {:test_case => test_case}
41 +
@@ -116,24 +116,64
116 116 def submission
117 117 @user = User.find(session[:user_id])
118 118 @problems = Problem.find_available_problems
119 119 if params[:id]==nil
120 120 @problem = nil
121 121 @submissions = nil
122 122 else
123 123 @problem = Problem.find_by_name(params[:id])
124 124 @submissions = Submission.find_all_by_user_problem(@user.id, @problem.id)
125 125 end
126 126 end
127 127
128 + def result
129 + if !Configuration.show_grading_result
130 + redirect_to :action => 'list' and return
131 + end
132 + @user = User.find(session[:user_id])
133 + @submission = Submission.find(params[:id])
134 + if @submission.user!=@user
135 + flash[:notice] = 'You are not allowed to view result of other users.'
136 + redirect_to :action => 'list' and return
137 + end
138 + prepare_grading_result(@submission)
139 + end
140 +
141 + def load_output
142 + if !Configuration.show_grading_result or params[:num]==nil
143 + redirect_to :action => 'list' and return
144 + end
145 + @user = User.find(session[:user_id])
146 + @submission = Submission.find(params[:id])
147 + if @submission.user!=@user
148 + flash[:notice] = 'You are not allowed to view result of other users.'
149 + redirect_to :action => 'list' and return
150 + end
151 + case_num = params[:num].to_i
152 + out_filename = output_filename(@user.login,
153 + @submission.problem.name,
154 + @submission.id,
155 + case_num)
156 + if !FileTest.exists?(out_filename)
157 + flash[:notice] = 'Output not found.'
158 + redirect_to :action => 'list' and return
159 + end
160 +
161 + response.headers['Content-Type'] = "application/force-download"
162 + response.headers['Content-Disposition'] = "attachment; filename=\"output-#{case_num}.txt\""
163 + response.headers["X-Sendfile"] = out_filename
164 + response.headers['Content-length'] = File.size(out_filename)
165 + render :nothing => true
166 + end
167 +
128 168 def error
129 169 @user = User.find(session[:user_id])
130 170 end
131 171
132 172 protected
133 173 def prepare_list_information
134 174 @problems = Problem.find_available_problems
135 175 @prob_submissions = Array.new
136 176 @user = User.find(session[:user_id])
137 177 @problems.each do |p|
138 178 sub = Submission.find_last_by_user_and_problem(@user.id,p.id)
139 179 if sub!=nil
@@ -147,14 +187,114
147 187 :conditions => "published = 1",
148 188 :order => "created_at DESC")
149 189 end
150 190
151 191 def check_viewability
152 192 @user = User.find(session[:user_id])
153 193 if (!Configuration.show_tasks_to?(@user)) and
154 194 ((action_name=='submission') or (action_name=='submit'))
155 195 redirect_to :action => 'list' and return
156 196 end
157 197 end
158 198
199 + def prepare_grading_result(submission)
200 + grading_info = Configuration.task_grading_info[submission.problem.name]
201 + @test_runs = []
202 + if grading_info['testruns'].is_a? Integer
203 + trun_count = grading_info['testruns']
204 + trun_count.times do |i|
205 + @test_runs << [ read_grading_result(@user.login,
206 + submission.problem.name,
207 + submission.id,
208 + i+1) ]
209 + end
210 + else
211 + grading_info['testruns'].keys.sort.each do |num|
212 + run = []
213 + testrun = grading_info['testruns'][num]
214 + testrun.each do |c|
215 + run << read_grading_result(@user.login,
216 + submission.problem.name,
217 + submission.id,
218 + c)
219 + end
220 + @test_runs << run
221 + end
222 + end
223 + end
224 +
225 + def grading_result_dir(user_name, problem_name, submission_id, case_num)
226 + return "#{GRADING_RESULT_DIR}/#{user_name}/#{problem_name}/#{submission_id}/test-result/#{case_num}"
227 + end
228 +
229 + def output_filename(user_name, problem_name, submission_id, case_num)
230 + dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
231 + return "#{dir}/output.txt"
159 232 end
160 233
234 + def read_grading_result(user_name, problem_name, submission_id, case_num)
235 + dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
236 + result_file_name = "#{dir}/result"
237 + if !FileTest.exists?(result_file_name)
238 + return {:num => case_num, :msg => 'program did not run'}
239 + else
240 + results = File.open(result_file_name).readlines
241 + run_stat = extract_running_stat(results)
242 + output_filename = "#{dir}/output.txt"
243 + if FileTest.exists?(output_filename)
244 + output_file = true
245 + output_size = File.size(output_filename)
246 + else
247 + output_file = false
248 + output_size = 0
249 + end
250 +
251 + return {
252 + :num => case_num,
253 + :msg => results[0],
254 + :run_stat => run_stat,
255 + :output => output_file,
256 + :output_size => output_size
257 + }
258 + end
259 + end
260 +
261 + # copied from grader/script/lib/test_request_helper.rb
262 + def extract_running_stat(results)
263 + running_stat_line = results[-1]
264 +
265 + # extract exit status line
266 + run_stat = ""
267 + if !(/[Cc]orrect/.match(results[0]))
268 + run_stat = results[0].chomp
269 + else
270 + run_stat = 'Program exited normally'
271 + end
272 +
273 + logger.info "Stat line: #{running_stat_line}"
274 +
275 + # extract running time
276 + if res = /r(.*)u(.*)s/.match(running_stat_line)
277 + seconds = (res[1].to_f + res[2].to_f)
278 + time_stat = "Time used: #{seconds} sec."
279 + else
280 + seconds = nil
281 + time_stat = "Time used: n/a sec."
282 + end
283 +
284 + # extract memory usage
285 + if res = /s(.*)m/.match(running_stat_line)
286 + memory_used = res[1].to_i
287 + else
288 + memory_used = -1
289 + end
290 +
291 + return {
292 + :msg => "#{run_stat}\n#{time_stat}",
293 + :running_time => seconds,
294 + :exit_status => run_stat,
295 + :memory_usage => memory_used
296 + }
297 + end
298 +
299 + end
300 +
@@ -1,20 +1,23
1 + require 'yaml'
2 +
1 3 #
2 4 # This class also contains various login of the system.
3 5 #
4 6 class Configuration < ActiveRecord::Base
5 7
6 8 SYSTEM_MODE_CONF_KEY = 'system.mode'
7 9
8 10 @@configurations = nil
11 + @@task_grading_info = nil
9 12
10 13 def self.get(key)
11 14 if @@configurations == nil
12 15 self.read_config
13 16 end
14 17 return @@configurations[key]
15 18 end
16 19
17 20 def self.[](key)
18 21 self.get(key)
19 22 end
20 23
@@ -38,41 +41,58
38 41 end
39 42 return true
40 43 end
41 44
42 45 def self.show_tasks_to?(user)
43 46 mode = get(SYSTEM_MODE_CONF_KEY)
44 47 if (mode=='contest')
45 48 return false if (user.site!=nil) and (user.site.started!=true)
46 49 end
47 50 return true
48 51 end
49 52
53 + def self.show_grading_result
54 + return (get(SYSTEM_MODE_CONF_KEY)=='analysis')
55 + end
56 +
50 57 def self.allow_test_request(user)
51 58 mode = get(SYSTEM_MODE_CONF_KEY)
52 59 if (mode=='contest')
53 60 return false if (user.site!=nil) and ((user.site.started!=true) or (user.site.time_left < 30.minutes))
54 61 end
55 62 return false if mode=='analysis'
56 63 return true
57 64 end
58 65
66 + def self.task_grading_info
67 + if @@task_grading_info==nil
68 + read_grading_info
69 + end
70 + return @@task_grading_info
71 + end
72 +
59 73 protected
60 74 def self.read_config
61 75 @@configurations = {}
62 76 Configuration.find(:all).each do |conf|
63 77 key = conf.key
64 78 val = conf.value
65 79 case conf.value_type
66 80 when 'string'
67 81 @@configurations[key] = val
68 82
69 83 when 'integer'
70 84 @@configurations[key] = val.to_i
71 85
72 86 when 'boolean'
73 87 @@configurations[key] = (val=='true')
74 88 end
75 89 end
76 90 end
77 91
92 + def self.read_grading_info
93 + f = File.open(TASK_GRADING_INFO_FILENAME)
94 + @@task_grading_info = YAML.load(f)
95 + f.close
78 96 end
97 +
98 + end
@@ -3,18 +3,21
3 3 = "-"
4 4 - else
5 5 - if submission.graded_at==nil
6 6 Submitted at
7 7 = format_short_time(submission.submitted_at)
8 8 - else
9 9 = "Graded at #{format_short_time(submission.graded_at)}, "
10 10 = "score: #{(submission.points*100/submission.problem.full_score).to_i} " if Configuration['ui.show_score']
11 11 = " ["
12 12 %tt
13 13 = submission.grader_comment
14 14 = "]"
15 + - if Configuration.show_grading_result
16 + = " | "
17 + = link_to '[detailed result]', :action => 'result', :id => submission.id
15 18 = " | "
16 19 = link_to('[msg]', {:action => 'compiler_msg', :id => submission.id}, {:popup => true})
17 20 = " | "
18 - = link_to('[source]',{:action => 'source', :id => submission.id})
21 + = link_to('[src]',{:action => 'source', :id => submission.id})
19 22 = " | "
20 23 = link_to '[submissions]', :action => 'submission', :id => problem_name
@@ -55,17 +55,34
55 55 <a href="/tasks/view/roads-th.pdf">Thailand</a><br/>
56 56
57 57 <strong>DNA:</strong>
58 58 <a href="/tasks/view/dna-en.pdf">Official English</a>&nbsp;&nbsp;
59 59 <a href="/tasks/view/apio2008-cn.pdf">China (all tasks)</a>&nbsp;&nbsp;
60 60 <a href="/tasks/view/dna-tw.pdf">Chinese Taipei</a>&nbsp;&nbsp;
61 61 <a href="/tasks/view/dna-id.pdf">Indonesia</a>&nbsp;&nbsp;
62 62 <a href="/tasks/view/dna-jp.pdf">Japan</a>&nbsp;&nbsp;
63 63 <a href="/tasks/view/dna-kr.pdf">Korea</a>&nbsp;&nbsp;
64 64 <a href="/tasks/view/dna-mo.pdf">Macao, China</a>&nbsp;&nbsp;
65 65 <a href="/tasks/view/dna-th.pdf">Thailand</a>
66 66 </p>
67 +
68 + <p> <b>Test data</b> for all tasks:
69 + <a href="/files/testdata/all.zip">.zip</a>
70 + <a href="/files/testdata/all.tgz">.tgz</a><br/>
71 + <b>Beads:</b>
72 + <a href="/files/testdata/beads.zip">.zip</a>
73 + <a href="/files/testdata/beads.tgz">.tgz</a>&nbsp;&nbsp;
74 + <b>Roads:</b>
75 + <a href="/files/testdata/roads.zip">.zip</a>
76 + <a href="/files/testdata/roads.tgz">.tgz</a>&nbsp;&nbsp;
77 + <b>DNA:</b>
78 + <a href="/files/testdata/dna.zip">.zip</a>
79 + <a href="/files/testdata/dna.tgz">.tgz</a><br/>
80 + <b>Notes:</b><br/>
81 + &nbsp;&nbsp;<i>Beads.</i> The zip files contain the testing library that also outputs some magic numbers to verify the correct usage of the library. Files <tt>questions-*.txt</tt> are also prefixed with fake data.<br/>
82 + &nbsp;&nbsp;<i>Roads.</i> The zip files contain <tt>verify.cpp</tt> that checks the output.
83 + </p>
67 84 </td>
68 85 </tr>
69 86
70 87 <%= render :partial => 'problem', :collection => @problems %>
71 88 </table>
You need to be logged in to leave comments. Login now