Description:
add run_stat checking
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r160:f0502be39e3b - - 3 files changed: 49 inserted, 11 deleted

@@ -1,134 +1,152
1 module Grader
1 module Grader
2
2
3 class SubmissionRoomMaker
3 class SubmissionRoomMaker
4 def initialize
4 def initialize
5 @config = Grader::Configuration.get_instance
5 @config = Grader::Configuration.get_instance
6 end
6 end
7
7
8 def produce_grading_room(submission)
8 def produce_grading_room(submission)
9 user = submission.user
9 user = submission.user
10 problem = submission.problem
10 problem = submission.problem
11 grading_room = "#{@config.user_result_dir}/" +
11 grading_room = "#{@config.user_result_dir}/" +
12 "#{user.login}/#{problem.name}/#{submission.id}"
12 "#{user.login}/#{problem.name}/#{submission.id}"
13
13
14 FileUtils.mkdir_p(grading_room)
14 FileUtils.mkdir_p(grading_room)
15 grading_room
15 grading_room
16 end
16 end
17
17
18 def find_problem_home(submission)
18 def find_problem_home(submission)
19 problem = submission.problem
19 problem = submission.problem
20 "#{@config.problems_dir}/#{problem.name}"
20 "#{@config.problems_dir}/#{problem.name}"
21 end
21 end
22
22
23 def save_source(submission,source_name)
23 def save_source(submission,source_name)
24 dir = self.produce_grading_room(submission)
24 dir = self.produce_grading_room(submission)
25 f = File.open("#{dir}/#{source_name}","w")
25 f = File.open("#{dir}/#{source_name}","w")
26 f.write(submission.source)
26 f.write(submission.source)
27 f.close
27 f.close
28 end
28 end
29
29
30 def clean_up(submission)
30 def clean_up(submission)
31 end
31 end
32 end
32 end
33
33
34 class SubmissionReporter
34 class SubmissionReporter
35 def initialize(options={})
35 def initialize(options={})
36 options = {:dry_run => false, :result_collector => nil}.merge(options)
36 options = {:dry_run => false, :result_collector => nil}.merge(options)
37 @config = Grader::Configuration.get_instance
37 @config = Grader::Configuration.get_instance
38 @dry_run = options[:dry_run]
38 @dry_run = options[:dry_run]
39 @result_collector = options[:result_collector]
39 @result_collector = options[:result_collector]
40 end
40 end
41
41
42 def report(sub,test_result_dir)
42 def report(sub,test_result_dir)
43 result = read_result(test_result_dir)
43 result = read_result(test_result_dir)
44 if @result_collector
44 if @result_collector
45 @result_collector.save(sub,
45 @result_collector.save(sub,
46 result)
46 result)
47 end
47 end
48 save_result(sub,result)
48 save_result(sub,result)
49 end
49 end
50
50
51 def report_error(sub,msg)
51 def report_error(sub,msg)
52 save_result(sub,{:points => 0,
52 save_result(sub,{:points => 0,
53 :comment => "Grading error: #{msg}" })
53 :comment => "Grading error: #{msg}" })
54 end
54 end
55
55
56 protected
56 protected
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
123 submission.grader_comment = comment
141 submission.grader_comment = comment
124 end
142 end
125 submission.compiler_message = result[:cmp_msg] or ''
143 submission.compiler_message = result[:cmp_msg] or ''
126
144
127 if not @dry_run
145 if not @dry_run
128 submission.save
146 submission.save
129 end
147 end
130 end
148 end
131
149
132 end
150 end
133
151
134 end
152 end
@@ -1363,197 +1363,192
1363 while (*x)
1363 while (*x)
1364 {
1364 {
1365 char *key = x;
1365 char *key = x;
1366 while (*x && *x != ':' && *x != '\n')
1366 while (*x && *x != ':' && *x != '\n')
1367 x++;
1367 x++;
1368 if (!*x || *x == '\n')
1368 if (!*x || *x == '\n')
1369 break;
1369 break;
1370 *x++ = 0;
1370 *x++ = 0;
1371 while (*x == ' ' || *x == '\t')
1371 while (*x == ' ' || *x == '\t')
1372 x++;
1372 x++;
1373
1373
1374 char *val = x;
1374 char *val = x;
1375 while (*x && *x != '\n')
1375 while (*x && *x != '\n')
1376 x++;
1376 x++;
1377 if (!*x)
1377 if (!*x)
1378 break;
1378 break;
1379 *x++ = 0;
1379 *x++ = 0;
1380
1380
1381 if (!strcmp(key, "VmPeak"))
1381 if (!strcmp(key, "VmPeak"))
1382 {
1382 {
1383 int peak = atoi(val);
1383 int peak = atoi(val);
1384 if (peak > mem_peak_kb)
1384 if (peak > mem_peak_kb)
1385 mem_peak_kb = peak;
1385 mem_peak_kb = peak;
1386 }
1386 }
1387 }
1387 }
1388
1388
1389 if (verbose > 1)
1389 if (verbose > 1)
1390 msg("[mem-peak: %u KB]\n", mem_peak_kb);
1390 msg("[mem-peak: %u KB]\n", mem_peak_kb);
1391 }
1391 }
1392
1392
1393 static void
1393 static void
1394 boxkeeper(void)
1394 boxkeeper(void)
1395 {
1395 {
1396 int syscall_count = (filter_syscalls ? 0 : 1);
1396 int syscall_count = (filter_syscalls ? 0 : 1);
1397 struct sigaction sa;
1397 struct sigaction sa;
1398
1398
1399 is_ptraced = 1;
1399 is_ptraced = 1;
1400
1400
1401 bzero(&sa, sizeof(sa));
1401 bzero(&sa, sizeof(sa));
1402 sa.sa_handler = signal_int;
1402 sa.sa_handler = signal_int;
1403 sigaction(SIGINT, &sa, NULL);
1403 sigaction(SIGINT, &sa, NULL);
1404
1404
1405 gettimeofday(&start_time, NULL);
1405 gettimeofday(&start_time, NULL);
1406 ticks_per_sec = sysconf(_SC_CLK_TCK);
1406 ticks_per_sec = sysconf(_SC_CLK_TCK);
1407 if (ticks_per_sec <= 0)
1407 if (ticks_per_sec <= 0)
1408 die("Invalid ticks_per_sec!");
1408 die("Invalid ticks_per_sec!");
1409
1409
1410 if (timeout || wall_timeout)
1410 if (timeout || wall_timeout)
1411 {
1411 {
1412 sa.sa_handler = signal_alarm;
1412 sa.sa_handler = signal_alarm;
1413 sigaction(SIGALRM, &sa, NULL);
1413 sigaction(SIGALRM, &sa, NULL);
1414 alarm(1);
1414 alarm(1);
1415 }
1415 }
1416
1416
1417 for(;;)
1417 for(;;)
1418 {
1418 {
1419 struct rusage rus;
1419 struct rusage rus;
1420 int stat;
1420 int stat;
1421 pid_t p;
1421 pid_t p;
1422 if (timer_tick)
1422 if (timer_tick)
1423 {
1423 {
1424 check_timeout();
1424 check_timeout();
1425 timer_tick = 0;
1425 timer_tick = 0;
1426 }
1426 }
1427 p = wait4(box_pid, &stat, WUNTRACED, &rus);
1427 p = wait4(box_pid, &stat, WUNTRACED, &rus);
1428 if (p < 0)
1428 if (p < 0)
1429 {
1429 {
1430 if (errno == EINTR)
1430 if (errno == EINTR)
1431 continue;
1431 continue;
1432 die("wait4: %m");
1432 die("wait4: %m");
1433 }
1433 }
1434 if (p != box_pid)
1434 if (p != box_pid)
1435 die("wait4: unknown pid %d exited!", p);
1435 die("wait4: unknown pid %d exited!", p);
1436 if (WIFEXITED(stat))
1436 if (WIFEXITED(stat))
1437 {
1437 {
1438 box_pid = 0;
1438 box_pid = 0;
1439 final_stats(&rus);
1439 final_stats(&rus);
1440 if (WEXITSTATUS(stat))
1440 if (WEXITSTATUS(stat))
1441 {
1441 {
1442 if (syscall_count)
1442 if (syscall_count)
1443 {
1443 {
1444 meta_printf("exitcode:%d\n", WEXITSTATUS(stat));
1444 meta_printf("exitcode:%d\n", WEXITSTATUS(stat));
1445 err("RE: Exited with error status %d", WEXITSTATUS(stat));
1445 err("RE: Exited with error status %d", WEXITSTATUS(stat));
1446 }
1446 }
1447 else
1447 else
1448 {
1448 {
1449 // Internal error happened inside the child process and it has been already reported.
1449 // Internal error happened inside the child process and it has been already reported.
1450 box_exit(2);
1450 box_exit(2);
1451 }
1451 }
1452 }
1452 }
1453 if (timeout && total_ms > timeout)
1453 if (timeout && total_ms > timeout)
1454 err("TO: Time limit exceeded");
1454 err("TO: Time limit exceeded");
1455 if (wall_timeout && wall_ms > wall_timeout)
1455 if (wall_timeout && wall_ms > wall_timeout)
1456 err("TO: Time limit exceeded (wall clock)");
1456 err("TO: Time limit exceeded (wall clock)");
1457 flush_line();
1457 flush_line();
1458 fprintf(stderr,"OK\n");
1458 fprintf(stderr,"OK\n");
1459 - print_running_stat(
1460 - (double)wall_ms/1000,
1461 - (double)total_ms/1000,
1462 - (double)sys_ms/1000,
1463 - (mem_peak_kb + 1023) / 1024);
1464 box_exit(0);
1459 box_exit(0);
1465 }
1460 }
1466 if (WIFSIGNALED(stat))
1461 if (WIFSIGNALED(stat))
1467 {
1462 {
1468 box_pid = 0;
1463 box_pid = 0;
1469 meta_printf("exitsig:%d\n", WTERMSIG(stat));
1464 meta_printf("exitsig:%d\n", WTERMSIG(stat));
1470 final_stats(&rus);
1465 final_stats(&rus);
1471 err("SG: Caught fatal signal %d%s", WTERMSIG(stat), (syscall_count ? "" : " during startup"));
1466 err("SG: Caught fatal signal %d%s", WTERMSIG(stat), (syscall_count ? "" : " during startup"));
1472 }
1467 }
1473 if (WIFSTOPPED(stat))
1468 if (WIFSTOPPED(stat))
1474 {
1469 {
1475 int sig = WSTOPSIG(stat);
1470 int sig = WSTOPSIG(stat);
1476 if (sig == SIGTRAP)
1471 if (sig == SIGTRAP)
1477 {
1472 {
1478 if (verbose > 2)
1473 if (verbose > 2)
1479 msg("[ptrace status %08x] ", stat);
1474 msg("[ptrace status %08x] ", stat);
1480 static int stop_count;
1475 static int stop_count;
1481 if (!stop_count++) /* Traceme request */
1476 if (!stop_count++) /* Traceme request */
1482 msg(">> Traceme request caught\n");
1477 msg(">> Traceme request caught\n");
1483 else
1478 else
1484 err("SG: Breakpoint");
1479 err("SG: Breakpoint");
1485 ptrace(PTRACE_SYSCALL, box_pid, 0, 0);
1480 ptrace(PTRACE_SYSCALL, box_pid, 0, 0);
1486 }
1481 }
1487 else if (sig == (SIGTRAP | 0x80))
1482 else if (sig == (SIGTRAP | 0x80))
1488 {
1483 {
1489 if (verbose > 2)
1484 if (verbose > 2)
1490 msg("[ptrace status %08x] ", stat);
1485 msg("[ptrace status %08x] ", stat);
1491 struct syscall_args a;
1486 struct syscall_args a;
1492 static unsigned int sys_tick, last_act;
1487 static unsigned int sys_tick, last_act;
1493 static arg_t last_sys;
1488 static arg_t last_sys;
1494 if (++sys_tick & 1) /* Syscall entry */
1489 if (++sys_tick & 1) /* Syscall entry */
1495 {
1490 {
1496 char namebuf[32];
1491 char namebuf[32];
1497 int act;
1492 int act;
1498
1493
1499 get_syscall_args(&a, 0);
1494 get_syscall_args(&a, 0);
1500 arg_t sys = a.sys;
1495 arg_t sys = a.sys;
1501 msg(">> Syscall %-12s (%08jx,%08jx,%08jx) ", syscall_name(sys, namebuf), (intmax_t) a.arg1, (intmax_t) a.arg2, (intmax_t) a.arg3);
1496 msg(">> Syscall %-12s (%08jx,%08jx,%08jx) ", syscall_name(sys, namebuf), (intmax_t) a.arg1, (intmax_t) a.arg2, (intmax_t) a.arg3);
1502 if (!exec_seen)
1497 if (!exec_seen)
1503 {
1498 {
1504 msg("[master] ");
1499 msg("[master] ");
1505 if (sys == NATIVE_NR_execve)
1500 if (sys == NATIVE_NR_execve)
1506 {
1501 {
1507 exec_seen = 1;
1502 exec_seen = 1;
1508 close_user_mem();
1503 close_user_mem();
1509 }
1504 }
1510 }
1505 }
1511 else if ((act = valid_syscall(&a)) >= 0)
1506 else if ((act = valid_syscall(&a)) >= 0)
1512 {
1507 {
1513 last_act = act;
1508 last_act = act;
1514 syscall_count++;
1509 syscall_count++;
1515 if (act & A_SAMPLE_MEM)
1510 if (act & A_SAMPLE_MEM)
1516 sample_mem_peak();
1511 sample_mem_peak();
1517 }
1512 }
1518 else
1513 else
1519 {
1514 {
1520 /*
1515 /*
1521 * Unfortunately, PTRACE_KILL kills _after_ the syscall completes,
1516 * Unfortunately, PTRACE_KILL kills _after_ the syscall completes,
1522 * so we have to change it to something harmless (e.g., an undefined
1517 * so we have to change it to something harmless (e.g., an undefined
1523 * syscall) and make the program continue.
1518 * syscall) and make the program continue.
1524 */
1519 */
1525 set_syscall_nr(&a, ~(arg_t)0);
1520 set_syscall_nr(&a, ~(arg_t)0);
1526 err("FO: Forbidden syscall %s", syscall_name(sys, namebuf));
1521 err("FO: Forbidden syscall %s", syscall_name(sys, namebuf));
1527 }
1522 }
1528 last_sys = sys;
1523 last_sys = sys;
1529 }
1524 }
1530 else /* Syscall return */
1525 else /* Syscall return */
1531 {
1526 {
1532 get_syscall_args(&a, 1);
1527 get_syscall_args(&a, 1);
1533 if (a.sys == ~(arg_t)0)
1528 if (a.sys == ~(arg_t)0)
1534 {
1529 {
1535 /* Some syscalls (sigreturn et al.) do not return a value */
1530 /* Some syscalls (sigreturn et al.) do not return a value */
1536 if (!(last_act & A_NO_RETVAL))
1531 if (!(last_act & A_NO_RETVAL))
1537 err("XX: Syscall does not return, but it should");
1532 err("XX: Syscall does not return, but it should");
1538 }
1533 }
1539 else
1534 else
1540 {
1535 {
1541 if (a.sys != last_sys)
1536 if (a.sys != last_sys)
1542 err("XX: Mismatched syscall entry/exit");
1537 err("XX: Mismatched syscall entry/exit");
1543 }
1538 }
1544 if (last_act & A_NO_RETVAL)
1539 if (last_act & A_NO_RETVAL)
1545 msg("= ?\n");
1540 msg("= ?\n");
1546 else
1541 else
1547 msg("= %jd\n", (intmax_t) a.result);
1542 msg("= %jd\n", (intmax_t) a.result);
1548 }
1543 }
1549 ptrace(PTRACE_SYSCALL, box_pid, 0, 0);
1544 ptrace(PTRACE_SYSCALL, box_pid, 0, 0);
1550 }
1545 }
1551 else if (sig == SIGSTOP)
1546 else if (sig == SIGSTOP)
1552 {
1547 {
1553 msg(">> SIGSTOP\n");
1548 msg(">> SIGSTOP\n");
1554 if (ptrace(PTRACE_SETOPTIONS, box_pid, NULL, (void *) PTRACE_O_TRACESYSGOOD) < 0)
1549 if (ptrace(PTRACE_SETOPTIONS, box_pid, NULL, (void *) PTRACE_O_TRACESYSGOOD) < 0)
1555 die("ptrace(PTRACE_SETOPTIONS): %m");
1550 die("ptrace(PTRACE_SETOPTIONS): %m");
1556 ptrace(PTRACE_SYSCALL, box_pid, 0, 0);
1551 ptrace(PTRACE_SYSCALL, box_pid, 0, 0);
1557 }
1552 }
1558 else if (sig != SIGXCPU && sig != SIGXFSZ)
1553 else if (sig != SIGXCPU && sig != SIGXFSZ)
1559 {
1554 {
@@ -1,108 +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)
35 + puts "TIME: #{t}"
36 + if (result=/^(.*)r(.*)u(.*)s(.*)m/.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
77 result_file.close
95 result_file.close
78 end
96 end
79 end
97 end
80
98
81 run_result_file = File.new("result-#{k}", "w")
99 run_result_file = File.new("result-#{k}", "w")
82 run_result_file.write run_score
100 run_result_file.write run_score
83 run_result_file.write "\n"
101 run_result_file.write "\n"
84 run_result_file.close
102 run_result_file.close
85
103
86 run_comment_file = File.new("comment-#{k}", "w")
104 run_comment_file = File.new("comment-#{k}", "w")
87 run_comment_file.write "#{run_comment}\n"
105 run_comment_file.write "#{run_comment}\n"
88 run_comment_file.close
106 run_comment_file.close
89
107
90 all_score = all_score + run_score
108 all_score = all_score + run_score
91
109
92 # append comment for test run with many test cases
110 # append comment for test run with many test cases
93 if run.tests.length > 1
111 if run.tests.length > 1
94 run_comment_short = '[' + run_comment_short + ']'
112 run_comment_short = '[' + run_comment_short + ']'
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
107
125
108 - log "score = #{all_score} comment = #{all_comment}"
126 +
127 + File.open("run_stat","w") do |file|
128 + file.puts max_runtime
129 + file.puts peak_memory
130 + end
131 +
132 + log "score = #{all_score}\ncomment = #{all_comment}"
133 + log "max_runtime = #{max_runtime}\npeak_memory = #{peak_memory}"
You need to be logged in to leave comments. Login now