This is a simulation assignment in implementing replacement algorithms. You are given an existing C++ program which reads actual memory reference traces produced by a program called valgrind. The existing simulation implements the LRU, NRU and FIFO algorithms discussed in the text. You are to add clock and page aging.
Though the trace files must be generated on Linux, this assignment can be solved anywhere you can compile standard C++.
Each of the example programs requires a valgrind address trace to run. There's some instructions below about making your own, but here are some traces I made: tgz, zip. The one called a3_lslog.txt is a short trace from running the Unix file listing command ls, the others are small GUIs, a toy (xeyes) and a a calculator tool (xcalc). It is quite possible to make longer ones, but these already take a while for the program to process.
Download the code and make it compile, and download the traces. The executable runs from the command line, and it takes four or five arguments. The name of the trace file to process, the name of the process to use, the number of real memory pages, the number of bits in the page offset, and the frequency of running the maintenance operation. The maintenance operation parameter is only used by NRU, and refers tells how often to run the procedure to clear all the reference bits. The units are references, so if the parameter is given as 1000, NRU clears the referenced bits every 1000 memory references. The number of page offset bits is the number of bits in the rightmost part of the address when it is broken up for translation. For 4k pages, that is 12 bits. This is also the default value. After running, it prints statistics. For instance,
As noted, you are to add the two additional algorithms, one to simulate clock, and one for page aging. Aging will use the maintenance frequency to decide how often to update the ages; clock will ignore this parameter.
Study the existing code to see how the algorithms are coded. Each algorithm has its own class, derived from the abstract base class ReplacementAlg defined in replacement.h. The base class takes care of reading the file of memory references, maintaining the page table, and deciding if each reference causes a fault. If so, it calls the abstract virtual method fault which returns the number of the real page chosen to use to bring in the new page. This is where the replacement algorithm runs.
You will need to add two new classes, one for clock and one for aging, and you will need to modify the vm.cpp program to included your new class files, and to recognize their names when given on the command line. You should find code for these things already present, commented out.
For clock, you might want to start with the FIFO class and modify it. Clock is just FIFO with second chance, so modify the program to check the ref bit before evicting a page. If it's set, clear it and go on. As the hand moves through each page number, use the base class method get_PTE_by_frame to see what page (if any) is using that frame, and to access its referenced bit.
For the page aging class, your constructor will need to allocate an array of 8-bit ages per page. Implement the virtual method maint to update the ages. This is called periodically by the base class according to the maintenance frequency setting. Your method will scan through each real page number, and update each age, again using get_PTE_by_frame to get and clear the reference bit. You might look at the one in NRU for a starting point. Your fault method will then scan through the ages looking for the smallest one.
Page aging should make one important modification to the algorithm as described in the text: When you bring in a new page after a fault, initialize its age to 128 rather than waiting for it to be updated at the next maintenance scan. This will keep the page from being immediately selected again if the next fault occurs before the next regular age update.
For both algorithms, fill all unused pages before replacing pages in use. This may happen naturally, but make sure it does.
The trace files can be quite large, containing many millions of memory references. These small simulations can therefore take a while to finish. I have also noticed that aging is very sensitive to the frequency parameter, and usually doesn't do well when the number of pages is small. Clock seems to perform consistently well on these traces. Here are the results from a few of mine:
The figure below shows the general organization of the simulation.
The main program is in vm.cpp. It mostly handles arguments, creates objects, and calls the trace reader in class ReplacementAlg, which is what drives the simulation. The ReplacementAlg object contains the reader, and also the page table. It handles most of the mechanics of maintaining the page table and translating references. This is all done and working.
The “Specific Algorithm” box implements the particular replacement algorithm in question. In fact, there are three of these given, to implement LRU, FIFO and NRU. You must create two more, to implement Clock and Aging. A specific algorithm class is derived from ReplacementAlg, and implements the specifics by overriding the methods name(), fault() and possibly maint(), according to the algorithm implemented. The base class processes page references, manages the page table, identifies faults, and provides a number of utility methods to help implement your overrides.
You will need to implement (override) these methods:
There are several inherited methods available to interact with the base class. The first one is the constructor, which takes a number of page frames (real memory size), number of page offset bits (which implies the page size), and (optionally) a maintenance frequency, which tells how often to call the maint method, in memory references. A frequency of zero disables the call. For this, your class should mostly receive and forward on the same values. See the constructors of the existing replacement algorithms for examples of how to do this. In addition, you have a number of inherited methods to use implementing your overrides. Some of the major ones are: