CS411/511. Operating Systems
Spring 1999
Project #2: Memory Management
Due at 9:00 AM on Wednesday, May 12.
For this project, you'll modify an implementation of
Least-Recently-Used (LRU) paging so that it uses:
- Least-Frequently-Used (LFU),
- then Most-Frequently-Used (MFU),
- then LFU with a second-chance for any dirty page.
These algorithms were all discussed
in class. All are global replacements -- that is, the victim is
chosen from all pages currently in memory, not just pages belonging to
the process that experiences the page fault.
As you implement each algorithm, you will compare its performance with those
you obtained using the original LRU version.
Turn in:
- Source code and a simulation run (using the hand_in script) for
the third algorithm, LFU with second-chance.
- A typed memo (1.5 pages expected, 2 page maximum) emailed
to cs411@engr.orst.edu. Compare the results of all three
versions, explaining your decisions and how well they worked out.
Include at least:
- How did you implement the LRU/MFU counters? When did you
update them, and why?
- How did you implement the second-chance part? When did you
check, and why then?
- Can processes starve under LRU? LFU? Under MFU? If so, how could
you prevent this?
- How, if at all, is the possibility of starvation affected by
adding second-chance?
- Justify any global variables you added
Also include a table of the results you obtained (raw numbers, means,
and standard deviations) by running 5 simulations each for the LRU,
LFU, MFU, and LRU with second chance versions, using heavy.parms.
The statistics we're interested in are CPU utilization, system
throughput, and total number of pages swapped in due to page faults.
Explain your results and how you
think each algorithm would work in a real-life implementation.
Building and executing the simulation
In OSP, memory management involves the functions in file memory.c.
The diagram at the end of this document indicates how OSP interacts with the
functions in that file, specifically refer (which is called each time memory
is referenced and initiates a page fault if the page is not in memory),
get_page (which is called by the page fault interrupt handler and manages the
page tables), and mem_find_frame (called by get_page to identify which
page should be victimized). These three routines are where you will be
concentrating your efforts, but you will also need to modify a couple of
lines in memory_init. Don't add global variables unless they are really
necessary. If so, they should go just prior to memory_init, and you will need
to use memory_init (which is called when OSP is set up) to initialize those
global variables.
Copy the seven files indicated below into your own directory:
~cs411/asst2.hp700/Makefile
~cs411/asst2.hp700/OSP.demo
~cs411/asst2.hp700/memory.c
~cs411/asst2.hp700/memory.h
~cs411/asst2.hp700/dialog.c
~cs411/asst2.hp700/light.parms
~cs411/asst2.hp700/heavy.parms
The only file you should have to modify is memory.c (and optionally
dialog.c). Modifying the other files will probably "break" OSP.
Compile, link, and run the program as you did for the last assignment.
How Memory Management Fits with the Rest of OSP
Whenever a memory address (note that this is a virtual address) is referenced
OSP's main loop invokes your refer() routine. The arguments are the
virtual address and the action, which is "store" if the value at
that address is to be modified. It performs the following actions:
- perform DAT: check to see that reference is within process's address space;
calculate page number; if page is not resident (OSP calls this the
"valid" bit), initiate a page fault by calling gen_int_handler()
- update any special timers or counters associated with page use
- if the action was a store, set the dirty bit
Note that most of these operations
would normally be performed in hardware, not software!
If a page fault occurred, the page fault interrupt handler calls your
get_page() routine to manage the operations:
- if the page is already in memory, return control to the interrupt handler
immediately
- find out where to put the needed page by calling mem_find_frame():
- find a frame that is not in use (that is, both "free" *and* with a lock
count of zero); if one is available, return that frame number to
get_page()
- select a victim and return that frame number to get_page()
- if the victim is dirty, write the page out via a call to siodrum(),
then update the corresponding page table entry to show that it is
no longer resident in memory (OSP calls this the "valid" bit)
- fetch in the new page via a call to siodrum(), then
update the page table entry fo the page that was just brought in,
clear its dirty bit, and re-initialize and special timers or
counters associated with page use
Tips for Doing Your Assignment
OSP has an inverted page table that may make it easier to keep track of
global page use (re-read this portion of the book if necessary; an inverted
page table has basic info on all the pages currently in memory).
Here are some fields associated with the Frame_Tbl that may be useful:
| lock_count | 0 if the page can be replaced; 1 or more if
a process(es) is using it and an I/O operation is pending
|
| dirty | true if the page in that frame has been modified
|
| free | true if there is currently no page allocated
to that frame
|
There is also one global variable you'll need to use:
time_stamps - integer array containing time of last
reference to the page in the cooresponding frame (in
our LRU version; you may use this array
as a counter for implementing LFU and MFU
algorithms
Survivial hint: Since you need to turn in something that
compiles and runs, you may want to work up to the final solution in stages. A
good way to start would be to first print out the frame table, then
change the LRU algorithm into LFU. Once you have done this, it should be
easy to change it to MFU. Don't even think about the second-chance part
until everything else is done.
Debugging hint: Note that if a page fault occurs and I/O is performed, the CPU may be assigned
to another process while the I/O takes place. When your code in get_page()
is resumed, the
page table base register (PTBR) will point to that other process's page table,
not the one you want! So be sure to save PTBR->pcb before calling siodrum().
Debugging hint: Routine mem_find_frame() should always
find a victim unless by some bizarre chance all frames are locked. (But
the fact that all frames are dirty should not keep you from identifying
a victim!) Otherwise, OSP will break; it assumes that it will get a frame
unless there are a whole bunch of outstanding I/O requests.
Turning in Your Assignment
When you are satisfied that your memory management algorithm works, use the hand_in
script to submit your project. Be sure you have made several runs using the heavy.parms
parameter file. Bugs in your implementation may not show up under the light.parms
parameter settings. For that reason, assignments which are handed in using the
light.parms file are not acceptable.
To submit your project, use the following command from the directory where you source
files are located:
> ~cs411/asst2.hp700/hand_in
This script will compile your source code and link it with OSP. Then it will prompt you
for a parameter file. Use heavy.parms. Hand_in will run the OSP
simulator and put a copy of your source code and a copy of the simulation results in a
secure sub-directory in the cs411 directory. You can submit the assignment as many times
as you want -- only the last submission will count. Earlier submissions are overwritten.
Remember to turn your assignment in on time. We don't accept late submissions, but
we do give partial credit if the assignment actually runs and is on time.