CSEP551 -- Programming Assignment #1
Out: Thursday January 24th, 2008
Due: Thursday February 14th, 2008, before class
In this assignment, you will investigate the impact of system call
overhead on application performance. Your ultimate goal is to produce
a set of graphs that looks something like the following:
This graph shows some application-level benchmark performance as a
function of system call latency. To generate this graph, you will
modify the linux kernel so that you can add a specifiable amount of
overhead to every system call. By varying this overhead, you can
measure benchmark performance as a function of this overhead to
generate the curve.
Here are the steps you should follow:
- Set up an environment in which you can install linux and compile
linux kernels. I strongly recommend using VMware for this. (It is true
that VMware will affect your benchmark performance, but let's ignore
that for this assignment.) You'll need to:
- Find a computer on which you can install VMware. VMware lets
you install VMware player for free. You can also get trial versions
of VMware workstation or VMware server for various environments.
- Install VMware.
- Prepare a Linux virtual machine. I recommend you browse and
download a linux "virtual appliance" from VMware, but
feel free to install Linux from scratch if you feel up to a
challenge. You can get virtual appliances here.
- Download and install the linux kernel source code. You can get
source code for different kernel versions from www.kernel.org.
- Practice compiling and installing a new kernel based on the
kernel source code you downloaded. If you've never
compiled/installed a kernel, you can find plenty of help on the Web,
for example, from here.
- Modify the linux kernel so that you can add overhead to every
system call that occurs. To do this, you'll need to:
- Figure out how system calls work on Linux, and trace them
through the linux kernel source code. There are plenty of Web pages
that should help with this, but as a hint, Linux 2.6 uses the
sysenter and sysexit instructions to do efficient user
to kernel crossings. See, for example, here.
- Add your code to the system call path. You'll have to decide
where to do this; there is a quick way that will require a small
amount of assembly hacking in one location, and a more onerous way
that will require C programming but patching a bunch of files and
routines.
- Your code should introduce a variable amount of overhead,
presumably by doing computation in a loop, and varying the loop
count.
- Make it possible for user-level programs to change the amount
of system call overhead introduced by your code. I suggest that you
add something to the /proc virtual file system to do this -- i.e.,
by writing a number to a file you create in proc, your code will
vary the amount of loop overhead according to that number. There
are plenty of web pages that will help you learn how to add
something to the /proc filesystem; see, for example, here.
- Calibrate your system call overhead by measuring the latency
of a simple system call (e.g., close(100)) as a function of your
variable overhead.
- Measure the performance of the following three benchmarks
as a function of system call overhead:
- compiling the linux kernel source tree
- the maximum throughput of apache serving a small, static file
- something of your choice
Be careful of caching effects when running your benchmarks, in particular,
of the file system buffer cache!
What to turn in
You should submit your assignment using the following "dropbox"
URL:
https://catalysttools.washington.edu/collectit/dropbox/sangt/1736
Your submission should be a single .tar.gz or .zip file, containing the
following elements:
- a description of your linux environment, including whether you used
VMware, which linux kernel version you modified, etc.
- any source code you generated, including files that you
modified in the linux kernel tree
- a writeup that includes:
- a brief description of how you added overhead (i.e., explain the design / implementation of your code)
- a brief description of the mechanism you introduced that allows user-level code to vary the system call overhead
- a graph showing the calibration of your introduced system call overhead
- the graphs of your benchmark results, and a description of your measurement method
- a short analysis of the graphs -- why are they shaped the way they are, why are they differently shaped for the different benchmarks, and what high-level lessons do you draw from this?