Description:
[grader] box.cc now reports running status when die git-svn-id: http://theory.cpe.ku.ac.th/grader/judge/trunk/scripts@172 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

r46:31f3935d33aa - - 2 files changed: 45 inserted, 31 deleted

@@ -33,94 +33,112
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
47
48 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ > 0
48 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ > 0
49 /* glibc 2.1 or newer -> has lseek64 */
49 /* glibc 2.1 or newer -> has lseek64 */
50 #define long_seek(f,o,w) lseek64(f,o,w)
50 #define long_seek(f,o,w) lseek64(f,o,w)
51 #else
51 #else
52 /* Touching clandestine places in glibc */
52 /* Touching clandestine places in glibc */
53 extern loff_t llseek(int fd, loff_t pos, int whence);
53 extern loff_t llseek(int fd, loff_t pos, int whence);
54 #define long_seek(f,o,w) llseek(f,o,w)
54 #define long_seek(f,o,w) llseek(f,o,w)
55 #endif
55 #endif
56
56
57 + int max_mem_used = 0;
58 +
59 + void print_running_stat(double wall_time,
60 + double user_time,
61 + double system_time,
62 + int mem_usage)
63 + {
64 + fprintf(stderr,"%.4lfr%.4lfu%.4lfs%dm\n",
65 + wall_time, user_time, system_time, mem_usage);
66 + }
67 +
57 static void NONRET
68 static void NONRET
58 box_exit(void)
69 box_exit(void)
59 {
70 {
60 - if (box_pid > 0)
71 + if (box_pid > 0) {
61 - {
62 if (is_ptraced)
72 if (is_ptraced)
63 ptrace(PTRACE_KILL, box_pid);
73 ptrace(PTRACE_KILL, box_pid);
64 kill(-box_pid, SIGKILL);
74 kill(-box_pid, SIGKILL);
65 kill(box_pid, SIGKILL);
75 kill(box_pid, SIGKILL);
66 }
76 }
67 - exit(1);
77 +
68 - }
78 + struct timeval total;
79 + int wall;
80 + struct rusage rus;
81 + int stat;
82 + pid_t p;
69
83
70 - static void
84 + // wait so that we can get information
71 - box_kill(void)
85 + p = wait4(box_pid, &stat, WUNTRACED, &rus);
72 - {
86 + if (p < 0) {
73 - if (box_pid > 0)
87 + fprintf(stderr,"wait4: error\n");
74 - {
88 + print_running_stat(0,0,0,max_mem_used);
75 - if (is_ptraced)
89 + } else if (p != box_pid) {
76 - ptrace(PTRACE_KILL, box_pid);
90 + fprintf(stderr,"wait4: unknown pid %d exited!\n", p);
77 - kill(-box_pid, SIGKILL);
91 + print_running_stat(0,0,0,max_mem_used);
78 - kill(box_pid, SIGKILL);
92 + } else {
93 + if (!WIFEXITED(stat))
94 + fprintf(stderr,"wait4: unknown status\n");
95 + struct timeval total;
96 + int wall;
97 + wall = time(NULL) - start_time;
98 + timeradd(&rus.ru_utime, &rus.ru_stime, &total);
99 +
100 + print_running_stat((double)wall,
101 + (double) rus.ru_utime.tv_sec +
102 + ((double) rus.ru_utime.tv_usec/1000000.0),
103 + (double) rus.ru_stime.tv_sec +
104 + ((double) rus.ru_stime.tv_usec/1000000.0),
105 + max_mem_used);
79 }
106 }
107 + exit(1);
80 }
108 }
81
109
82 static void NONRET __attribute__((format(printf,1,2)))
110 static void NONRET __attribute__((format(printf,1,2)))
83 die(char *msg, ...)
111 die(char *msg, ...)
84 {
112 {
85 va_list args;
113 va_list args;
86 va_start(args, msg);
114 va_start(args, msg);
87 vfprintf(stderr, msg, args);
115 vfprintf(stderr, msg, args);
88 fputc('\n', stderr);
116 fputc('\n', stderr);
89 box_exit();
117 box_exit();
90 }
118 }
91
119
92 static void __attribute__((format(printf,1,2)))
120 static void __attribute__((format(printf,1,2)))
93 - die_report(char *msg, ...)
94 - {
95 - va_list args;
96 - va_start(args, msg);
97 - vfprintf(stderr, msg, args);
98 - fputc('\n', stderr);
99 - box_kill();
100 - }
101 -
102 - static void __attribute__((format(printf,1,2)))
103 log(char *msg, ...)
121 log(char *msg, ...)
104 {
122 {
105 va_list args;
123 va_list args;
106 va_start(args, msg);
124 va_start(args, msg);
107 if (verbose)
125 if (verbose)
108 {
126 {
109 vfprintf(stderr, msg, args);
127 vfprintf(stderr, msg, args);
110 fflush(stderr);
128 fflush(stderr);
111 }
129 }
112 va_end(args);
130 va_end(args);
113 }
131 }
114
132
115 static void
133 static void
116 valid_filename(unsigned long addr)
134 valid_filename(unsigned long addr)
117 {
135 {
118 char namebuf[4096], *p, *end;
136 char namebuf[4096], *p, *end;
119 static int mem_fd;
137 static int mem_fd;
120
138
121 if (!file_access)
139 if (!file_access)
122 die("File access forbidden.");
140 die("File access forbidden.");
123 if (file_access >= 9)
141 if (file_access >= 9)
124 return;
142 return;
125
143
126 if (!mem_fd)
144 if (!mem_fd)
@@ -328,54 +346,52
328 if ((c = read(proc_status_fd, buf, sizeof(buf)-1)) < 0)
346 if ((c = read(proc_status_fd, buf, sizeof(buf)-1)) < 0)
329 die("read on /proc/$pid/stat: %m");
347 die("read on /proc/$pid/stat: %m");
330 if (c >= (int) sizeof(buf) - 1)
348 if (c >= (int) sizeof(buf) - 1)
331 die("/proc/$pid/stat too long");
349 die("/proc/$pid/stat too long");
332 buf[c] = 0;
350 buf[c] = 0;
333 x = buf;
351 x = buf;
334 while (*x && *x != ' ')
352 while (*x && *x != ' ')
335 x++;
353 x++;
336 while (*x == ' ')
354 while (*x == ' ')
337 x++;
355 x++;
338 if (*x++ != '(')
356 if (*x++ != '(')
339 die("proc syntax error 1");
357 die("proc syntax error 1");
340 while (*x && (*x != ')' || x[1] != ' '))
358 while (*x && (*x != ')' || x[1] != ' '))
341 x++;
359 x++;
342 while (*x == ')' || *x == ' ')
360 while (*x == ')' || *x == ' ')
343 x++;
361 x++;
344 if (sscanf(x, "%*c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d %d", &utime, &stime) != 2)
362 if (sscanf(x, "%*c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d %d", &utime, &stime) != 2)
345 die("proc syntax error 2");
363 die("proc syntax error 2");
346 //printf("%s - %d\n",x,ticks_per_sec);
364 //printf("%s - %d\n",x,ticks_per_sec);
347 sec = (utime + stime + ticks_per_sec-1)/ticks_per_sec;
365 sec = (utime + stime + ticks_per_sec-1)/ticks_per_sec;
348 }
366 }
349 if (verbose > 1)
367 if (verbose > 1)
350 fprintf(stderr, "[timecheck: %d seconds]\n", sec);
368 fprintf(stderr, "[timecheck: %d seconds]\n", sec);
351 if (sec > timeout) {
369 if (sec > timeout) {
352 - die_report("Time limit exceeded.");
370 + die("Time limit exceeded.");
353 }
371 }
354 }
372 }
355
373
356 - int max_mem_used = 0;
357 -
358 static void
374 static void
359 check_memory_usage()
375 check_memory_usage()
360 {
376 {
361 char proc_fname[100];
377 char proc_fname[100];
362 sprintf(proc_fname,"/proc/%d/statm",box_pid);
378 sprintf(proc_fname,"/proc/%d/statm",box_pid);
363 //printf("proc fname: %s\n",proc_fname);
379 //printf("proc fname: %s\n",proc_fname);
364 FILE *fp = fopen(proc_fname,"r");
380 FILE *fp = fopen(proc_fname,"r");
365 if(fp!=NULL) {
381 if(fp!=NULL) {
366 char line[1000];
382 char line[1000];
367 fgets(line,999,fp);
383 fgets(line,999,fp);
368 //printf("%s\n",line);
384 //printf("%s\n",line);
369 int m;
385 int m;
370
386
371 if(sscanf(line,"%d",&m)==1)
387 if(sscanf(line,"%d",&m)==1)
372 if(m>max_mem_used)
388 if(m>max_mem_used)
373 max_mem_used = m;
389 max_mem_used = m;
374
390
375 fclose(fp);
391 fclose(fp);
376 }
392 }
377 }
393 }
378
394
379 static void
395 static void
380 boxkeeper(void)
396 boxkeeper(void)
381 {
397 {
@@ -431,76 +447,74
431 if (p < 0)
447 if (p < 0)
432 {
448 {
433 if (errno == EINTR)
449 if (errno == EINTR)
434 continue;
450 continue;
435 die("wait4: %m");
451 die("wait4: %m");
436 }
452 }
437 if (p != box_pid)
453 if (p != box_pid)
438 die("wait4: unknown pid %d exited!", p);
454 die("wait4: unknown pid %d exited!", p);
439 if (WIFEXITED(stat))
455 if (WIFEXITED(stat))
440 {
456 {
441 struct timeval total;
457 struct timeval total;
442 int wall;
458 int wall;
443 wall = time(NULL) - start_time;
459 wall = time(NULL) - start_time;
444 timeradd(&rus.ru_utime, &rus.ru_stime, &total);
460 timeradd(&rus.ru_utime, &rus.ru_stime, &total);
445
461
446 box_pid = 0;
462 box_pid = 0;
447 if (WEXITSTATUS(stat))
463 if (WEXITSTATUS(stat))
448 fprintf(stderr,"Exited with error status %d.\n", WEXITSTATUS(stat));
464 fprintf(stderr,"Exited with error status %d.\n", WEXITSTATUS(stat));
449 else if ((use_wall_clock ? wall : total.tv_sec) > timeout)
465 else if ((use_wall_clock ? wall : total.tv_sec) > timeout)
450 fprintf(stderr,"Time limit exceeded.\n");
466 fprintf(stderr,"Time limit exceeded.\n");
451 else
467 else
452 // report OK and statistics
468 // report OK and statistics
453 fprintf(stderr,"OK\n");
469 fprintf(stderr,"OK\n");
454
470
455 - fprintf(stderr,"%dr%.4lfu%.4lfs%dm\n",
471 + print_running_stat((double) wall,
456 - wall,
457 (double) rus.ru_utime.tv_sec +
472 (double) rus.ru_utime.tv_sec +
458 ((double) rus.ru_utime.tv_usec/1000000.0),
473 ((double) rus.ru_utime.tv_usec/1000000.0),
459 (double) rus.ru_stime.tv_sec +
474 (double) rus.ru_stime.tv_sec +
460 ((double) rus.ru_stime.tv_usec/1000000.0),
475 ((double) rus.ru_stime.tv_usec/1000000.0),
461 max_mem_used);
476 max_mem_used);
462 /*
477 /*
463 (%.4lf sec real (%d), %d sec wall, %d syscalls, %d kb)\n",
478 (%.4lf sec real (%d), %d sec wall, %d syscalls, %d kb)\n",
464 (double) total.tv_sec + ((double)total.tv_usec / 1000000.0),
479 (double) total.tv_sec + ((double)total.tv_usec / 1000000.0),
465 (int) total.tv_usec,
480 (int) total.tv_usec,
466 wall,
481 wall,
467 syscall_count,
482 syscall_count,
468 max_mem_used);
483 max_mem_used);
469 */
484 */
470 exit(0);
485 exit(0);
471 }
486 }
472 if (WIFSIGNALED(stat))
487 if (WIFSIGNALED(stat))
473 {
488 {
474 box_pid = 0;
489 box_pid = 0;
475 fprintf(stderr,"Caught fatal signal %d.\n", WTERMSIG(stat));
490 fprintf(stderr,"Caught fatal signal %d.\n", WTERMSIG(stat));
476
491
477 struct timeval total;
492 struct timeval total;
478 int wall;
493 int wall;
479 wall = time(NULL) - start_time;
494 wall = time(NULL) - start_time;
480 timeradd(&rus.ru_utime, &rus.ru_stime, &total);
495 timeradd(&rus.ru_utime, &rus.ru_stime, &total);
481 - fprintf(stderr,"%dr%.4lfu%.4lfs%dm\n",
496 + print_running_stat((double) wall,
482 - wall,
483 (double) rus.ru_utime.tv_sec +
497 (double) rus.ru_utime.tv_sec +
484 ((double) rus.ru_utime.tv_usec/1000000.0),
498 ((double) rus.ru_utime.tv_usec/1000000.0),
485 (double) rus.ru_stime.tv_sec +
499 (double) rus.ru_stime.tv_sec +
486 ((double) rus.ru_stime.tv_usec/1000000.0),
500 ((double) rus.ru_stime.tv_usec/1000000.0),
487 max_mem_used);
501 max_mem_used);
488 exit(0);
502 exit(0);
489 }
503 }
490 if (WIFSTOPPED(stat))
504 if (WIFSTOPPED(stat))
491 {
505 {
492 int sig = WSTOPSIG(stat);
506 int sig = WSTOPSIG(stat);
493 if (sig == SIGTRAP)
507 if (sig == SIGTRAP)
494 {
508 {
495 struct user u;
509 struct user u;
496 static int stop_count = -1;
510 static int stop_count = -1;
497 if (ptrace(PTRACE_GETREGS, box_pid, NULL, &u) < 0)
511 if (ptrace(PTRACE_GETREGS, box_pid, NULL, &u) < 0)
498 die("ptrace(PTRACE_GETREGS): %m");
512 die("ptrace(PTRACE_GETREGS): %m");
499 stop_count++;
513 stop_count++;
500 if (!stop_count) /* Traceme request */
514 if (!stop_count) /* Traceme request */
501 log(">> Traceme request caught\n");
515 log(">> Traceme request caught\n");
502 else if (stop_count & 1) /* Syscall entry */
516 else if (stop_count & 1) /* Syscall entry */
503 {
517 {
504 log(">> Syscall %3ld (%08lx,%08lx,%08lx) ", u.regs.orig_eax, u.regs.ebx, u.regs.ecx, u.regs.edx);
518 log(">> Syscall %3ld (%08lx,%08lx,%08lx) ", u.regs.orig_eax, u.regs.ebx, u.regs.ecx, u.regs.edx);
505 syscall_count++;
519 syscall_count++;
506 if (!valid_syscall(&u))
520 if (!valid_syscall(&u))
@@ -220,49 +220,49
220 it "should compile test request with error and report compilation error" do
220 it "should compile test request with error and report compilation error" do
221 problem = stub(Problem,
221 problem = stub(Problem,
222 :id => 1, :name => 'test_normal')
222 :id => 1, :name => 'test_normal')
223 grader_should(:grade => 'test1_compile_error.c',
223 grader_should(:grade => 'test1_compile_error.c',
224 :on => problem,
224 :on => problem,
225 :with => 'in1.txt',
225 :with => 'in1.txt',
226 :and_report => {
226 :and_report => {
227 :graded_at= => nil,
227 :graded_at= => nil,
228 :compiler_message= => /.+/,
228 :compiler_message= => /.+/,
229 :grader_comment= => /[Cc]ompil.*error/,
229 :grader_comment= => /[Cc]ompil.*error/,
230 :running_stat= => '',
230 :running_stat= => '',
231 :save => nil})
231 :save => nil})
232 end
232 end
233
233
234 it "should report exit status" do
234 it "should report exit status" do
235 problem = stub(Problem,
235 problem = stub(Problem,
236 :id => 1, :name => 'test_normal')
236 :id => 1, :name => 'test_normal')
237 grader_should(:grade => 'add_nonzero_exit_status.c',
237 grader_should(:grade => 'add_nonzero_exit_status.c',
238 :on => problem,
238 :on => problem,
239 :with => 'in1.txt',
239 :with => 'in1.txt',
240 :and_report => {
240 :and_report => {
241 :graded_at= => nil,
241 :graded_at= => nil,
242 :compiler_message= => '',
242 :compiler_message= => '',
243 :grader_comment= => '',
243 :grader_comment= => '',
244 - :running_stat= => /[Ee]xit.*status.*10.*0\.0 sec/m,
244 + :running_stat= => /[Ee]xit.*status.*10.*0\.0\d* sec/m,
245 :output_file_name= => lambda { |fname|
245 :output_file_name= => lambda { |fname|
246 File.exists?(fname).should be_true
246 File.exists?(fname).should be_true
247 },
247 },
248 :running_time= => nil,
248 :running_time= => nil,
249 :exit_status= => /10/,
249 :exit_status= => /10/,
250 :memory_usage= => nil,
250 :memory_usage= => nil,
251 :save => nil})
251 :save => nil})
252 end
252 end
253
253
254 it "should produce running statistics for normal submission" do
254 it "should produce running statistics for normal submission" do
255 problem = stub(Problem,
255 problem = stub(Problem,
256 :id => 1, :name => 'test_normal')
256 :id => 1, :name => 'test_normal')
257 grader_should(:grade => 'test_run_stat.c',
257 grader_should(:grade => 'test_run_stat.c',
258 :on => problem,
258 :on => problem,
259 :with => 'in1.txt',
259 :with => 'in1.txt',
260 :and_report => {
260 :and_report => {
261 :graded_at= => nil,
261 :graded_at= => nil,
262 :compiler_message= => '',
262 :compiler_message= => '',
263 :grader_comment= => '',
263 :grader_comment= => '',
264 :running_stat= => nil,
264 :running_stat= => nil,
265 :output_file_name= => lambda { |fname|
265 :output_file_name= => lambda { |fname|
266 File.exists?(fname).should be_true
266 File.exists?(fname).should be_true
267 },
267 },
268 :running_time= => lambda { |t|
268 :running_time= => lambda { |t|
You need to be logged in to leave comments. Login now