OPERATING SYSTEMS – ASSIGNMENT 2 SCHEDULING Task 1: Scheduling Policies Scheduling is a basic and important facility of any operating system. The scheduler must satisfy several conflicting objectives: fast process response time, good throughput for background jobs, avoidance of process starvation, reconciliation of the needs of lowpriority and high-priority processes, and so on. The set of rules used to determine when and how to select a new process to run is called a scheduling policy. You first need to understand the current scheduling policy. Locate it in the code and try to answer the following questions: which process the policy chooses to run, what happens when a process returns from I/O, what happens when a new process is created and when/how often the scheduling takes place. First, change the current scheduling code so that swapping out running processes will be done every quanta size (measured in clock ticks) instead of every clock tick. #define QUANTA <int value> Add this line to param.h and initialize the value of QUANTA to 5. In the next part of the assignment you will add four different scheduling policies in addition to the existing policy. Add these policies by using the C preprocessing abilities. Tip: You should read about #IFDEF macros. These can be set during compilation by gcc (see http://gcc.gnu.org/onlinedocs/cpp/Ifdef.html) Modify the Makefile to support ‘SCHEDFLAG’ – a macro for quick compilation of the appropriate scheduling scheme. Thus the following line will invoke the xv6 build with Round Robin scheduling: make qemu SCHEDFLAG=FRR The default value for SCHEDFLAG should be DEFAULT (in the Makefile). Tip: you can (and should!) read more about the make utility here: http://www.opussoftware.com/tutorial/TutMakefile.htm Policy 0: Default policy (SCHEDFLAG=DEFAULT) Represents scheduling policy currently implemented at xv6. Policy 1: FIFO Round Robin (SCHEDFLAG=FRR) This policy will extend the previous default policy. In this policy the decision of which process will run next will be on a First In - First Out basis. When a process finishes running for QUANTA time, created or finishes waiting for I/O it is considered to be the last process to arrive and wait for its next turn to run. Policy 2: First Come First Served (SCHEDFLAG=FCFS) This is a non-preemptive policy. Process that gets CPU runs until it no longer needs the CPU (yield/finish/blocked). This policy is somewhat like FIFO Round Robin with infinite quanta. Policy 3: Multi Level Queues Scheduling (SCHEDFLAG=MLQ) This policy will maintain three queues and work according to the following rules: The first queue will hold the high priority processes. The second queue will hold medium priority processes. The third queue will hold low priority processes. A process with a higher priority will be preferred and run before a process with a medium/lower priority. This means that no low or medium priority process will be allowed to run while there are still high priority runnable processes (or running), and no low priority process will be allowed to run while there are still medium priority runnable processes. You must implement system call int set_prioty(uchar priority) in order to have an ability to change process' priority (where priority can be 0,1 or 2). On creation, the process will receive a medium priority. The processes in the first two queues will be scheduled according to FIFO Round Robin. In the last queue processes will be scheduled in a First Come First Served (nonpreemptive) manner. To keep things simple we will use same quanta (from policy 1 and 2) for all queues. To define the priority mechanism for the processes you can change the ‘proc’ struct, so that it will also support different priorities. Policy 4: Multi-Core FIFO Round Robin (SCHEDFLAG=MC_FRR) Scheduling Algorithms can get tricky when more than one CPU is involved. Sometimes, it would benefit the system performance if the same process would always run on the same CPU, instead of a different one each time it is scheduled. On other hand, the OS may achieve even more efficiency on multi-CPU machine if a "smart" scheduling policy in used. Another issue is multithreading. On a single-CPU system, multithreading (i.e., more than one control flow in a single address space) is a fine thing, and if done right can greatly benefit a system's performance. But on a multiprocessor system, there are even greater benefits to win - while at the same time it gets harder to achieve them. One of the problems the OS developer will meet, while developing multi-CPU scheduling policy, is inter-CPU synchronization. We certainly do not want that the same process (at the same time) will run on more than one CPU in order to maintain the system consistency. Current xv6 implementation supports multi-core CPUs. In order to synchronize between CPUs a spinlock is used. When one of CPUs searches for a process to run (i.e., executing scheduler code) no one of other CPUs can execute a scheduler's code. This achieved by acquiring a ptable spinlock. This approach used to solve former problem, but it hardly affects OS efficiency: despite the fact that some CPUs can actually execute a process, they must wait for their turn to get an ability to choose a process to run. In this assignment we will solve this issue by introducing Multi-Core scheduling policy. In order to achieve concurrency in multi-CPU scheduling, every CPU will maintain its own process queue. When a new process created, it will be joined to the queue of the CPU that the amount of the processes in its queue is minimal (tie-breaking by the CPU id). At the time a CPU must choose a process to run it will choose the process from its queue. This way we allow multiple-CPUs to choose a process to run simultaneously. But such approach has a drawback: when a CPU cannot find a process to run in its queue, there are may be still processes that can be run at other queues. In such case the CPU must search other queues for RUNNABLE processes and if it find such process it will transfer this process to its queue and run it. Tip: you must use this technique very carefully; a special attention should be given to inter-CPU synchronization. Tip: figure out every piece of code that must be protected by an appropriate spinlock. For the sake of simplicity, every CPU must use a FIFO round robin scheduling policy. In addition, to check the consistency of the OS, every process must maintain a set of records for every time it was scheduled (the tick when its state changed to RUNNING, the tick when its state changed to RUNNABLE/SLEEPING and the CPU id which executed the process). You can assume that every process can be scheduled at most 10000 times. Task 2: Performance Measures After we have implemented different scheduling policies we will create the infrastructure that will allow us to examine how they affect performance under different evaluation metrics. The first step is to extend the ‘proc’ struct located at proc.h (line 61). Extend the ‘proc’ struct by adding the following fields to it: ctime, etime, wtime and rtime. These will respectively represent the creation time, end time, the total waiting and running time of the process. Tip: These fields retain sufficient information to calculate the turnaround time and waiting time of each process. Upon the creation of a new process the kernel will update the process’ creation time. The run time should be incremented by updating the current process whenever a clock tick occurs. Waiting time should be updated every clock tick when the state of the process is SLEEPING. Finally, care should be taken in marking the end time of the process (note: a process may stay in the ‘ZOMBIE’ state for an arbitrary length of time. Naturally this should not affect the process’ turnaround time, wait time, etc). Since all this information is retained by the kernel, we are left with the question of extracting this information and presenting it to the user. To do so, create a new system call wait2 which extends the wait system call. int wait2(int *wtime, int *rtime, int *iotime) Where the three arguments are pointers to integers to which the wait2 function will assign: (1) The aggregated number of clock ticks during which the process waited (was able to run but did not get CPU) (2) The aggregated number of clock ticks during which the process was running (3) The aggregated number of clock ticks during which the process was waiting (was not able to run). The wait2 function shall return the pid of the child process caught or -1 upon failure. Implement int get_sched_record(int *s_tick, int *e_tick, int *cpu) system call that will retrieve next record for current process and return start, stop and executing cpu id accordingly. The system call must advance to next record or yield the process if no such records exist. Task 3: Sanity Test In this section you will add an application which tests the impact of each scheduling policy. Add a program called sanity. This program will fork 20 child processes. Each child process will have a unique id (from 0 to 19) denoted by cid. Every process will get a priority based on its cid (i.e., the priority can be defined by cid mod 3). All processes will immediately perform a time-consuming computation. We do not have any restrictions regarding this computation, but make sure that every process will be scheduled at least 5 times. The code of the child processes will print its cid 500 times and will then call exit. The parent process will wait until its children exit, and then print the average waiting time, running time and turnaround time of all its children. It will then print the waiting time, running time and turnaround time of all children in each priority group (i.e the statistics for each group), followed by the waiting time, running time and turnaround time of each child process. Tip: to add a user space program, first write its code (e.g., sanity.c). Next update the Makefile so that the new program is added to the file system image. The simplest way to achieve this is by modifying the lines right after "UPROGS=\". Tip: do not use printf system call in child processes implementation since this system call will synchronize between the processes. Tip: you have to call the exit system call to terminate a process' execution. Tip: ensure the consistency of the system using get_sched_record system call just before each process termination. Submission Guidelines Make sure that your Makefile is properly updated and that your code compiles with no warnings whatsoever. We strongly recommend documenting your code changes with comments – these are often handy when discussing your code with the graders. Due to our constrained resources, assignments are only allowed in pairs. Please note this important point and try to match up with a partner as soon as possible. Submissions are only allowed through the submission system. To avoid submitting a large number of xv6 builds you are required to submit a patch (i.e. a file which patches the original xv6 and applies all your changes). You may use the following instructions to guide you through the process: Back-up your work before proceeding! Before creating the patch review the change list and make sure it contains all the changes that you applied and noting more. Modified files are automatically detected by svn but new files must be added explicitly with the ‘svn add’ command: > svn add <filename> In case you need to revert to a previous version: > svn revert <filename> At this point you may examine the differences (the patch): > svn diff Alternatively, if you have a diff utility such as kompare: > svn diff | kompare –o Once you are ready to create a patch simply make sure the output is redirected to the patch file: > svn diff > ID1_ID2.patch Tip: Although grades will only apply your latest patch, the submission system supports multiple uploads. Use this feature often and make sure you upload patches of your current work even if you haven’t completed the assignment. Finally, you should note that the graders are instructed to examine your code on lab computers only! We advise you to test your code on lab computers prior to submission, and in addition after submission to download your assignment, apply the patch, compile it, and make sure everything runs and works. Enjoy !!!
© Copyright 2026 Paperzz