pop up description layer
Last modified: 20080911:115102/initial version for 2008

FIT2022 AJH-2008-36

FIT2022 Computer Systems II

Laboratory Session 5

Objectives and Outcomes | The Literate Program | The Story So Far | Processes | Events | Outputs of the Simulations | Shortest Remaining Time First (Preemptive) | Round Robin | Main | Exercises | Indices

Shortest Remaining Time First and Round Robin Schedulers

1. Objectives and Outcomes

1.1 Objectives

  1. to understand factors governing the choice of job scheduling algorithms;
  2. to understand the behaviour of the Shortest Remaining Time First job scheduling algorithm;
  3. to understand the behaviour of the Round Robin job scheduling algorithm; and
  4. to develop skills in comparing and explaining the behaviours of two related algorithms.

1.2 Outcomes

At the end of this lab session, you should:

  1. be familiar with the SRTF and RR pre-emptive job scheduling algorithms;
  2. be able to explain the behaviours of these algorithms in terms of the nature of processes that they handle; and
  3. be able to compare and contrast those behaviours with each other.

Your demonstrator may ask you questions about these points, and will only give you a "satisfactory" for the lab if you can respond correctly.

Don't forget to enter your experiences into your lab journal, and save it back to the svn repository!

2. The Literate Program

There are no new ideas introduced to the literate programming model in Lab 4.

The program below has already been tangled. There are eight files:

  1. The Process Module
  2. The Events Module
  3. The SRTF Module
  4. The RR Module
  5. The Simulation Program for SRTF
  6. The Simulation Program for RR
  7. The Gantt chart generator
  8. a test file (initial)
and you need to download each of them by clicking on each of these links. Alternatively, download the full Lab 5 tar file

3. The Story So Far

This simulation is about modelling processes, the events that occur to them, and the process (or job) scheduling algorithm. We model the execution of several processes, and try out the various algorithms discussed in lectures to see the effect on throughput, or the number of processes completed within a given time. We expect that some algorithms will perform better than others, but we also expect to see a variation in the comparison depending upon the actual behaviour of the processes, and the flow of events as they execute.

The heart of the simulation is this focus upon the key events that happen during a process's life cycle. We are interested in the effect of these events, and we seek to discover something about the real operating system environment by abstracting the events from that real world system. So we are not building an operating system itself, but rather a model in which the events, the time at which they happen and their effect upon the system, exactly parallel the real system, but all other unnecessary detail is removed.

4. Processes

Remember in Lab 2 how we modeled processes by means of a set of threads? Since we are not actually running any processes per se in this lab exercise, we no longer need to use threads, but instead restrict ourselves to just the salient abstractions of a process, such as the fact that it has a unique process number, that it has a predicted run time, that it spends some time doing IO (and hence in the wait queue), and so on. All of these attributes are abstracted into a new class Process, defined in a separate module.

The Process definitions appear in a separate module.

5. Events

We use the event model developed in Lab2 to drive the simulation. Events are things like process completion, IO start and finish, resource requests, and so on. Anything which moves a process around the process state diagram, in fact. Each simulation is driven by a sequence of events, an encoding of which is read in from standard input, and used to define the process state transitions. It is the timing of these transitions that interests us in this lab.

Shown below for each event is the format of the event record, read in as part of the initial file. Some events (create and admit) are identified in the initial event list. Other events, such as dispatch, are generated by the simulation, and added to the event list as the simulation proceeds.

The Events definitions appear in a separate module.

create
A process is created. The event defines the process number of the process that is created. We also define the total running time of the process, which determines how long the process will execute before it reaches the terminate state. Since the process may also generate I/O which will in turn generate a rescheduling, we model this with a (very simple) model of defining how many time intervals before it issues an I/O operation. If this value is zero, no I/O will take place. Other information attached to the process is not used in FCFS, and so can be set to zero. The event record will look like this:
[event time] create [process no] [run time] [I/O time]
admit
A specified process is admitted to the ready queue. No other information required.
[event time] admit [process no] 0 0 0
dispatch
this event will be generated by the scheduler, when it determines which process to make ready. There should be no input event records for dispatch.
iowait
this event will be generated by the scheduler, from information in the create input record. There is no input event record for iowait itself.
iocomplete
this event needs to be generated by the scheduler, whenever a process goes into the iowait state. For the moment, we will adopt a simple approach, and assume that the length of time a process spends in iowait is fixed, and this time is specified as the value of a class variable IOWaitTime. There is no corresponding input record.
exit
this event will also be generated by the scheduler, when the total execution time of the process (p.time) has been used up. There is no input event record for exit.

6. Outputs of the Simulations

Each simulation is designed to generate similar outputs, so that you can compare them easily. There are three main outputs:

  1. A text listing of events as they are simulated.
  2. A sumary of the Process Table at the end of simulation. This table records all events that happened to this process.
  3. A Gantt chart of the process state for each process (derived from 2). In this lab, this is generated as an ASCII diagram, but in the tar file you will find another Gantt chart module (Gantt-gtk.py), which is a plug-in replacement for the ASCII version. Unfortunately, I have been unable to test this module (which has worked previously), due to upgrade incompatibilities with my version of gnome and pygtk/gtk. See Exercise 7 for an opportunity to explore this module further.

7. Shortest Remaining Time First (Preemptive)

7.1 Introduction

Here is the process state transition diagram, augmented to include the pre-emptive edge of interruption. This is now the full state diagram, as given in the text (and should be committed to memory).

Unlike the First-Come First-Served algorithm, processes are not scheduled in order of arrival, but rather which one has the shortest time to run. Two strategies are possible:

  1. maintain the ready queue in order of shortest time first (schedule on addition to queue); or
  2. maintain the ready queue in arbitrary order, and select the shortest time entry when we need to dispatch a process (schedule on removal from queue).
The choice is arbitrary, but since it is nice if the ready queue bears some resemblance to the actual scheduling of processes, we will chose the former strategy. The changes are described in <define the SRTF AddReady method 7.4>.

SRTF and RR are both pre-emptive schedulers, which means that a process may be removed from the running state before we expect it to be. This means that the approach we used in lab 4 of working out how long a process will run for before dispatching it, and scheduling an event for either io waiting or termination, will no longer work, since these events will not happen at the appointed time if the process is pre-empted.

Instead, we have to check the event clock at each cycle, to see whether pre-emption is taking place, and if so, update the process data accordingly. The main thrust of the changes is to refine the process data to include a variable to count how much time to the next io wait, and to the event module to explicitly cycle the clock, and see if an event is due at the current time. The process variable timetoio is initialized to the value of iotime, and counts down the time to the next io wait event. It is preserved over pre-emption, and thus captures the semantics that we seek.

In the new model, rather than computing the process time values at the event times, we recompute them on each clock tick. If the time to run time, or time to next io wait timeio reaches zero, we schedule the appropriate event then.

Again, we use the initial set of events developed in Lab2 to start the simulation off.

7.2 The Shortest Remaining Time First class

"SRTF.py" 7.1 =
import Processimport Events<SRTF definitions 7.2,7.16>

We write the SRTF algorithm as a Python module. This means that it is constructed as a separate file, which is imported into our main program. The file just contains all the definitions we are going to use.

<SRTF definitions 7.2> =
class SRTF: running = -1 ReadyQ = [] IOWaitTime = 10 preemptTime = -1 <define the SRTF tick method 7.3> <define the SRTF HandleEvent method 7.5> <define the SRTF AddReady method 7.4>
Chunk referenced in 7.1
Chunk defined in 7.2,7.16

The running variable defines which process currently is running. A value of -1 indicates that no process is currently running. The ReadyQ is implemented as a Python list, initialized to empty. As suggested above, we use a simple model of IO activity, and assume that all IO takes a fixed amount of time to complete, given by the variable IOWaitTime. This variable may be altered by specification on the command line (see below).

7.2.1 The SRTF tick method

<define the SRTF tick method 7.3> =
def tick(self): if SRTF.running >= 0: pr = Process.PT.pt[SRTF.running] if pr.time == 0: newEv = Events.EventCreate(Events.currentTime,'exit',pr.num,0,0,0) Events.AddEvent(newEv) elif pr.timetoio == 0: newEv = Events.EventCreate(Events.currentTime,'iowait',pr.num,0,0,0) Events.AddEvent(newEv)
Chunk referenced in 7.2

As each clock tick passes, we check the currently running process to see if it has any activity to note. Two counters count down to indicate this: the time variable, which indicates the remaining time for the process, and the timetoio variable, which indicates when the next io event for the process will happen. If either of these reach zero, then the process will exit or iowait. Note that we test for exit (termination) first, since if both counters hit zero simultaneously, the process is regarded as terminated.

7.2.2 The SRTF Add to Ready Queue method

<define the SRTF AddReady method 7.4> =
def AddReady(self,pnum): addp = Process.PT.pt[pnum] for i in range(len(self.ReadyQ)): pn = self.ReadyQ[i] process = Process.PT.pt[pn] if (addp.time < process.time): self.ReadyQ.insert(i,pnum) break else: self.ReadyQ.append(pnum) print " added process %d to ready queue with time %d, ReadyQ=%s" \ % (pnum,addp.time,self.ReadyQ)
Chunk referenced in 7.2

This defines the method of adding a process to the ready queue. Recall that we decided in the Introduction above to maintain the ready queue in shortest time first order, rather than just using the default append-to-end employed in FCFS. The method takes a process number as argument, and inserts that process (number) into the ready queue ordered in shortest time first order.

We scan the ready queue from first to last, looking for a process time that is larger than the incoming one. If we find one, the new entry is inserted just before that one. Two endcases arise: the list is initially empty (the for loop body is not executed), or the new value is larger than any in the list (the for loop falls through the end). In both cases, the else branch of the for loop is taken, and we just append the new value to the (possibly empty) list. Neat huh?

7.3 Handling Events in SRTF

What distinguishes SRTF from other algorithms is the way in which it responds to the events that occur at the process management level. The structure of the outer part of the algorithm is similar to FCFS, however.

<define the SRTF HandleEvent method 7.5> =
def HandleEvent(self,ev): if ev.type == 'create': <SRTF handle create event 7.6> elif ev.type == 'admit': <SRTF handle admit event 7.7> elif ev.type == 'dispatch': <SRTF handle dispatch event 7.8> elif ev.type == 'interrupt': <SRTF handle interrupt event 7.9> elif ev.type == 'iowait': <SRTF handle iowait event 7.10> elif ev.type == 'iocomplete': <SRTF handle iocomplete event 7.11> elif ev.type == 'exit': # terminate <SRTF handle exit event 7.12> <SRTF schedule process 7.14>
Chunk referenced in 7.2

This is the main event handler for the algorithm. Each of the event types is handled within this method. Some events will cause other events to be added to the event list.

7.3.1 The SRTF Create Event

<SRTF handle create event 7.6> =
pr = Process.ProcessCreate(ev.p1,ev.p2,ev.p3,ev.p4)pr.statechange(ev.time,'created')if pr.iotime > 0: pr.timetoio = pr.iotimeelse: pr.timetoio = pr.time + 1LogEvent(pr,"created")
Chunk referenced in 7.5

A create event simply creates the corresponding process. We call statechange to indicate that the process now is created, which fact is recorded in the history data. Note that if no io is to be simulated, indicated by a zero value for iotime, then set the time to the next io event to one unit greater than the time to run. This means the io event will never happen, since the process will terminate first.

7.3.2 The SRTF Admit Event

<SRTF handle admit event 7.7> =
pr = Process.PT.pt[ev.p1]pr.statechange(ev.time,'ready')self.AddReady(ev.p1)LogEvent(pr,"admitted")<SRTF check if current process should be preempted 7.13>
Chunk referenced in 7.5

When a process is admitted to the ready queue, we set its state to ready, and call the AddReady routine to insert it in the right position to maintain shortest remaining time first.

Since the arriving job may be shorter than the currently executing job, pre-emption may occur, and we have to check for that.

7.3.3 The SRTF Dispatch Event

<SRTF handle dispatch event 7.8> =
pr = Process.PT.pt[ev.p1]pr.statechange(ev.time,'running')SRTF.running = pr.numLogEvent(pr,"dispatched")
Chunk referenced in 7.5

A 'dispatch' event causes a process to start running. Its state is therefore set to 'running', and we record the new running process. Since this is a preemptive environment, we rely upon the tick algorithm to check for completion/io/interruption events, and need not test for them here.

7.3.4 The SRTF Interrupt Event

<SRTF handle interrupt event 7.9> =
pr = Process.PT.pt[ev.p1]pr.statechange(ev.time,'ready')if SRTF.running == pr.num: SRTF.running = -1self.AddReady(pr.num)LogEvent(pr,"interrupted")
Chunk referenced in 7.5

A 'interrupt' event causes a process to stop running. Its state is therefore set to 'ready'. Set the running flag to indicate no process is running. We must therefore call the scheduler to reschedule the shortest remaining time process next.

7.3.5 The SRTF IOWait Event

<SRTF handle iowait event 7.10> =
pr = Process.PT.pt[ev.p1]pr.statechange(ev.time,'waiting')SRTF.running = -1waitfor = SRTF.IOWaitTimeetime = Events.currentTime + waitfornewEv = Events.EventCreate(etime,'iocomplete',ev.p1,0,0,0)Events.AddEvent(newEv)LogEvent(pr,"io waits",waitfor)
Chunk referenced in 7.5

A 'iowait' event causes a process to stop running, and its state is set to 'waiting'. Work out how long to wait for, and schedule an iocomplete event at that time.

7.3.6 The SRTF IOComplete Event

<SRTF handle iocomplete event 7.11> =
pr = Process.PT.pt[ev.p1]pr.statechange(ev.time,'ready')if pr.iotime > 0: pr.timetoio = pr.iotimeelse: pr.timetoio = pr.time + 1self.AddReady(ev.p1)LogEvent(pr,"completes io")<SRTF check if current process should be preempted 7.13>
Chunk referenced in 7.5

A 'iocomplete' event causes a process to stop waiting for io, and its state to become 'ready' again. Update its waiting time, and reset the time to the next io event from the iotime value. If there is no io, set the time to io to be greater than the time to run, so that no io wait will take place. The process is returned to the ready queue.

Because the algorithm is pre-emptive, we must check if the current process should be pre-empted. This is handled in a separate piece of code.

7.3.7 The SRTF Exit Event

<SRTF handle exit event 7.12> =
pr = Process.PT.pt[ev.p1]pr.statechange(Events.currentTime,'terminated')SRTF.running = -1LogEvent(pr,"terminates")
Chunk referenced in 7.5

An 'exit' event causes a process to stop all demands for CPU time. Its state is set to 'terminated'.

7.3.8 Handling Pre-emption and Scheduling

<SRTF check if current process should be preempted 7.13> =
if SRTF.preemptTime != Events.currentTime and SRTF.running > 0: curpr = Process.PT.pt[SRTF.running] timeToRun = curpr.time if timeToRun > 0 and curpr.timetoio > 0: if pr.time < timeToRun: newEv = Events.EventCreate(Events.currentTime,'interrupt',SRTF.running,0,0,0) Events.AddEvent(newEv) msg = "preemption forced" SRTF.preemptTime = Events.currentTime else: msg = "no preemption" print " check preemption: " + \ "new (%d): %d, current (%d): %d/%d, %s" % \ (pr.num,pr.time,SRTF.running,timeToRun,curpr.timetoio,msg)
Chunk referenced in 7.7 7.11

An event (admit or iocomplete) has occurred that could cause preemption. Because there may be more than one event that could cause pre-emption, we first check the time of last pre-emption. If it is the same as now, we don't need to recompute this calculation (nor should we, since we might create a redundant interrupt event).

Check the time to run of the current process and see whether it is longer than the new process. Note that if the current process has a zero time or timetoio, then do nothing, since the current process will quit the running state this clock tick anyway.

7.3.9 Schedule a Process

<SRTF schedule process 7.14> =
if SRTF.running < 0: if len(SRTF.ReadyQ) > 0: <SRTF dispatch a process 7.15>
Chunk referenced in 7.5

After handling an event, we check the running flag. If it is set to -1, it means that there is no process running, and we pop the ready queue to determine which process should be dispatched.

<SRTF dispatch a process 7.15> =
runP = SRTF.ReadyQ[0]SRTF.running = runPdel SRTF.ReadyQ[0]newEv = Events.EventCreate(Events.currentTime,'dispatch',runP,0,0,0)Events.AddEvent(newEv)
Chunk referenced in 7.14

Dispatch a process by removing it from the ready queue, and scheduling a dispatch event for it for the current time.

7.4 Utility Functions

<SRTF definitions 7.16> =
def LogEvent(pr,evname,waitfor=0): if waitfor>0: msg = ", io wait for %d" % waitfor else: msg = "" print "time:%3d => process %d %s, run time %d, time to io %d%s" % \ (Events.currentTime,pr.num,evname,pr.time,pr.timetoio,msg)
Chunk referenced in 7.1
Chunk defined in 7.2,7.16

This is a convenient logging function to record on standard output the events that have been processed.

8. Round Robin

8.1 Introduction

We continue on from the Shortest Time First Scheduler, using the code developed there to develop the Round Robin scheduler.

The Round Robin scheduler maintains the ready queue as for the First-Come First-Served algorithm, so we can revert to the simpler AddReady algorithm.

In the new model, rather than updating the process time values at each event time, we update them on each clock tick. If the time to run time, or time to next io wait timeio reaches zero, we schedule the appropriate event then.

Again, we use the initial set of events developed in Lab2 to start the simulation off.

8.2 The Round Robin class

"RR.py" 8.1 =
import Processimport Events<RR definitions 8.2,8.15>

We write the RR algorithm as a Python module. This means that it is constructed as a separate file, which is imported into our main program. The file just contains all the definitions we are going to use.

<RR definitions 8.2> =
class RR: running = -1 ReadyQ = [] IOWaitTime = 10 TimeSlice = 3 <define the RR tick method 8.3> <define the RR HandleEvent method 8.5> <define the RR AddReady method 8.4>
Chunk referenced in 8.1
Chunk defined in 8.2,8.15

The running variable defines which process currently is running. A value of -1 indicates that no process is currently running. The ReadyQ is implemented as a Python list, initialized to empty.

As suggested above, we use a simple model of IO activity, and assume that all IO takes a fixed amount of time to complete, given by the variable IOWaitTime. This may be modified by command line parameters.

The Round Robin algorithm requires that we allocate a maximum time slice to each process when it is dispatched. This is defined by the (fixed) value of TimeSlice, which also may be modified by command line parameters.

8.2.1 The RR tick method

<define the RR tick method 8.3> =
def tick(self): if RR.running >= 0: pr = Process.PT.pt[RR.running] if pr.time == 0: newEv = Events.EventCreate(Events.currentTime,'exit',pr.num,0,0,0) Events.AddEvent(newEv) elif pr.timetoio == 0: newEv = Events.EventCreate(Events.currentTime,'iowait',pr.num,0,0,0) Events.AddEvent(newEv) elif pr.slice == 0: newEv = Events.EventCreate(Events.currentTime,'interrupt',pr.num,0,0,0) Events.AddEvent(newEv)
Chunk referenced in 8.2

As each clock tick passes, we check the currently running process to see if it has any activity to note. Three counters count down to indicate this: the time variable, which indicates the remaining time for the process, the timetoio variable, which indicates when the next io event for the process will happen, and the slice variable, added to the Process data to indicate how much time is left in the current time slice. If any of these reach zero, then the process will exit, iowait, or interrupt, as appropriate. Note the order in which we test these, since if exit (termination) occurs first, the others do not matter. Similarly, if the process iowaits, it does not need to be interrupted.

8.2.2 The RR Add to Ready Queue method

<define the RR AddReady method 8.4> =
def AddReady(self,pnum): addp = Process.PT.pt[pnum] self.ReadyQ.append(pnum) print " added process %d to ready queue with time %d, ReadyQ=%s" \ % (pnum,addp.time,self.ReadyQ)
Chunk referenced in 8.2

This defines the method of adding a process to the ready queue. For Round Robin, we revert to first in first out order, so simply appending to the queue suffices.

8.3 Handling Events in RR

What distinguishes RR from other algorithms is the way in which it responds to the events that occur at the process management level. The structure of the outer part of the algorithm is similar to FCFS and SRTF, as before.

<define the RR HandleEvent method 8.5> =
def HandleEvent(self,ev): if ev.type == 'create': <RR handle create event 8.6> elif ev.type == 'admit': <RR handle admit event 8.7> elif ev.type == 'dispatch': <RR handle dispatch event 8.8> elif ev.type == 'interrupt': <RR handle interrupt event 8.9> elif ev.type == 'iowait': <RR handle iowait event 8.10> elif ev.type == 'iocomplete': <RR handle iocomplete event 8.11> elif ev.type == 'exit': # terminate <RR handle exit event 8.12> <RR schedule process 8.13>
Chunk referenced in 8.2

This is the main event handler for the algorithm. Each of the event types is handled within this method. Some events will cause other events to be added to the event list.

8.3.1 The RR Create Event

<RR handle create event 8.6> =
pr = Process.ProcessCreate(ev.p1,ev.p2,ev.p3,ev.p4)pr.statechange(ev.time,'created')if pr.iotime > 0: pr.timetoio = pr.iotimeelse: pr.timetoio = pr.time + 1LogEvent(pr,"created")
Chunk referenced in 8.5

A create event simply creates the corresponding process, and we set its state to 'created'. Note that if no io is to be simulated, indicated by a zero value for iotime, then set the time to the next io event to one unit greater than the time to run. This means the io event will never happen, since the process will terminate first.

8.3.2 The RR Admit Event

<RR handle admit event 8.7> =
pr = Process.PT.pt[ev.p1]pr.statechange(ev.time,'ready')self.AddReady(ev.p1)LogEvent(pr,"admitted")
Chunk referenced in 8.5

When a process is admitted to the ready queue, we set its state to ready, and call the AddReady routine to insert it in the right position to maintain shortest remaining time first.

Unlike SRTF, the arrival of a process does not cause pre-emption, since we wait until the end of the current slice for the new process to get a turn in the running slot.

8.3.3 The RR Dispatch Event

<RR handle dispatch event 8.8> =
pr = Process.PT.pt[ev.p1]pr.statechange(ev.time,'running')pr.slice = RR.TimeSliceRR.running = pr.numLogEvent(pr,"dispatched")
Chunk referenced in 8.5

A 'dispatch' event causes a process to start running. Its state is therefore set to 'running'. We must allocate a fixed unit of time to run, so the slice counter is reset to the slice value.

8.3.4 The RR Interrupt Event

<RR handle interrupt event 8.9> =
pr = Process.PT.pt[ev.p1]pr.statechange(ev.time,'ready')if RR.running == pr.num: RR.running = -1self.AddReady(pr.num)LogEvent(pr,"interrupted")
Chunk referenced in 8.5

A 'interrupt' event causes a process to stop running. Its state is therefore set to 'ready'. We must therefore call the scheduler to reschedule the shortest remaining time process next.

8.3.5 The RR IOWait Event

<RR handle iowait event 8.10> =
pr = Process.PT.pt[ev.p1]pr.statechange(ev.time,'waiting')RR.running = -1waitfor = RR.IOWaitTimeetime = Events.currentTime + waitfornewEv = Events.EventCreate(etime,'iowait',ev.p1,0,0,0)Events.AddEvent(newEv)LogEvent(pr,"io waits",waitfor)
Chunk referenced in 8.5

A 'iowait' event causes a process to stop running, and enter the 'waiting' state. Work out how long to wait for, and schedule an iocomplete event at that time.

8.3.6 The RR IOComplete Event

<RR handle iocomplete event 8.11> =
pr = Process.PT.pt[ev.p1]pr.statechange(ev.time,'ready')if pr.iotime > 0: pr.timetoio = pr.iotimeelse: pr.timetoio = pr.time + 1self.AddReady(ev.p1)LogEvent(pr,"completes io")
Chunk referenced in 8.5

A 'iocomplete' event causes a process to stop waiting for io, and its state to become 'ready' again. Update its waiting time, and reset the time to the next io event from the iotime value. If there is no io, set the time to io to be greater than the time to run, so that no io wait will take place. The process is returned to the ready queue.

8.3.7 The RR Exit Event

<RR handle exit event 8.12> =
pr = Process.PT.pt[ev.p1]pr.statechange(Events.currentTime,'terminated')RR.running = -1LogEvent(pr,"terminates")
Chunk referenced in 8.5

An 'exit' event causes a process to stop all demands for CPU time. Its state is set to 'terminated'.

8.3.8 Handling Pre-emption and Scheduling

The only pre-emption that occurs in Round Robin is at the end of a time slice, which is handled by the tick method, and a separate interrupt event. Hence there is no need to check for pre-emption here.

8.3.9 Schedule a Process

<RR schedule process 8.13> =
if RR.running < 0: if len(RR.ReadyQ) > 0: <RR dispatch a process 8.14>
Chunk referenced in 8.5

After handling an event, we check the running flag. If it is set to -1, it means that there is no process running, and we pop the ready queue to determine which process should be dispatched.

<RR dispatch a process 8.14> =
runP = RR.ReadyQ[0]RR.running = runPdel RR.ReadyQ[0]newEv = Events.EventCreate(Events.currentTime,'dispatch',runP,0,0,0)Events.AddEvent(newEv)
Chunk referenced in 8.13

Dispatch a process by removing it from the ready queue, and scheduling a dispatch event for it for the current time.

8.4 Utility Functions

<RR definitions 8.15> =
def LogEvent(pr,evname,waitfor=0): if waitfor>0: msg = ", io wait for %d" % waitfor else: msg = "" print "time:%3d => process %d %s, run time %d, time to io %d%s" % \ (Events.currentTime,pr.num,evname,pr.time,pr.timetoio,msg)
Chunk referenced in 8.1
Chunk defined in 8.2,8.15

This is a convenient logging function to record on standard output the events that have been processed.

9. Main

The main process of this simulation reads in the simulation file, builds the event queue, and then starts the simulation running.

"srtfsim.py" 9.1 =
#!/usr/bin/env python<imports 9.3><define subroutines 9.4,9.5><collect CLI values 9.9>import SRTFsrtf = SRTF.SRTF()SRTF.SRTF.IOWaitTime = IOWaitCycleparms = "(iowait:%d)" % (SRTF.SRTF.IOWaitTime)<run the SRTF simulation 9.7>print Process.PTGantt.Gantt(Process.PT,"Shortest Remaining Time First"+" "+parms,result)

The main program for Shortest Remaining Time First. The call on the Gantt chart generator should display charts like this:

"rrsim.py" 9.2 =
#!/usr/bin/env python<imports 9.3><define subroutines 9.4,9.5><collect CLI values 9.9>import RRrr = RR.RR()RR.RR.IOWaitTime = IOWaitCycleRR.RR.TimeSlice = TimeSliceparms = "(iowait:%d, slice:%d)" % (RR.RR.IOWaitTime,RR.RR.TimeSlice)<run the RR simulation 9.8>print Process.PTGantt.Gantt(Process.PT,"Round Robin"+" "+parms,result)

The main program for Round Robin.

<imports 9.3> =
import stringimport Processimport Eventsimport Ganttimport sys
Chunk referenced in 9.1 9.2

The common set of import statements.

<define subroutines 9.4> =
def read_simulation(): "read the initial event list for simulation" parms = open('initial','r') line = parms.readline() while len(line) > 0: fields = string.split(line) etime = string.atoi(fields[0]) etype = fields[1] p1 = string.atoi(fields[2]) p2 = string.atoi(fields[3]) p3 = string.atoi(fields[4]) p4 = string.atoi(fields[5]) line = parms.readline() event = Events.EventCreate(etime,etype,p1,p2,p3,p4) Events.AddEvent(event) parms.close() return
Chunk referenced in 9.1 9.2
Chunk defined in 9.4,9.5

This code reads lines from the initial file, which defines the initial set of events, and builds the initial event queue.

<define subroutines 9.5> =
epoch = 100def run_simulation(algorithm): "run the simulation" while Events.currentTime < epoch: algorithm.tick() ev = Events.NextEvent() while ev != None: algorithm.HandleEvent(ev) ev = Events.NextEvent() Events.tick() Process.tick() <compute simulation results 9.6> return result
Chunk referenced in 9.1 9.2
Chunk defined in 9.4,9.5

This code performs the simulation itself. Its main loop counts the clock along, updates process data, and then calls the scheduling algorithm to see if any action needs to be taken. The simulation ends when the clock reaches the end of the epoch. "Epoch" means "a particular period of time marked by distinguishing events" (Macquarie), and here the distinguishing events are the start and end of simulation.

<compute simulation results 9.6> =
totalwait = 0.0avgwait = 0.0nprocs = len(Process.PT.pt)if nprocs>0: for k in Process.PT.pt.keys(): p = Process.PT.pt[k] totalwait = totalwait + p.twait avgwait = totalwait / nprocs result="average wait time: %5.1f" % (avgwait)else: result = "(no processes to analyse)"
Chunk referenced in 9.5

Add up all the wait times for each process to find the average waiting time.

<run the SRTF simulation 9.7> =
print "\n"; print "SRTF:"; print "====="read_simulation()result = run_simulation(srtf)
Chunk referenced in 9.1
<run the RR simulation 9.8> =
print "\n"; print "RR:"; print "====="read_simulation()result = run_simulation(rr)
Chunk referenced in 9.2
<collect CLI values 9.9> =
if len(sys.argv)>1: IOWaitCycle = string.atoi(sys.argv[1])else: IOWaitCycle = 10if len(sys.argv)>2: TimeSlice = string.atoi(sys.argv[2])else: TimeSlice = 5
Chunk referenced in 9.1 9.2

The main program consists of loading the initial events and running the simulation.

"initial" 9.10 =
0 create 20 8 3 01 admit 20 0 0 02 create 21 12 5 03 create 22 8 4 04 create 23 24 7 04 admit 23 0 0 08 admit 22 0 0 013 admit 21 0 0 0

10. Exercises

You asked for the exercises to be separate. You got it!

Exercise 1

There is a fairly obvious bug in the RR scheduler. Find it and fix it. Your demonstrator will give help as you need it.

Exercise 2

Once you have fixed the bug, run the two simulations SRTF and RR with the standard initial file and standard parameter values (that is, no additional CLI parameters, just python srtfsim.py and python rrsim.py. You'll find it convenient to run them in the background by appending & to each invocation. Compare the two outputs. Which algorithm gives the minimum average waiting time? Can you give an explanation for this behaviour?

Exercise 3

Two of the processes in the above simulations have no waiting time under SRTF(*). Is this simply fortuitous ("good luck"), or is it because the algorithm is intrinsically better ("good management")? Devise an experiment to test your theory.

Hint: "Testing will never show the absence of bugs, only their presence" is a famous statement by the eminent computer scientist Edsgar Dijkstra. You should bear this maxim in mind as you test your theory.

* Careful here! Distinguish between "waiting time" and "time in the (io) waiting state". Remember that process waiting time is defined as time in the ready state, NOT time in the waiting state.

Exercise 4

Now try both simulations again with a zero io wait time, indicated by putting a 0 after each file name on the command line, e.g., python srtfsim.py 0 &. What do you notice about process 23? Why? Check the process table dump at the end of each simulation run to confirm your theory.

Exercise 5

A zero wait time is not the same thing as having no io at all. Modify the initial data file to set all processes to have no io, and run the simulations again. Is the behaviour the same as for exercise 4, or not? (careful!) Why? Please explain.
Warning:This exercise should be completed only after all other basic sections have been completed, and are working satisfactorily.

Exercise 6

If you still have time, try some things for yourself. Explore changing the other parameters in the initial file, or you might care to extend the code to make it compute throughput (number of processes per unit time), and see how the two algorithms compare.
Now read on:
Warning:This exercise should be completed only after all other basic sections have been completed, and are working satisfactorily.

Exercise 7

As suggested in section 6, there is a more advanced Gantt chart module Gantt-gtk.py that generates a graphical version of the ASCII Gantt charts. Explore this module (you will need the python modules pygtk and gnome, as well as gtk and gnome themselves. I'm told that these exist under Windows (not Linux!) on the lab machines. Sorry, but I haven't had a chance to test this, so I would appreciate hearing about any experience that you gain.
Now read on:

11. Indices

11.1 Files Defined by this Document

File NameDefined in
RR.py8.1
SRTF.py7.1
initial9.10
rrsim.py9.2
srtfsim.py9.1

11.2 Macros Defined by this Document

Chunk NameDefined inUsed in
RR definitions8.2, 8.158.1
RR definitions8.2, 8.158.1
RR dispatch a process8.148.13
RR handle admit event8.78.5
RR handle create event8.68.5
RR handle dispatch event8.88.5
RR handle exit event8.128.5
RR handle interrupt event8.98.5
RR handle iocomplete event8.118.5
RR handle iowait event8.108.5
RR schedule process8.138.5
SRTF check if current process should be preempted7.137.7, 7.11
SRTF definitions7.2, 7.167.1
SRTF definitions7.2, 7.167.1
SRTF dispatch a process7.157.14
SRTF handle admit event7.77.5
SRTF handle create event7.67.5
SRTF handle dispatch event7.87.5
SRTF handle exit event7.127.5
SRTF handle interrupt event7.97.5
SRTF handle iocomplete event7.117.5
SRTF handle iowait event7.107.5
SRTF schedule process7.147.5
collect CLI values9.99.1, 9.2
compute simulation results9.69.5
define subroutines9.4, 9.59.1, 9.2
define the RR AddReady method8.48.2
define the RR HandleEvent method8.58.2
define the RR tick method8.38.2
define the SRTF AddReady method7.47.2
define the SRTF HandleEvent method7.57.2
define the SRTF tick method7.37.2
imports9.39.1, 9.2
run the RR simulation9.89.2
run the SRTF simulation9.79.1

11.3 Identifiers Defined by this Document

IdentifierDefined inUsed in
AddReady7.4
HandleEvent7.5
HandleEvent8.5
IOWaitTime7.2
LogEvent7.16
ReadyQ7.2
SRTF7.2
preemptTime7.2
read_simulation9.4
run_simulation9.5
running7.2
tick7.3

Document History

20080911:115102 2.0.0 ajh initial version for 2008

This page maintained by John Hurst.
Copyright Monash University Copyright Policy
1140 accesses since
14 Aug 2008
My PhotoTrain Photo

Generated at 20090704:1713 from an XML file modified on 20080918:1639
Maintainer use only; not generally accessible: Local ServerWork ServerCSSE Server

22 accesses since 09 Jul 2009, HTML cache rendered at 20091124:2248