#!/usr/bin/perl # # Program to run a replacement algorithm (FIFO, OPT, or LRU) on a # reference string with a specified window size. This is designed # as an aide to check the results of your homework. # # This program is super basic and should be easy to undestand, modify, # and extend. # # Author: Dmitri Tikhonov use strict; use warnings; use integer; package Algorith::PageReplacement; sub new { my $class = shift; return bless { @_ }, ref($class) || $class; } sub print_window { my ($self, $window, $index) = @_; print "Pages: @$window\n"; print "Index: $index\n" if defined $index; print "\n"; return; } package Algorith::PageReplacement::FIFO; use base qw(Algorith::PageReplacement); sub run { my ($self, %opts) = @_; my $window_size = delete $opts{'window_size'}; my @window; my $index = -1; my @reference_string = @{ $self->{'reference_string'} }; my $page_faults = 0; for my $page (@reference_string) { unless (grep { $page == $_ } @window) { ++$page_faults; $index = ($index + 1) % $window_size; $window[$index] = $page; } $self->print_window(\@window, $index); } print "Page faults: $page_faults\n"; return; } package Algorith::PageReplacement::Optimal; use base qw(Algorith::PageReplacement); sub run { my ($self, %opts) = @_; my $window_size = delete $opts{'window_size'}; my @window; my @reference_string = @{ $self->{'reference_string'} }; my $page_faults = 0; for (my $i = 0; $i < @reference_string; ++$i) { my $page = $reference_string[$i]; unless (grep { $page == $_ } @window) { ++$page_faults; if (@window < $window_size) { # There's room push @window, $page; } else { # There's no room my $victim_index = 0; my $max_distance = 0; for (my $p = 0; $p < @window; ++$p) { my $pv = $window[$p]; #pv: potential victim my $distance = 1; for (my $j = $i + 1; $j < @reference_string; ++$j) { last if $pv == $reference_string[$j]; ++$distance; } if ($distance > $max_distance) { $victim_index = $p; $max_distance = $distance; } } $window[$victim_index] = $page; } } $self->print_window(\@window); } print "Page faults: $page_faults\n"; return; } package Algorith::PageReplacement::LRU; use base qw(Algorith::PageReplacement); sub run { my ($self, %opts) = @_; my $window_size = delete $opts{'window_size'}; my @window; my @reference_string = @{ $self->{'reference_string'} }; my $page_faults = 0; for (my $i = 0; $i < @reference_string; ++$i) { my $page = $reference_string[$i]; unless (grep { $page == $_ } @window) { ++$page_faults; if (@window < $window_size) { # There's room push @window, $page; } else { # There's no room my $victim_index = 0; my $max_distance = 0; for (my $p = 0; $p < @window; ++$p) { my $pv = $window[$p]; #pv: potential victim my $distance = 0; for (my $j = $i - 1; $j >= 0; --$j) { last if $pv == $reference_string[$j]; ++$distance; } if ($distance > $max_distance) { $victim_index = $p; $max_distance = $distance; } } $window[$victim_index] = $page; } } $self->print_window(\@window); } print "Page faults: $page_faults\n"; return; } package main; use Getopt::Long; # Some defaults. my $window_size = 2; my $algorithm_class = 'FIFO'; sub usage { (my $progname = $0) =~ s~.*/~~; print < Options: --window-size Window size. Defaults to $window_size. --algorith Algorithm. One of FIFO, Optimal, or LRU. Defaults to $algorithm_class. --help Print this screen and exit. USAGE exit(shift); } GetOptions( "window-size=i" => \$window_size, "window_size=i" => \$window_size, "algorithm=s" => \$algorithm_class, "help" => sub { usage(0) }, ); if (uc($algorithm_class) eq 'FIFO') { $algorithm_class = 'Algorith::PageReplacement::FIFO'; } elsif (uc($algorithm_class) eq 'OPTIMAL') { $algorithm_class = 'Algorith::PageReplacement::Optimal'; } elsif (uc($algorithm_class) eq 'LRU') { $algorithm_class = 'Algorith::PageReplacement::LRU'; } else { die "Invalid algorithm '$algorithm_class'\n"; } $algorithm_class->new(reference_string => \@ARGV) ->run(window_size => $window_size);