Description:
[grader] added fractional timelimit git-svn-id: http://theory.cpe.ku.ac.th/grader/judge/trunk/scripts@191 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

r51:3618759afb50 - - 6 files changed: 62 inserted, 53 deleted

@@ -0,0 +1,38
1 + #include <stdio.h>
2 + #include <stdlib.h>
3 + #include <unistd.h>
4 + #include <sys/time.h>
5 + #include <time.h>
6 + #include <sys/resource.h>
7 +
8 + // run it for 1.5 s
9 +
10 + int main()
11 + {
12 + int a,b;
13 +
14 + int c=0;
15 +
16 + scanf("%d %d",&a,&b);
17 + printf("%d\n",a+b);
18 +
19 + struct rusage ru;
20 +
21 + while(1) {
22 + c++;
23 + b+=c;
24 + while(c<100000) {
25 + c++;
26 + b+=c;
27 + }
28 + getrusage(RUSAGE_SELF,&ru);
29 + double rtime = ru.ru_utime.tv_sec + ru.ru_stime.tv_sec;
30 + rtime += (double)ru.ru_utime.tv_usec / 1000000.0;
31 + rtime += (double)ru.ru_stime.tv_usec / 1000000.0;
32 + if(rtime > 0.5)
33 + break;
34 + }
35 + printf("%d\n",b);
36 + exit(0);
37 + }
38 +
@@ -146,39 +146,44
146 while true
146 while true
147
147
148 if check_stopfile # created by calling grader stop
148 if check_stopfile # created by calling grader stop
149 clear_stopfile
149 clear_stopfile
150 log "stopped (with stop file)"
150 log "stopped (with stop file)"
151 break
151 break
152 end
152 end
153
153
154 if grader_mode=="queue"
154 if grader_mode=="queue"
155 task = runner.grade_oldest_task
155 task = runner.grade_oldest_task
156 else
156 else
157 task = runner.grade_oldest_test_request
157 task = runner.grade_oldest_test_request
158 end
158 end
159 if task==nil
159 if task==nil
160 sleep(1)
160 sleep(1)
161 end
161 end
162 end
162 end
163
163
164 when "prob"
164 when "prob"
165 engine = Grader::Engine.new
165 engine = Grader::Engine.new
166 runner = Grader::Runner.new(engine, grader_proc)
166 runner = Grader::Runner.new(engine, grader_proc)
167
167
168 grader_proc.report_active if grader_proc!=nil
168 grader_proc.report_active if grader_proc!=nil
169
169
170 - prob = Problem.find_by_name(ARGV[2])
170 + ARGV.shift
171 + ARGV.shift
172 +
173 + ARGV.each do |prob_name|
174 + prob = Problem.find_by_name(prob_name)
171 if prob==nil
175 if prob==nil
172 - puts "cannot find problem: #{ARGV[2]}"
176 + puts "cannot find problem: #{prob_name}"
173 else
177 else
174 runner.grade_problem(prob)
178 runner.grade_problem(prob)
175 end
179 end
180 + end
176
181
177 else
182 else
178 display_manual
183 display_manual
179 exit(0)
184 exit(0)
180 end
185 end
181
186
182 # report inactive
187 # report inactive
183 grader_proc.report_inactive if grader_proc!=nil
188 grader_proc.report_inactive if grader_proc!=nil
184
189
@@ -8,49 +8,49
8 //#define _GNU_SOURCE
8 //#define _GNU_SOURCE
9
9
10 #include <errno.h>
10 #include <errno.h>
11 #include <stdio.h>
11 #include <stdio.h>
12 #include <fcntl.h>
12 #include <fcntl.h>
13 #include <stdlib.h>
13 #include <stdlib.h>
14 #include <string.h>
14 #include <string.h>
15 #include <stdarg.h>
15 #include <stdarg.h>
16 #include <unistd.h>
16 #include <unistd.h>
17 #include <getopt.h>
17 #include <getopt.h>
18 #include <time.h>
18 #include <time.h>
19 #include <sys/wait.h>
19 #include <sys/wait.h>
20 #include <sys/user.h>
20 #include <sys/user.h>
21 #include <sys/time.h>
21 #include <sys/time.h>
22 #include <sys/ptrace.h>
22 #include <sys/ptrace.h>
23 #include <sys/signal.h>
23 #include <sys/signal.h>
24 #include <sys/sysinfo.h>
24 #include <sys/sysinfo.h>
25 #include <sys/syscall.h>
25 #include <sys/syscall.h>
26 #include <sys/resource.h>
26 #include <sys/resource.h>
27
27
28 #define NONRET __attribute__((noreturn))
28 #define NONRET __attribute__((noreturn))
29 #define UNUSED __attribute__((unused))
29 #define UNUSED __attribute__((unused))
30
30
31 static int filter_syscalls; /* 0=off, 1=liberal, 2=totalitarian */
31 static int filter_syscalls; /* 0=off, 1=liberal, 2=totalitarian */
32 - static int timeout;
32 + static double timeout;
33 static int pass_environ;
33 static int pass_environ;
34 static int use_wall_clock;
34 static int use_wall_clock;
35 static int file_access;
35 static int file_access;
36 static int verbose;
36 static int verbose;
37 static int memory_limit;
37 static int memory_limit;
38 static int allow_times;
38 static int allow_times;
39 static char *redir_stdin, *redir_stdout;
39 static char *redir_stdin, *redir_stdout;
40 static char *set_cwd;
40 static char *set_cwd;
41
41
42 static pid_t box_pid;
42 static pid_t box_pid;
43 static int is_ptraced;
43 static int is_ptraced;
44 static volatile int timer_tick;
44 static volatile int timer_tick;
45 static time_t start_time;
45 static time_t start_time;
46 static int ticks_per_sec;
46 static int ticks_per_sec;
47 static int page_size;
47 static int page_size;
48
48
49 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ > 0
49 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ > 0
50 /* glibc 2.1 or newer -> has lseek64 */
50 /* glibc 2.1 or newer -> has lseek64 */
51 #define long_seek(f,o,w) lseek64(f,o,w)
51 #define long_seek(f,o,w) lseek64(f,o,w)
52 #else
52 #else
53 /* Touching clandestine places in glibc */
53 /* Touching clandestine places in glibc */
54 extern loff_t llseek(int fd, loff_t pos, int whence);
54 extern loff_t llseek(int fd, loff_t pos, int whence);
55 #define long_seek(f,o,w) llseek(f,o,w)
55 #define long_seek(f,o,w) llseek(f,o,w)
56 #endif
56 #endif
@@ -306,90 +306,90
306 return 0;
306 return 0;
307 }
307 }
308 }
308 }
309
309
310 static void
310 static void
311 signal_alarm(int unused UNUSED)
311 signal_alarm(int unused UNUSED)
312 {
312 {
313 /* Time limit checks are synchronous, so we only schedule them there. */
313 /* Time limit checks are synchronous, so we only schedule them there. */
314 timer_tick = 1;
314 timer_tick = 1;
315
315
316 //NOTE: do not use alarm, changed to setitimer for precision
316 //NOTE: do not use alarm, changed to setitimer for precision
317 // alarm(1);
317 // alarm(1);
318 }
318 }
319
319
320 static void
320 static void
321 signal_int(int unused UNUSED)
321 signal_int(int unused UNUSED)
322 {
322 {
323 /* Interrupts are fatal, so no synchronization requirements. */
323 /* Interrupts are fatal, so no synchronization requirements. */
324 die("Interrupted.");
324 die("Interrupted.");
325 }
325 }
326
326
327 static void
327 static void
328 check_timeout(void)
328 check_timeout(void)
329 {
329 {
330 - int sec;
330 + double sec;
331
331
332 if (use_wall_clock)
332 if (use_wall_clock)
333 - sec = time(NULL) - start_time;
333 + sec = (double)(time(NULL) - start_time);
334 else
334 else
335 {
335 {
336 char buf[4096], *x;
336 char buf[4096], *x;
337 int c, utime, stime;
337 int c, utime, stime;
338 static int proc_status_fd;
338 static int proc_status_fd;
339 if (!proc_status_fd)
339 if (!proc_status_fd)
340 {
340 {
341 sprintf(buf, "/proc/%d/stat", (int) box_pid);
341 sprintf(buf, "/proc/%d/stat", (int) box_pid);
342 proc_status_fd = open(buf, O_RDONLY);
342 proc_status_fd = open(buf, O_RDONLY);
343 if (proc_status_fd < 0)
343 if (proc_status_fd < 0)
344 die("open(%s): %m", buf);
344 die("open(%s): %m", buf);
345 }
345 }
346 lseek(proc_status_fd, 0, SEEK_SET);
346 lseek(proc_status_fd, 0, SEEK_SET);
347 if ((c = read(proc_status_fd, buf, sizeof(buf)-1)) < 0)
347 if ((c = read(proc_status_fd, buf, sizeof(buf)-1)) < 0)
348 die("read on /proc/$pid/stat: %m");
348 die("read on /proc/$pid/stat: %m");
349 if (c >= (int) sizeof(buf) - 1)
349 if (c >= (int) sizeof(buf) - 1)
350 die("/proc/$pid/stat too long");
350 die("/proc/$pid/stat too long");
351 buf[c] = 0;
351 buf[c] = 0;
352 x = buf;
352 x = buf;
353 while (*x && *x != ' ')
353 while (*x && *x != ' ')
354 x++;
354 x++;
355 while (*x == ' ')
355 while (*x == ' ')
356 x++;
356 x++;
357 if (*x++ != '(')
357 if (*x++ != '(')
358 die("proc syntax error 1");
358 die("proc syntax error 1");
359 while (*x && (*x != ')' || x[1] != ' '))
359 while (*x && (*x != ')' || x[1] != ' '))
360 x++;
360 x++;
361 while (*x == ')' || *x == ' ')
361 while (*x == ')' || *x == ' ')
362 x++;
362 x++;
363 if (sscanf(x, "%*c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d %d", &utime, &stime) != 2)
363 if (sscanf(x, "%*c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d %d", &utime, &stime) != 2)
364 die("proc syntax error 2");
364 die("proc syntax error 2");
365 //printf("%s - %d\n",x,ticks_per_sec);
365 //printf("%s - %d\n",x,ticks_per_sec);
366 - sec = (utime + stime + ticks_per_sec-1)/ticks_per_sec;
366 + sec = ((double)(utime + stime))/(double)ticks_per_sec;
367 }
367 }
368 if (verbose > 1)
368 if (verbose > 1)
369 fprintf(stderr, "[timecheck: %d seconds]\n", sec);
369 fprintf(stderr, "[timecheck: %d seconds]\n", sec);
370 if (sec > timeout) {
370 if (sec > timeout) {
371 - die("Time limit exceeded.");
371 + die("Time limit exceeded.",sec,timeout);
372 }
372 }
373 }
373 }
374
374
375 static void
375 static void
376 check_memory_usage()
376 check_memory_usage()
377 {
377 {
378 char proc_fname[100];
378 char proc_fname[100];
379 sprintf(proc_fname,"/proc/%d/statm",box_pid);
379 sprintf(proc_fname,"/proc/%d/statm",box_pid);
380 //printf("proc fname: %s\n",proc_fname);
380 //printf("proc fname: %s\n",proc_fname);
381 FILE *fp = fopen(proc_fname,"r");
381 FILE *fp = fopen(proc_fname,"r");
382 if(fp!=NULL) {
382 if(fp!=NULL) {
383 char line[1000];
383 char line[1000];
384 fgets(line,999,fp);
384 fgets(line,999,fp);
385 //printf("%s\n",line);
385 //printf("%s\n",line);
386 int m;
386 int m;
387
387
388 if(sscanf(line,"%d",&m)==1) {
388 if(sscanf(line,"%d",&m)==1) {
389 m = (m*page_size+1023)/1024;
389 m = (m*page_size+1023)/1024;
390 if(m>max_mem_used)
390 if(m>max_mem_used)
391 max_mem_used = m;
391 max_mem_used = m;
392 }
392 }
393
393
394 fclose(fp);
394 fclose(fp);
395 }
395 }
@@ -445,49 +445,52
445 check_timeout();
445 check_timeout();
446 check_memory_usage();
446 check_memory_usage();
447 timer_tick = 0;
447 timer_tick = 0;
448 }
448 }
449 p = wait4(box_pid, &stat, WUNTRACED, &rus);
449 p = wait4(box_pid, &stat, WUNTRACED, &rus);
450
450
451 if (p < 0)
451 if (p < 0)
452 {
452 {
453 if (errno == EINTR)
453 if (errno == EINTR)
454 continue;
454 continue;
455 die("wait4: %m");
455 die("wait4: %m");
456 }
456 }
457 if (p != box_pid)
457 if (p != box_pid)
458 die("wait4: unknown pid %d exited!", p);
458 die("wait4: unknown pid %d exited!", p);
459 if (WIFEXITED(stat))
459 if (WIFEXITED(stat))
460 {
460 {
461 struct timeval total;
461 struct timeval total;
462 int wall;
462 int wall;
463 wall = time(NULL) - start_time;
463 wall = time(NULL) - start_time;
464 timeradd(&rus.ru_utime, &rus.ru_stime, &total);
464 timeradd(&rus.ru_utime, &rus.ru_stime, &total);
465
465
466 box_pid = 0;
466 box_pid = 0;
467 if (WEXITSTATUS(stat))
467 if (WEXITSTATUS(stat))
468 fprintf(stderr,"Exited with error status %d.\n", WEXITSTATUS(stat));
468 fprintf(stderr,"Exited with error status %d.\n", WEXITSTATUS(stat));
469 - else if ((use_wall_clock ? wall : total.tv_sec) > timeout)
469 + else if ((use_wall_clock ?
470 + wall :
471 + (double) total.tv_sec +
472 + ((double) total.tv_usec/1000000.0)) > timeout)
470 fprintf(stderr,"Time limit exceeded.\n");
473 fprintf(stderr,"Time limit exceeded.\n");
471 else
474 else
472 // report OK and statistics
475 // report OK and statistics
473 fprintf(stderr,"OK\n");
476 fprintf(stderr,"OK\n");
474
477
475 print_running_stat((double) wall,
478 print_running_stat((double) wall,
476 (double) rus.ru_utime.tv_sec +
479 (double) rus.ru_utime.tv_sec +
477 ((double) rus.ru_utime.tv_usec/1000000.0),
480 ((double) rus.ru_utime.tv_usec/1000000.0),
478 (double) rus.ru_stime.tv_sec +
481 (double) rus.ru_stime.tv_sec +
479 ((double) rus.ru_stime.tv_usec/1000000.0),
482 ((double) rus.ru_stime.tv_usec/1000000.0),
480 max_mem_used);
483 max_mem_used);
481 /*
484 /*
482 (%.4lf sec real (%d), %d sec wall, %d syscalls, %d kb)\n",
485 (%.4lf sec real (%d), %d sec wall, %d syscalls, %d kb)\n",
483 (double) total.tv_sec + ((double)total.tv_usec / 1000000.0),
486 (double) total.tv_sec + ((double)total.tv_usec / 1000000.0),
484 (int) total.tv_usec,
487 (int) total.tv_usec,
485 wall,
488 wall,
486 syscall_count,
489 syscall_count,
487 max_mem_used);
490 max_mem_used);
488 */
491 */
489 exit(0);
492 exit(0);
490 }
493 }
491 if (WIFSIGNALED(stat))
494 if (WIFSIGNALED(stat))
492 {
495 {
493 box_pid = 0;
496 box_pid = 0;
@@ -625,49 +628,49
625 switch (c)
628 switch (c)
626 {
629 {
627 case 'a':
630 case 'a':
628 file_access = atol(optarg);
631 file_access = atol(optarg);
629 break;
632 break;
630 case 'c':
633 case 'c':
631 set_cwd = optarg;
634 set_cwd = optarg;
632 break;
635 break;
633 case 'e':
636 case 'e':
634 pass_environ = 1;
637 pass_environ = 1;
635 break;
638 break;
636 case 'f':
639 case 'f':
637 filter_syscalls++;
640 filter_syscalls++;
638 break;
641 break;
639 case 'i':
642 case 'i':
640 redir_stdin = optarg;
643 redir_stdin = optarg;
641 break;
644 break;
642 case 'm':
645 case 'm':
643 memory_limit = atol(optarg);
646 memory_limit = atol(optarg);
644 break;
647 break;
645 case 'o':
648 case 'o':
646 redir_stdout = optarg;
649 redir_stdout = optarg;
647 break;
650 break;
648 case 't':
651 case 't':
649 - timeout = atol(optarg);
652 + timeout = atof(optarg);
650 break;
653 break;
651 case 'T':
654 case 'T':
652 allow_times++;
655 allow_times++;
653 break;
656 break;
654 case 'v':
657 case 'v':
655 verbose++;
658 verbose++;
656 break;
659 break;
657 case 'w':
660 case 'w':
658 use_wall_clock = 1;
661 use_wall_clock = 1;
659 break;
662 break;
660 default:
663 default:
661 usage();
664 usage();
662 }
665 }
663 if (optind >= argc)
666 if (optind >= argc)
664 usage();
667 usage();
665
668
666 uid = geteuid();
669 uid = geteuid();
667 if (setreuid(uid, uid) < 0)
670 if (setreuid(uid, uid) < 0)
668 die("setreuid: %m");
671 die("setreuid: %m");
669 box_pid = fork();
672 box_pid = fork();
670 if (box_pid < 0)
673 if (box_pid < 0)
671 die("fork: %m");
674 die("fork: %m");
672 if (!box_pid)
675 if (!box_pid)
673 box_inside(argc-optind, argv+optind);
676 box_inside(argc-optind, argv+optind);
@@ -1,20 +1,24
1 problem do
1 problem do
2 num_tests 2
2 num_tests 2
3 full_score 20
3 full_score 20
4 time_limit_each 1
4 time_limit_each 1
5 mem_limit_each 16
5 mem_limit_each 16
6 score_each 10
6 score_each 10
7
7
8 + test 1 do
9 + time_limit 0.5
10 + end
11 +
8 run 1 do
12 run 1 do
9 tests 1
13 tests 1
10 end
14 end
11
15
12 test 2 do
16 test 2 do
13 - time_limit 2
17 + time_limit 0.6
14 end
18 end
15
19
16 run 2 do
20 run 2 do
17 tests 2
21 tests 2
18 end
22 end
19
23
20 end
24 end
@@ -27,53 +27,53
27 :comment => /^PASSED/})
27 :comment => /^PASSED/})
28 end
28 end
29
29
30
30
31 it "should produce error message when submission cannot compile" do
31 it "should produce error message when submission cannot compile" do
32 grader_should(:grade => "test1_compile_error.c",
32 grader_should(:grade => "test1_compile_error.c",
33 :on => @problem_test_normal,
33 :on => @problem_test_normal,
34 :and_report => {
34 :and_report => {
35 :score => 0,
35 :score => 0,
36 :comment => 'FAILED: compilation error',
36 :comment => 'FAILED: compilation error',
37 :compiler_message => /[Ee]rror/})
37 :compiler_message => /[Ee]rror/})
38 end
38 end
39
39
40 it "should produce timeout error when submission runs forever" do
40 it "should produce timeout error when submission runs forever" do
41 @problem_test_timeout = stub(Problem,
41 @problem_test_timeout = stub(Problem,
42 :id => 1, :name => 'test_timeout',
42 :id => 1, :name => 'test_timeout',
43 :full_score => 10)
43 :full_score => 10)
44 grader_should(:grade => "test2_timeout.c",
44 grader_should(:grade => "test2_timeout.c",
45 :on => @problem_test_timeout,
45 :on => @problem_test_timeout,
46 :and_report => {
46 :and_report => {
47 :score => 0,
47 :score => 0,
48 :comment => 'FAILED: TT'})
48 :comment => 'FAILED: TT'})
49 end
49 end
50
50
51 - it "should produce timeout error correctly when submission runs slower than expected in less than a second" do
51 + it "should produce timeout error correctly with fractional running time and fractional time limits" do
52 @problem_test_timeout = stub(Problem,
52 @problem_test_timeout = stub(Problem,
53 :id => 1, :name => 'test_timeout',
53 :id => 1, :name => 'test_timeout',
54 :full_score => 20)
54 :full_score => 20)
55 - grader_should(:grade => "test2_1-5sec.c",
55 + grader_should(:grade => "test2_05sec.c",
56 :on => @problem_test_timeout,
56 :on => @problem_test_timeout,
57 :and_report => {
57 :and_report => {
58 :score => 10,
58 :score => 10,
59 :comment => 'FAILED: TP'})
59 :comment => 'FAILED: TP'})
60 end
60 end
61
61
62 it "should produce runtime error when submission uses too much static memory" do
62 it "should produce runtime error when submission uses too much static memory" do
63 @problem_test_memory = stub(Problem,
63 @problem_test_memory = stub(Problem,
64 :id => 1, :name => 'test_memory',
64 :id => 1, :name => 'test_memory',
65 :full_score => 20)
65 :full_score => 20)
66 grader_should(:grade => "add_too_much_memory_static.c",
66 grader_should(:grade => "add_too_much_memory_static.c",
67 :on => @problem_test_memory,
67 :on => @problem_test_memory,
68 :and_report => {
68 :and_report => {
69 :score => 10,
69 :score => 10,
70 :comment => /FAILED: [^P]P/})
70 :comment => /FAILED: [^P]P/})
71 end
71 end
72
72
73 it "should not allow submission to allocate too much dynamic memory" do
73 it "should not allow submission to allocate too much dynamic memory" do
74 @problem_test_memory = stub(Problem,
74 @problem_test_memory = stub(Problem,
75 :id => 1, :name => 'test_memory',
75 :id => 1, :name => 'test_memory',
76 :full_score => 20)
76 :full_score => 20)
77 grader_should(:grade => "add_too_much_memory_dynamic.c",
77 grader_should(:grade => "add_too_much_memory_dynamic.c",
78 :on => @problem_test_memory,
78 :on => @problem_test_memory,
79 :and_report => {
79 :and_report => {
deleted file
You need to be logged in to leave comments. Login now