- 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'} = $@;
-}
-
-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 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);
-}
-\f
-sub verify_common {
- my (@output) = @_;
-
- my (@assertion) = grep (/PANIC/, @output);
- if (@assertion != 0) {
- my ($details) = "Kernel panic:\n $assertion[0]\n";
-
- my (@stack_line) = grep (/Call stack:/, @output);
- if (@stack_line != 0) {
- $details .= " $stack_line[0]\n\n";
- $details .= "Translation of backtrace:\n";
- my (@addrs) = $stack_line[0] =~ /Call stack:((?: 0x[0-9a-f]+)+)/;
-
- my ($A2L);
- if (`uname -m`
- =~ /i.86|pentium.*|[pk][56]|nexgen|viac3|6x86|athlon.*/) {
- $A2L = "addr2line";
- } else {
- $A2L = "i386-elf-addr2line";
- }
- open (A2L, "$A2L -fe output/$test/kernel.o @addrs|");
- for (;;) {
- my ($function, $line);
- last unless defined ($function = <A2L>);
- $line = <A2L>;
- chomp $function;
- chomp $line;
- $details .= " $function ($line)\n";
- }
- }
- $extra{$test} = $details;
- die "Kernel panic. Details at end of file.\n"
- }
-
- die "No output at all\n" if @output == 0;
- die "Didn't start up properly: no \"Pintos booting\" startup message\n"
- if !grep (/Pintos booting with.*kB RAM\.\.\./, @output);
- die "Didn't start up properly: no \"Boot complete\" startup message\n"
- if !grep (/Boot complete/, @output);
- die "Didn't shut down properly: no \"Timer: # ticks\" shutdown message\n"
- if !grep (/Timer: \d+ ticks/, @output);
- die "Didn't shut down properly: no \"Powering off\" shutdown message\n"
- if !grep (/Powering off/, @output);
-}
-
-sub eq_lines {
- my ($actual, $expected) = @_;
- return $actual eq $expected;
-}
-
-sub compare_output {
- my ($exp, @actual) = @_;
- @actual = map ("$_\n", @actual);
-
- # Trim header and trailer from @actual.
- our ($test);
- my ($first);
- for ($first = 0; $first <= $#actual; $first++) {
- $first++, last if $actual[$first] =~ /^Executing '$test':$/;
- }
-
- my ($last);
- for ($last = $#actual; $last >= 0; $last--) {
- $last--, last if $actual[$last] =~ /^Timer: \d+ ticks$/;
- }
-
- if ($last < $first) {
- my ($no_first) = $first > $#actual;
- my ($no_last) = $last < $#actual;
- die "Couldn't locate output.\n";
- }
-
- @actual = @actual[$first ... $last];
-
- # Fix up lines that look like exit codes.
- for my $i (0...$#actual) {
- if (my ($process, $code)
- = $actual[$i] =~ /^([-a-zA-Z0-9 ]+):.*[ \(](-?\d+)\b\)?$/) {
- $process = substr ($process, 0, 15);
- $actual[$i] = "$process: exit($code)\n";
- }
- }
-
- my ($details) = "";
- $details .= "$test actual output:\n";
- $details .= join ('', map (" $_", @actual));
-
- my ($fuzzy_match) = 0;
- for (my ($i) = 0; ; $i++) {
- my ($fn) = $exp;
- $fn .= $i if $i;
- if (! -e $fn) {
- die "$exp: stat: $!\n" if !$i;
- last;
- }
- my (@expected) = map ("$_\n", snarf ($fn));
-
- $details .= "\n$test acceptable output:\n";
- $details .= join ('', map (" $_", @expected));
-
- # Check whether they're the same.
- if ($#actual == $#expected) {
- my ($eq) = 1;
- for (my ($i) = 0; $i <= $#expected; $i++) {
- $eq = 0 if !eq_lines ($actual[$i], $expected[$i]);
- }
- return if $eq;
- }