X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=grading%2Flib%2FPintos%2FGrading.pm;h=30ac7101493b473bf96a316f0268e986f64581fb;hb=2969f4df6a95b37e05ad6aa562ae82206b646eb0;hp=3411b637dc7ad69a8096afe25755b672bcf56d0c;hpb=aa611970d5cbcfd5b0170c03effd74c2cab05708;p=pintos-anon diff --git a/grading/lib/Pintos/Grading.pm b/grading/lib/Pintos/Grading.pm index 3411b63..30ac710 100644 --- a/grading/lib/Pintos/Grading.pm +++ b/grading/lib/Pintos/Grading.pm @@ -13,26 +13,38 @@ our $action; our $hw; use POSIX; -use Getopt::Long; +use Getopt::Long qw(:config no_ignore_case); use Algorithm::Diff; +# We execute lots of subprocesses. +# Without this, our stdout output can get flushed multiple times, +# which is harmless but looks bizarre. +$| = 1; + sub parse_cmd_line { + my ($do_regex, $no_regex); GetOptions ("v|verbose+" => \$verbose, "h|help" => sub { usage (0) }, - "T|tests=s" => \@TESTS, + "d|do-tests=s" => \$do_regex, + "n|no-tests=s" => \$no_regex, "c|clean" => sub { set_action ('clean'); }, "x|extract" => sub { set_action ('extract'); }, "b|build" => sub { set_action ('build'); }, "t|test" => sub { set_action ('test'); }, "a|assemble" => sub { set_action ('assemble'); }) or die "Malformed command line; use --help for help.\n"; - die "Non-option argument not supported; use --help for help.\n" + die "Non-option arguments not supported; use --help for help.\n" if @ARGV > 0; @TESTS = split(/,/, join (',', @TESTS)) if defined @TESTS; if (!defined $action) { $action = -e 'review.txt' ? 'assemble' : 'test'; } + + my (@default_tests) = @_; + @TESTS = @default_tests; + @TESTS = grep (/$do_regex/, @TESTS) if defined $do_regex; + @TESTS = grep (!/$no_regex/, @TESTS) if defined $no_regex; } sub set_action { @@ -70,7 +82,8 @@ Workflow: Options: -c, --clean Delete test results and temporary files, then exit. - -T, --tests=TESTS Run only the specified comma-separated tests. + -d, --do-tests=RE Run only tests that match the given regular expression. + -n, --no-tests=RE Do not run tests that match the given regular expression. -x, --extract Stop after step 1. -b, --build Stop after step 2. -t, --test Stop after step 3 (default if "review.txt" not present). @@ -87,11 +100,12 @@ EOF # applies any patches providing in the grading directory, # and installs a default pintos/src/constants.h sub extract_sources { - # Nothing to do if we already have a source tree. - return if -d "pintos"; - + # Make sure the output dir exists. -d ("output") || mkdir ("output") or die "output: mkdir: $!\n"; + # Nothing else to do if we already have a source tree. + return if -d "pintos"; + my ($tarball) = choose_tarball (); # Extract sources. @@ -185,7 +199,7 @@ sub run_and_grade_tests { if $grade eq 'ok' && defined $details{$test}; print "$msg\n"; - $result{$test} = $result; + $result{$test} = $grade; } } @@ -302,7 +316,13 @@ sub xsystem { open (STDOUT, ">output/$log.out"); open (STDERR, ">output/$log.err"); } - exec ($command); + chdir $options{CHDIR} or die "$options{CHDIR}: chdir: $!\n" + if defined ($options{CHDIR}); + if (!defined ($options{EXEC})) { + exec ($command); + } else { + exec (@{$options{EXEC}}); + } exit (-1); } waitpid ($pid, 0); @@ -331,12 +351,9 @@ sub xsystem { print "Child terminated with signal $signal\n"; } - my ($exp_status) = !defined ($options{EXPECT}) ? 0 : $options{EXPECT}; - $result = WIFEXITED ($status) && WEXITSTATUS ($status) == $exp_status - ? "ok" : "error"; + $result = $status == 0 ? "ok" : "error"; } - if ($result eq 'error' && defined $options{DIE}) { my ($msg) = $options{DIE}; if (defined ($log)) { @@ -388,10 +405,15 @@ sub get_test_result { sub run_pintos { my ($cmd_line, %args) = @_; - $args{EXPECT} = 1 unless defined $args{EXPECT}; - my ($retval) = xsystem ($cmd_line, %args); + unshift (@$cmd_line, 'pintos'); + my ($retval) = xsystem (join (' ', @$cmd_line), %args, EXEC => $cmd_line); return 'ok' if $retval eq 'ok'; - return "Timed out after $args{TIMEOUT} seconds" if $retval eq 'timeout'; + if ($retval eq 'timeout') { + my ($msg) = "Timed out after $args{TIMEOUT} seconds"; + my ($load_avg) = `uptime` =~ /(load average:.*)$/i; + $msg .= " - $load_avg" if defined $load_avg; + return $msg; + } return 'Error running Bochs' if $retval eq 'error'; die; } @@ -399,7 +421,9 @@ sub run_pintos { # Grade the test. sub grade_test { # Read test output. - my (@output) = snarf ("output/$test/run.out"); + my ($outfile) = "output/$test/run.out"; + die "$outfile: missing test output file (make failed?)" if ! -e $outfile; + my (@output) = snarf ($outfile); # If there's a function "grade_$test", use it to evaluate the output. # If there's a file "$GRADES_DIR/$test.exp", compare its contents @@ -539,7 +563,7 @@ sub look_for_panic { } my ($kernel_o); if ($hw eq 'threads') { - $kernel_o = "pintos/src/filesys/build/kernel.o"; + $kernel_o = "output/$test/kernel.o"; } else { $kernel_o = "pintos/src/$hw/build/kernel.o"; } @@ -816,5 +840,12 @@ sub file_contains { close (FILE); return $equal; } + +sub success { + for my $test (@TESTS) { + return 1 if !defined ($result{$test}) || $result{$test} ne 'ok'; + } + return 0; +} 1;