of crashes. Therefore, you should
periodically write all cached blocks to disk. If you have
@func{timer_sleep} from the first project working, this is an
-excellent application for it.
+excellent application for it. (If you're still using the base
+implementation of @func{timer_sleep}, be aware that it busy-waits, which
+is not an acceptable solution.) If @func{timer_sleep}'s delays seem too
+short or too long, reread the explanation of the @option{-r} option to
+@command{pintos} (@pxref{Debugging versus Testing}).
Likewise, read-ahead is only really useful when done asynchronously.
That is, if a process wants disk block 1 from the file, it needs to
later runs, you can make new observations without having to discard or
verify your old observations. This property is called
``reproducibility.'' The simulator we use, Bochs, can be set up for
-reproducibility, and that's the way that @command{pintos} invokes it.
+reproducibility, and that's the way that @command{pintos} invokes it
+by default.
Of course, a simulation can only be reproducible from one run to the
next if its input is the same each time. For simulating an entire
doesn't give you any greater confidence in your code's correctness
than does running it only once.
-So, to make your code easier to test, we've added a feature to Bochs
-that makes timer interrupts come at random intervals, but in a
-perfectly predictable way. In particular, if you invoke
-@command{pintos} with the option @option{-j @var{seed}}, timer
+So, to make your code easier to test, we've added a feature, called
+``jitter,'' to Bochs, that makes timer interrupts come at random
+intervals, but in a perfectly predictable way. In particular, if you
+invoke @command{pintos} with the option @option{-j @var{seed}}, timer
interrupts will come at irregularly spaced intervals. Within a single
@var{seed} value, execution will still be reproducible, but timer
behavior will change as @var{seed} is varied. Thus, for the highest
degree of confidence you should test your code with many seed values.
+On the other hand, when Bochs runs in reproducible mode, timings are not
+realistic, meaning that a ``one-second'' delay may be much shorter or
+even much longer than one second. You can invoke @command{pintos} with
+a different option, @option{-r}, to make it set up Bochs for realistic
+timings, in which a one-second delay should take approximately one
+second of real time. Simulation in real-time mode is not reproducible,
+and options @option{-j} and @option{-r} are mutually exclusive.
+
@node Tips
@section Tips
ticks per second, where @code{TIMER_FREQ} is a macro defined in
@code{devices/timer.h}.
+If your delays seem too short or too long, reread the explanation of the
+@option{-r} option to @command{pintos} (@pxref{Debugging versus
+Testing}).
+
@node Problem 1-2 Join
@section Problem 1-2: Join
our ($sim);
our ($debug);
our ($vga);
-our ($jitter);
+our ($jitter, $realtime);
use Getopt::Long qw(:config require_order bundling);
GetOptions ("sim=s" => sub { set_sim (@_) },
"run|get|put|make-disk" => \&cmd_option,
"m|memory=i" => \$mem,
- "j|jitter=i" => \$jitter,
+ "j|jitter=i" => sub { set_jitter (@_) },
+ "r|realtime" => sub { set_realtime () },
"v|no-vga" => sub { set_vga ('none'); },
"s|no-serial" => sub { $serial_out = 0; },
$vga = $new_vga;
}
+sub set_jitter {
+ my ($new_jitter) = @_;
+ die "--realtime conflicts with --jitter\n" if defined $realtime;
+ die "different --jitter already defined\n"
+ if defined $jitter && $jitter != $new_jitter;
+ $jitter = $new_jitter;
+}
+
+sub set_realtime {
+ die "--realtime conflicts with --jitter\n" if defined $jitter;
+ $realtime = 1;
+}
+
sub cmd_option {
# Force an end to option processing, as with --.
die ("!FINISH");
print " -t, --terminal Display VGA in terminal (Bochs only)\n";
print "VM options:\n";
print " -j SEED Randomize timer interrupts (Bochs only)\n";
+ print " -r, --realtime Use realistic, but not reproducible, timings\n";
print " -m, --mem=MB Run VM with MB megabytes of physical memory\n";
print "Disk options:\n";
print " --os-disk=DISK Set OS disk file (default: os.dsk)\n";
print BOCHSRC bochs_disk_line ("ata1-slave", $disks[3]);
print BOCHSRC "boot: c\n";
print BOCHSRC "ips: 1000000\n";
- print BOCHSRC "clock: sync=none, time0=0\n";
+ if (!$realtime) {
+ print BOCHSRC "clock: sync=none, time0=0\n";
+ } else {
+ print BOCHSRC "clock: sync=realtime, time0=0\n";
+ }
print BOCHSRC "megs: $mem\n";
print BOCHSRC "log: bochsout.txt\n";
if ($vga ne 'terminal') {