Project 3: Virtual Memory Management

This project entails writing a simulator for experimenting with page replacement algorithms. This project will be done in groups of 3. The project is due on 11/18 at 5 pm .

Notes

11/14
Grading policy and writeup requirements clarified.
11/13
Due date is now Sunday, November 18th at 5 pm for both code and writeup.
11/1
I have posted a schedule of meetings for next week as well

10/31
I am dropping the requirement for LRU (least recently used) page replacement from project 3. Without LRU, you do not need to store a virtual address --> physical address mapping, which means that your page table can contain just a valid bit and a referenced bit thereby making it small.

A few clarifications:

  1. There is a file .test.c. in the directory with 537-parse.c and 537-parse.h This is sample code that shows how to use the uncommented routines . you don.t need to incorporate the code in your project in any way.
  2. The memory traces are a list of virtual page numbers. This means that the page size does not matter for this project. In addition, you can assume that there is no sharing: the virtual page are private to a process.

Goals

The goals for this project are to:
  1. Get experience with page replacement algorithms
  2. Get experience with writing simulation
  3. Get experience with software engineering techniques

Project Overview

Your primary goal for this project is to implement and experiment with page replacement algorithms. To do this, you will write a paging simulator. It will read in a set of data files specifying the scheduling and memory access behavior of programs, and will simulate the paging requirements of those programs.

As input, you will receive two types of files: scheduling traces and memory traces. Support code for parsing these files is available in ~cs537-2/public/Projects/P3 .

Scheduling Traces

Scheduling files contain a trace of process start time, CPU time, and I/O count. For the purposes of this project, you will only need to look at start time and CPU time. The format of these files is illustrated below:

xlogout       0          8.58      102720
login.kr      3          1.36      137024
rm            4          0.03      96

The format is:

Program  Start time    CPU time   I/O Count
 name   (in seconds) (in seconds) 

This trace indicates that xlogout started at time 0, required 8.58 CPU seconds to execute, and issued 102,720 I/O operations. The login.kr program started at time 3, required 1.36 CPU seconds to execute, and issued 137,024 I/O operations.

The trace is in order, meaning that each process has a start time later than or equal to the previous start time.

Code for parsing this file will be provided with the functions open_sched_trace(), close_sched_trace() and get_next_process().

The traces are available in the ~cs537-2/public/Projects/P3 directory and are named "p3sched.small", "p3sched.medium", and "p3sched.large".

Memory Traces

Memory trace files contain a list of addresess accessed by a program. The addresses are trunacted to vitual page numbers by removing the lower 12 bits, which makes the files smaller. Here is an example for PowerPoint program:

12f
77f46
12f
7ffde
12f
77f3c
12f
7ffde
12f

As an aside, the even numbered addresses (e.g. index 0,2,4) are instruction addresses and the odd numbered addresse (e.g. at index 1,3,5) are data addresses. This accounts for the alternating low values (instructions) and high values (data).

Code for parsing this file will be provided with the functions open_mem_trace(), close_mem_trace(), and get_next_vpn().

The memory traces are available in the ~cs537-2/public/Projects/P3 and are named "programname.trace". I recommend you leave the files there rather than copying them to your directory, as they are large (5MB each).

Simulating scheduling

You will need to simulate a simple scheduling algorithm that allows programs to alternate running. For this project, you only need implement round robin between runnable processes with fixed time slices. Your simulator should take as input the number of memory references in a time slice, which is called the quantum.

Your scheduler will keep track of the current time in terms of cycles, where a cycle is one memory reference in the memory trace. You will simulate a fairly slow system, where there are 100,000 cycles in a second.

Your scheduler should run (1) when the curent quantum expires, to decide whether to context switch the process, and (2) when a process blocks on a page fault (this will be explained below). Context switching should take 50 cycles. After a context switch, you should start simulating memory references from where you left off.

The scheduler should pick the next process to run and then start simulating the memory accessses for that process (see next section). Like a real scheduler, your simulated scheduler must keep track of which process is running, which are ready, and which are blocked.

Your simulator should maintain the current time (e.g., the number of seconds or cycles since the simulation started). A process from the trace should be put in the ready queue (or run) when the current time equals the start time in the scheduling trace file. It executes memory instructions for the cpu time value from the trace file, and then exits when it has used up its cpu time.

The scheduler should report elapsed time (time between when it started and when it completed) for each process. In addition, at the end of the simulation (when all processes have completed), it should report the total number of cycles executed and the number of cycles where no process was executing (i.e., there was nothing runnable).

You should experiment with quanta values of 10,000 cycles, 50,000 cycles, and 200,000 cycles.

Simulating page replacement

Your simulated machine will have a fixed number of physical pages that you must share between the currently running processes. Hence, when the memory required by the running programs exceeds the available physical memory, you will need to store some of the memory on a disk.

On each cycle, you will simulate the next memory reference in the trace for the running program. When a program starts, you should open the corresponding trace file based on the program name. For example, if the program name is "grep", you should open the "grep" memory trace.

You will simulate this by keeping track of which pages are in physical memory and which are on disk. It takes 1000 cycles to move a page from disk to memory. Moving pages from memory to disk is free, as this can be overlapped with computation. Only one page at a time can be read off disk. For example, if two processes both fault on different pages, you need to wait 1000 cycles for the first page and then 1000 cycles for the second page. You may want to maintain a queue of pending requests for the disk. While a page is moving from disk to memory, you can execute other processes -- the operation is asynchronous.

For each cycle that process executes, you should check whether the virtual page it accesses is in physical memory. If so, advance to the next address. If it is not in physical memory, you must simulate a page fault by:

  1. Context switching to a new process
  2. Putting the current process on a blocked queue
  3. Reading the page off disk
  4. Making the process ready again when the page comes back off disk

You must keep track, for each process, which pages are in physical memory and which are on disk. Assume that all pages start off on disk and you are doing demand paging. Because writing pages to disk is free, you don't have to worry about whether a page is dirty or not (and in fact, the trace does not indicate whether a memory reference is a read or a write).

For each process, you should report the number of page faults it experienced. In addition, when the simulation terminates, you should report the total number of page faults experienced across all processes.

You should experiment with total physical memory sizes of 50 pages, 250 pages, and 1000 pages.

Page replacement policies

You should simulate four different page replacement policies, specified as a command line parameter:
  1. FIFO: The first page brought in is the first to be removed.
  2. LRU: The least recently accessed page is the one to be removed
  3. Second-change FIFO: Physical memory is partitioned so that only 75% of pages are available to a process. The remaining 25% are maintained as a second-chance queue. Page start at the end of the large queue. When a new page is brought in, the head of this queue is removed and it is added to the tail of the second queue. Access to pages in this queue cause the page to be placed back at the end of the first queue. The page at the head of the second queue is replaced.
  4. Clock: You should maintain a clock hand that rotates around memory. Each physical page is marked "unused". Each time a page is needed, the hand advances until it finds a page marked "unused", at which time that page is chosen for eviction. If it finds a page marked "used" in this process, the page is changed to be "unused". In addition, on every memory reference, the page accesed should be marked "used".
For the provided scheduling traces, you should try all four page replacement policies to see how each one performs.

Write-up

You should write a 3-5 page document describing your system and explaining your results.

You should explain the architecture of your simulator: what are the components, what are the interfaces between components, and why you chose this deisgn. In addition, you should document policy decisions you made, such as:

  • Do new processes go at the head of the ready list or the end?
  • When a process starts up after a page fault, is it guaranteed to have the faulting page in memory, or could it fault again?
  • Do new processes or processes returning from a page fault get priority?
This is not a complete list -- you should include any policy decisions you made.

You should present three sets of experiments. For each one, you should present your results graphically (e.g., with a chart):

  1. Page replacement algorithm: Pick a reasonable amount of memory and time quantum, and compare the performance of the page replacement algorithms in terms of total page faults experienced and the total run time of programs (i.e., the average elapsed time of all programs).
  2. Time quantum: With either clock or second-chance FIFO, show the difference that the time quantum has on page faults and run time. You should present the results of your simulations with the three quantum values (10,000, 50,000 and 200,000). You should use a reasonable amount of memory (i.e., not 50 pages but not so much that there are no page faults).
  3. Memory size: With either clock or second-chance FIFO, demonstrate the difference that memory size has on page replacement. You should experiment with three memory sizes: 50, 500, and 5000 pages. Use a reasonable value for time quantum (e.g., 50,000 or 100,000 cycles).
For each experiment, explain the differences in performance between the different configurations.

Methodology

This project will be done in groups of three.

For the last two projects, you were free to organize the work however you liked. For this project, you must decide an architecture and division of labor in advance.

Week 1

In the first week of the project, you should design your simulator, figuring out what the major modules are and what they do. You should write a specification of the interface to each module. For example, you may have a scheduling module that decides which process is running, a page table module that tracks which pages are in memory, and a memory simulator modue that simulates each memory reference. You need to write the interface, in terms of what functions they provide and what structures they use, to each of the interfaces so that other members of your team can program against the interface before it has been implemented.

Simulator speed is important: if you use inefficient algorithms or data strctures, it may take days for your simulations to run. For this reason, you should think about how you will efficiently maintain implement each module. Consider the complexity (linear, quadratic, exponential) of each piece of your simulation as part of the design.

In addition to specifing the interface, you should create a division of labor that includes (at least) these roles:

  • Programmer for each module: the person who writes the code.
  • Tester for each module: the person who writes test code for the module.
  • Experimenter: the person who runs the experiments for the paper
After the first week, each team will meet with an instructor to discuss their design.

Week 2

After the second week, you should have a working scheduling simulator that simulates just the scheduling traces, ignoring memory simulations. You should also have an working memory trace simulator, that keeps track of what is in memory and can report the number of page faults experience by a memory trace. You do not need to implement any specific replacement policy here.

Project Specification

The command line for your simulator should be:

mem-sim pages quantum-pages pr-policy trace-file

where

  • pages is the number of physical pages
  • quantum is the number of cycles in a scheduling quantum
  • pr-policy is one of "fifo", "lru", "2fifo", or "clock" and indicates which page replacement policy to use.
  • trace-file is the name of the scheduling trace file
The output of the simulator should be:
  • For each process, the elapsed time it took to run and the number of pages faults it experienced.
  • For the entire simualtion, the total elapsed time, the total number of page faults, and the total idle time.

The simulator should handle these events:

  • Memory reference
  • Process creation
  • Timer interrupt for time slices
  • Disk I/O with disk interrupts
  • Page faults

The costs of events for the simulation are:

  • Memory reference: 1 cycles
  • Context switch: 50 cycles
  • Read page off disk: 1000 cycles
Other overheads, such as running the scheduler or handling a page fault, need not be considered.

The simulator should execute one memory instruction per cycle. Context switches take 50 cycles during which no memory instructions may be executed. Replacing a page (evicting it from memory) is free, but bringing it back from disk takes 1000 cycles. During this time, other programs may execute.

You should experiment with total physical memory sizes of 50 pages, 500 pages, and 5000 pages.

You should experiment with quanta values of 10,000 cycles, 50,000 cycles, and 200,000 cycles.

You should run experiments with FIFO, 2nd-chance FIFO, and Clock page replacement algorithms.

Hints

  • Here is some linked list code that may be helpful for managing queues. Here is example code that uses it.
  • Create a PCB structure for each running process, that records statistics about that process and has an open handle to the relevant memory trace.
  • Write a disk simulator module that manages a queue of requests and remembers which process to wake up when they complete. The disk simulator only need to run when a request is issued or completed, so it should give the scheduling simulator the time at which it should next execute.

What to turn in

Turn in your code to the directory ~cs537-2/handin//P3 by the specified due date for the code. Email your project writeup directly to the instructors mailing list (instruct537-2@cs.wisc.edu) by the due date for the writeup.

Grading Policy

  • 35% does it work -- we will run it on traces to make sure it computes the correct runtime and number of page faults.
  • 20% code quality -- is the code clearly written, well structured and documented, and does it handle possible errors appropriately.
  • 20% writeup -- do you clearly explain the design of your system, clearly present your performance results, and clearly explain the differences between different algorithms, memory sizes, and quantum size.
  • 25% group grade -- did you work well with your group?

Last modified: Mon Nov 19 13:10:40 CST 2007