CS 134 Homework Assignment #4: Scheduling

Final Patches Due: 12-14-2012

In this assignment you will be implementing two alternative scheduling algorithms for OS/161: nonpreemptive random scheduling and the multilevel feedback scheduling algorithm described in class.

Preliminaries

Recall that you must have your path correctly set to undertake all CS 134 assignments. If you haven't done so already, put the appropriate line in your .login, .bashrc, or .zshrc.

You no longer need your code from Assignment 3. You may delete your entire source tree (although you may wish to save your patch and any other changes for posterity). Do not use svn rm to remove old code; simply blow it away with plain rm. That way, your code can be recovered later if needed (most notably, for grading).

For this assignment, check out and setup your hw4 directory in the usual way, then configure and build the kernel using the SCHED configuration files, named SCHED-RR, SCHED-MLF, and SCHED-RAND (see previous assignments for details).

Note that a single instance of the OS/161 sources can support multiple configurations and builds. For this homework, you will have build areas named SCHED-RR, SCHED-MLF, and SCHED-RAND in src/kern/compile. Each build directory is independent.

Code Reading

You should have already read enough of OS/161 to understand how the thread system and scheduler work at a basic level. You should review sched_rr.c (formerly scheduler.c) and thread.c to ensure you understand how the existing round-robin scheduler works. Note that the code now differentiates involuntary and voluntary context switches, such as those that happen during I/O wait. To support this change, mi_switch now takes an extra argument (SW_VOLUNTARY or SW_QUANTEXP), and the hardclock function in hardclock.c now calls thread_timeryield instead of thread_yield.

In addition, you should make sure you understand the winning patch that provides file and process system calls. This patch has already been applied to the code. The revised source also includes some other other small changes, including adding a simple shell (accessible via the s command at the kernel prompt) and adding a yield system call to allow a process to voluntarily give up its time slice.

Note: whenever you run the shell, it will complain about "Unknown syscall 28". You can ignore that error.

Design and Implementation Requirements

The most fundamental requirement is that your code be simple and easy to follow. You may not use any clever data structures (such as a priority queue) to represent the queue of ready processes. You must use an array (as in the provided code) and use a simple linear search—the array is usually going to be short enough that any inefficiency shouldn't matter too much.

Multilevel Feedback Scheduler

Your multilevel feedback (MLF) scheduler (whose main implementation code you will put in sched_mlf.c) should behave according to the description given on the Example “Real” Scheduler page. You may add code that should only be compiled in when the MLF scheduler is used by bracketing this MLF-specific code as follows:

#include "opt-mlfsched.h"
...
#ifdef OPT_MLFSCHED
... (MLF-specific code)
#endif /* OPT_MLFSCHED */

The same technique can also be applied to make conditional code for the RR and RAND schedulers.

Nonpreemptive Random Scheduler

Your nonpreemptive random scheduler (RAND) scheduler (whose main implementation code you will put in sched_rand.c) should pick a random ready task and run it until the task either completes, blocks, or voluntarily yields the processor.

You should, however, determine a way to handle processes that are compute-bound and do not complete or voluntarily yield in a reasonable amount of time. It is up to you to decide on a reasonable strategy to handle such tasks—you will need to deal with such unresponsive tasks, but it is up to you to decide on (and justify) the correct way to handle these processes once the kernel has made the determination that they are taking too long.

Most importantly, your implementation should not advantage processes that “break the rules,” and should justifiably fit the description of being a “nonpreemptive random scheduler.”

Patch

As usual, once you have final working code, you should create a patch for OS/161. The patch should be named sched.patch and placed in the handin directory, as usual, along with documentation sched.txt. You probably shouldn't create the patch until after you have completed the performance analysis step described in the next section.

Performance Analysis

In this part of the assignment, you will perform a qualitative and quantitative analysis of the performance of all three scheduling algorithms. To compare performance quantitatively, you will need some numerical measures.

You should have noticed that System/161 provides some hardware performance counters, such as the number of cycles in supervisor mode, the number of cycles in user mode, and so forth, which it prints when the kernel exits. These measures, along with the fact that kernel menu arguments can be given on the sys161 command line, should allow you to obtain some basic measurements of execution time.

You may find it useful to implement some software counters as well. As a start, we suggest:

You should add the necessary infrastructure to maintain these statistics, as well as any other statistics that you think you will find useful in tuning your schedulers.

Once you have added any instrumentation, it is time to tune your operating system.

Comparing Schedulers and Tuning Scheduler Parameters

Maintain all your data and observations from this section in a file named performance.txt in the handin directory.

  1. Choose several of the test programs from testbin to test your scheduler (e.g., add.c, hog.c, farm.c, sink.c, kitchen.c, ps.c), or write your own.
  2. Run each of the programs using the default time slice and the round-robin scheduling algorithm. Record the average performance of a few runs of each in performance.txt. (Your goal should be to improve on these numbers.)
  3. Vary your time slice. Before running the program, predict what should happen to performance (and discuss your prediction with your partner). Now run the programs with the new time slice and discuss the results relative to your predictions. Make sure you explain these results thoroughly.
  4. Run the programs under the MLF and RAND schedulers. Once again, compare what actually happened to what you predicted and explain the difference.
  5. Experiment by varying some of the parameters of the MLF algorithm, and record the results.
  6. Based on your results, choose a “default” scheduling policy (both algorithm and time slice) that you think will be the best for a variety of workloads.

Although the steps above form a linear sequence, you can use your judgment in developing a testing strategy. In particular, it may help to analyze just one program first, and then choose another that seems like it might have quite different behavior.