X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=grading%2Fuserprog%2Frun-tests;h=e2587c20a44e2f6ddf2fb8dce94d5910b1e2ccab;hb=bf4c5c753234a3d014ecfc2a2b647551ccbad0e0;hp=e7a31acb5f06190369f9329b880a4e5623282da8;hpb=68cfbad945e00d12f3ac8f0fa33664ad2caa0eee;p=pintos-anon diff --git a/grading/userprog/run-tests b/grading/userprog/run-tests index e7a31ac..e2587c2 100755 --- a/grading/userprog/run-tests +++ b/grading/userprog/run-tests @@ -37,11 +37,22 @@ sub usage { } # Default set of tests. -@TESTS = qw (create-normal create-empty create-null create-bad-ptr +@TESTS = qw (args-argc args-argv0 args-argvn args-single args-multiple + args-dbl-space + sc-bad-sp sc-bad-arg sc-boundary + halt exit + create-normal create-empty create-null create-bad-ptr create-long create-exists create-bound - args-argc args-argv0 args-argvn args-single args-multiple - args-dbl-space) - unless @TESTS > 0; + open-normal open-missing open-boundary open-empty open-null + open-bad-ptr open-twice + close-normal close-twice close-stdin close-stdout close-bad-fd + read-normal read-bad-ptr read-boundary read-zero read-stdout + read-bad-fd + write-normal write-bad-ptr write-boundary write-zero write-stdin + write-bad-fd + exec-once exec-arg exec-multiple exec-missing exec-bad-ptr + multi-recurse multi-oom multi-child-fd + ) unless @TESTS > 0; our (%args); for my $key ('args-argc', 'args-argv0', 'args-argvn', 'args-multiple') { @@ -49,6 +60,8 @@ for my $key ('args-argc', 'args-argv0', 'args-argvn', 'args-multiple') { } $args{'args-single'} = "onearg"; $args{'args-dbl-space'} = "two args"; +$args{'multi-recurse'} = "15"; +$args{'multi-oom'} = "0"; # Handle final grade mode. if ($grade) { @@ -179,6 +192,15 @@ sub extract_tarball { xsystem ("patch -fs pintos/src/lib/debug.c < $GRADES_DIR/panic.diff", LOG => "patch", DIE => "patch failed\n"); + xsystem ("patch -fs pintos/src/lib/kernel/bitmap.c " + . "< $GRADES_DIR/random.diff", + LOG => "patch", + DIE => "patch failed\n"); + + open (CONSTANTS, ">pintos/src/constants.h") + or die "constants.h: create: $!\n"; + print CONSTANTS "#define THREAD_JOIN_IMPLEMENTED 1\n"; + close CONSTANTS; } sub ext_mdyHMS { @@ -247,6 +269,7 @@ sub really_run_test { # Run. my ($timeout) = 10; + $timeout = 60 if $test eq 'multi-oom'; my ($testargs) = defined ($args{$test}) ? " $args{$test}" : ""; xsystem ("pintos " . "--os-disk=pintos/src/userprog/build/os.dsk " @@ -264,15 +287,15 @@ sub grade_test { my (@output) = snarf ("output/$test/run.out"); - if (-e "$GRADES_DIR/$test.exp") { + my ($grade_func) = "grade_$test"; + $grade_func =~ s/-/_/g; + if (-e "$GRADES_DIR/$test.exp" && !defined (&$grade_func)) { eval { verify_common (@output); compare_output ("$GRADES_DIR/$test.exp", @output); } } else { - my ($grade_func); - ($grade_func = $test) =~ s/-/_/g; - eval "grade_$grade_func (\@output)"; + eval "$grade_func (\@output)"; } if ($@) { die $@ if $@ =~ /at \S+ line \d+$/; @@ -281,234 +304,74 @@ sub grade_test { return "ok"; } -sub grade_alarm_multiple { - verify_alarm (7, @_); -} - -sub verify_alarm { - my ($iterations, @output) = @_; - - verify_common (@output); - - my (@products); - for (my ($i) = 0; $i < $iterations; $i++) { - for (my ($t) = 0; $t < 5; $t++) { - push (@products, ($i + 1) * ($t + 1) * 10); - } - } - @products = sort {$a <=> $b} @products; - - local ($_); - foreach (@output) { - die $_ if /Out of order/; - - my ($p) = /product=(\d+)$/; - next if !defined $p; - - my ($q) = shift (@products); - die "Too many wakeups.\n" if !defined $q; - die "Out of order wakeups ($p vs. $q).\n" if $p != $q; # FIXME - } - die scalar (@products) . " fewer wakeups than expected.\n" - if @products != 0; -} - -sub grade_alarm_zero { - my (@output) = @_; - verify_common (@output); - die "Crashed in timer_sleep()\n" if !grep (/^Success\.$/, @output); -} - -sub grade_alarm_negative { +sub grade_write_normal { my (@output) = @_; verify_common (@output); - die "Crashed in timer_sleep()\n" if !grep (/^Success\.$/, @output); -} - -sub grade_join_invalid { - my (@output) = @_; - verify_common (@output); - grep (/Testing invalid join/, @output) or die "Test didn't start\n"; - grep (/Invalid join test done/, @output) or die "Test didn't complete\n"; -} - -sub grade_join_no { - my (@output) = @_; - verify_common (@output); - grep (/Testing no join/, @output) or die "Test didn't start\n"; - grep (/No join test done/, @output) or die "Test didn't complete\n"; -} - -sub grade_join_multiple { - my (@output) = @_; - - verify_common (@output); - my (@t); - $t[4] = $t[5] = $t[6] = -1; - local ($_); - foreach (@output) { - my ($idx) = /^Thread (\d+)/ or next; - my ($iter) = /iteration (\d+)$/; - $iter = 5 if /done!$/; - die "Malformed output\n" if !defined $iter; - if ($idx == 6) { - die "Thread 6 started before either other thread finished\n" - if $t[4] < 5 && $t[5] < 5; - die "Thread 6 started before thread 4 finished\n" - if $t[4] < 5; - die "Thread 6 started before thread 5 finished\n" - if $t[5] < 5; + compare_output ("$GRADES_DIR/write-normal.exp", @output); + my ($test_txt) = "output/$test/test.txt"; + get_file ("test.txt", $test_txt) if ! -e $test_txt; + + my (@actual) = snarf ($test_txt); + my (@expected) = snarf ("$GRADES_DIR/sample.txt"); + + my ($eq); + if ($#actual == $#expected) { + $eq = 1; + for my $i (0...$#actual) { + $eq = 0 if $actual[$i] ne $expected[$i]; } - die "Thread $idx out of order output\n" if $t[$idx] != $iter - 1; - $t[$idx] = $iter; + } else { + $eq = 0; } + if (!$eq) { + my ($details); + $details = "Expected file content:\n"; + $details .= join ('', map (" $_\n", @expected)); + $details .= "Actual file content:\n"; + $details .= join ('', map (" $_\n", @actual)); + $extra{$test} = $details; - my ($err) = ""; - for my $idx (4, 5, 6) { - if ($t[$idx] == -1) { - $err .= "Thread $idx did not run at all\n"; - } elsif ($t[$idx] != 5) { - $err .= "Thread $idx only completed $t[$idx] iterations\n"; - } + die "File written didn't have expected content.\n"; } - die $err if $err ne ''; } -sub grade_priority_fifo { +sub grade_multi_oom { my (@output) = @_; - verify_common (@output); - my ($thread_cnt) = 10; - my ($iter_cnt) = 5; - my (@order); - my (@t) = (-1) x $thread_cnt; - local ($_); - foreach (@output) { - my ($idx) = /^Thread (\d+)/ or next; - my ($iter) = /iteration (\d+)$/; - $iter = $iter_cnt if /done!$/; - die "Malformed output\n" if !defined $iter; - if (@order < $thread_cnt) { - push (@order, $idx); - die "Thread $idx repeated within first $thread_cnt iterations: " - . join (' ', @order) . ".\n" - if grep ($_ == $idx, @order) != 1; - } else { - die "Thread $idx ran when $order[0] should have.\n" - if $idx != $order[0]; - push (@order, shift @order); - } - die "Thread $idx out of order output.\n" if $t[$idx] != $iter - 1; - $t[$idx] = $iter; - } - my ($err) = ""; - for my $idx (0..$#t) { - if ($t[$idx] == -1) { - $err .= "Thread $idx did not run at all.\n"; - } elsif ($t[$idx] != $iter_cnt) { - $err .= "Thread $idx only completed $t[$idx] iterations.\n"; - } + @output = fix_exit_codes (get_core_output (@output)); + my ($n) = 0; + while (my ($m) = $output[0] =~ /^\(multi-oom\) begin (\d+)$/) { + die "Child process $m started out of order.\n" if $m != $n; + $n = $m + 1; + shift @output; } - die $err if $err ne ''; -} - -sub grade_mlfqs_on { - my (@output) = @_; - verify_common (@output); - our (@mlfqs_on_stats) = mlfqs_stats (@output); -} - -sub grade_mlfqs_off { - my (@output) = @_; - verify_common (@output); - our (@mlfqs_off_stats) = mlfqs_stats (@output); -} - -sub grade_mlfqs_speedup { - our (@mlfqs_off_stats); - our (@mlfqs_on_stats); - eval { - check_mlfqs (); - my ($off_ticks) = $mlfqs_off_stats[1]; - my ($on_ticks) = $mlfqs_on_stats[1]; - die "$off_ticks ticks without MLFQS, $on_ticks with MLFQS\n" - if $on_ticks >= $off_ticks; - die "ok\n"; - }; - chomp $@; - $result{'mlfqs-speedup'} = $@; -} - -sub grade_mlfqs_priority { - our (@mlfqs_off_stats); - our (@mlfqs_on_stats); - eval { - check_mlfqs () if !defined (@mlfqs_on_stats); - for my $cat qw (CPU IO MIX) { - die "Priority changed away from PRI_DEFAULT (29) without MLFQS\n" - if $mlfqs_off_stats[0]{$cat}{MIN} != 29 - || $mlfqs_off_stats[0]{$cat}{MAX} != 29; - die "Minimum priority never changed from PRI_DEFAULT (29) " - . "with MLFQS\n" - if $mlfqs_on_stats[0]{$cat}{MIN} == 29; - die "Maximum priority never changed from PRI_DEFAULT (29) " - . "with MLFQS\n" - if $mlfqs_on_stats[0]{$cat}{MAX} == 29; - } - die "ok\n"; - }; - chomp $@; - $result{'mlfqs-priority'} = $@; + die "Only $n child processes started.\n" if $n < 15; + while (--$n >= 0) { + die "Output ended unexpectedly before process $n finished.\n" + if @output < 2; + die "Child process $n ended out of order.\n" + if $output[0] !~ /^\(multi-oom\) end $n$/; + shift @output; + + die "Child process $n didn't print proper exit message.\n" + if $output[0] !~ /^multi-oom: exit\($n\)$/; + shift @output; + } + die "Spurious output at end: '$output[0]'.\n" if @output; } -sub check_mlfqs { - our (@mlfqs_off_stats); - our (@mlfqs_on_stats); - die "p1-4 didn't finish with MLFQS on or off\n" - if !defined (@mlfqs_off_stats) && !defined (@mlfqs_on_stats); - die "p1-4 didn't finish with MLFQS on\n" - if !defined (@mlfqs_on_stats); - die "p1-4 didn't finish with MLFQS off\n" - if !defined (@mlfqs_off_stats); +sub get_file { + my ($guest_fn, $host_fn) = @_; + xsystem ("pintos " + . "--os-disk=pintos/src/userprog/build/os.dsk " + . "--fs-disk=output/$test/fs.dsk " + . "-v get $guest_fn $host_fn", + LOG => "$test/get-$guest_fn", + TIMEOUT => 10) + or die "get $guest_fn failed\n"; } -sub mlfqs_stats { - my (@output) = @_; - my (%stats) = (CPU => {}, IO => {}, MIX => {}); - my (%map) = ("CPU intensive" => 'CPU', - "IO intensive" => 'IO', - "Alternating IO/CPU" => 'MIX'); - my (%rmap) = reverse %map; - my ($ticks); - local ($_); - foreach (@output) { - $ticks = $1 if /Timer: (\d+) ticks/; - my ($thread, $pri) = /^([A-Za-z\/ ]+): (\d+)$/ or next; - my ($t) = $map{$thread} or next; - - my ($s) = $stats{$t}; - $$s{N}++; - $$s{SUM} += $pri; - $$s{SUM2} += $pri * $pri; - $$s{MIN} = $pri if !defined ($$s{MIN}) || $pri < $$s{MIN}; - $$s{MAX} = $pri if !defined ($$s{MAX}) || $pri > $$s{MAX}; - } - - my (%expect_n) = (CPU => 5000, IO => 1000, MIX => 12000); - for my $cat (values (%map)) { - my ($s) = $stats{$cat}; - die "$rmap{$cat} printed $$s{N} times, not $expect_n{$cat}\n" - if $$s{N} != $expect_n{$cat}; - die "$rmap{$cat} priority dropped to $$s{MIN}, below PRI_MIN (0)\n" - if $$s{MIN} < 0; - die "$rmap{$cat} priority rose to $$s{MAX}, above PRI_MAX (59)\n" - if $$s{MAX} > 59; - $$s{MEAN} = $$s{SUM} / $$s{N}; - } - - return (\%stats, $ticks); -} sub verify_common { my (@output) = @_; @@ -530,7 +393,7 @@ sub verify_common { } else { $A2L = "i386-elf-addr2line"; } - open (A2L, "$A2L -fe output/$test/kernel.o @addrs|"); + open (A2L, "$A2L -fe pintos/src/userprog/build/kernel.o @addrs|"); for (;;) { my ($function, $line); last unless defined ($function = ); @@ -579,20 +442,26 @@ sub get_core_output { return @output[$first ... $last]; } -sub compare_output { - my ($exp, @actual) = @_; - @actual = get_core_output (map ("$_\n", @actual)); +sub fix_exit_codes { + my (@output) = @_; # Fix up lines that look like exit codes. - for my $i (0...$#actual) { + for my $i (0...$#output) { if (my ($process, $code) - = $actual[$i] =~ /^([-a-zA-Z0-9 ]+):.*[ \(](-?\d+)\b\)?$/) { + = $output[$i] =~ /^([-a-zA-Z0-9 ]+):.*[ \(](-?\d+)\b\)?$/) { $process = substr ($process, 0, 15); $process =~ s/\s.*//; - $actual[$i] = "$process: exit($code)\n"; + $output[$i] = "$process: exit($code)\n"; } } + return @output; +} + +sub compare_output { + my ($exp, @actual) = @_; + @actual = fix_exit_codes (get_core_output (map ("$_\n", @actual))); + my ($details) = ""; $details .= "$test actual output:\n"; $details .= join ('', map (" $_", @actual)); @@ -623,7 +492,7 @@ sub compare_output { # They differ. Output a diff. my (@diff) = ""; my ($d) = Algorithm::Diff->new (\@expected, \@actual); - my ($all_additions) = 1; + my ($not_fuzzy_match) = 0; while ($d->Next ()) { my ($ef, $el, $af, $al) = $d->Get (qw (min1 max1 min2 max2)); if ($d->Same ()) { @@ -631,11 +500,13 @@ sub compare_output { } else { push (@diff, map ("- $_", $d->Items (1))) if $d->Items (1); push (@diff, map ("+ $_", $d->Items (2))) if $d->Items (2); - $all_additions = 0 if $d->Items (1); + if ($d->Items (1) + || grep (/\($test\)|exit\(-?\d+\)/, $d->Items (2))) { + $not_fuzzy_match = 1; + } } } - - $fuzzy_match = 1 if $all_additions; + $fuzzy_match = 1 if !$not_fuzzy_match; $details .= "Differences in `diff -u' format:\n"; $details .= join ('', @diff);