Programming Assignment III
The simulation consists primarily of jobs, devices, and schedulers.
The jobs arrive at the system from the trace file and are scheduled to
use the system devices (the CPU and the disk). The amount of computing
a job wants to do before performing disk I/O or finishing execution is
called a burst. The program cycles through waiting for devices to
interrupt and then handling those interrupts -- which could entail removing
a job from a device and scheduling it with another device or discarding
a job that has finished. In the picture below, the Main Loop waits for
a device to interrupt. When it does, the Main Loop removes the job from
that device and either reschedules it with the same device (as in the case
of a clock interrupt), or it removes the current job from the device and
enqueues it with another.
object represents a customer of services. It records the job's
current state and maintains statistics about its lifetime. One Job is
created from each line of the input trace file, and a Job object spends
its lifetime being passed between
The resources required by a Job are characterized by an amount CPU time
needed (all times are in milliseconds) and the number of I/O operations
needed (each representing one disk transfer of Sim.BLOCKSIZE bytes of data).
The CPU time is generally distributed as evenly as possible into uniform
bursts between I/O operations (unless the job does no I/O at all); however,
occasionally a little randomness is injected into the system, and the CPU
burst is less than or greater than expected.
- Attributes of a Job Object
- Information about the starting state of the job
- time of arrival
- total amount of CPU time needed (in milliseconds)
- total number of I/O operations needed
- Information about the current state of the job
- total CPU time remaining
- number of I/O operations remaining
- the length of the current burst
- the time when the job started the current burst
arrived or became ready
- the amount of time remaining in the current
- time the job last started using the CPU
- Pointer to another Job object (allows Jobs to be chained together in
a linked-list fashion)
- Methods of a Job Object
- Constructor will read in a line from the file and initialize the job
- void start() starts the job running on
the CPU (sets up the start time)
- void stop() stops the job running on the
CPU (updates remaining CPU times)
- int nextBurst() returns burst time remaining
- void doIO() does an I/O operation (updates
- JobStats finish() completes the job (returns
- int state() returns the current state
- DONE - Job has completed
- BLOCKED - Job is waiting for I/O
- READY - Job is ready to execute on the
object represents a resource such as the Disk, the Clock, or
the CPU. It can be running or stopped; however once started, it will
at some time in the future. The Device object keeps track of the current
device state as well as at what time the next interrupt will occur.
monitors devices closely for their interrupts, and
when one occurs, Sim.mainLoop() advances its current time to the interrupt
time, stops the device, and does what an ``interrupt handler''
for the device would do.
- current job (if running)
- time of the next interrupt (Integer.MAX_VALUE
if not running)
- time last started running
- total time device has been running
- void start(Job, amount) starts the device
running and determines next interrupt time
- Job stop() stops the device and returns
the current job running
- int nextInterrupt() returns time of next
- boolean isBusy() returns whether the device
is currently running
- void printStats() prints the percentage
utilization of this device (time active / total time)
exist for the CPU and the Disk and schedule Jobs seeking
service from a device. They maintain a queue of waiting jobs
and determine which of those jobs will be the next to access the device.
(Job objects contain pointers to other Job objects -- these can be used
to create the Job lists.) The
default CPU scheduler
uses a Round-Robin (RR)
algorithm to determine the next job to run; the
uses a simple FCFS queuing algorithm.
base class presents a uniform
interface for the scheduling of Jobs. It also maintains statistics about
the queue length of the scheduler.
is the provided CPU scheduling class (you will
create the others). It maintains its Jobs in a simple FIFO queue and always
chooses the Job at the front of the queue for the next CPU access.
The reschedule() method always returns true
because jobs are always rescheduled at the end of a quantum,
and the add()
method always returns false because jobs are not preempted by
- boolean add(Job) adds a new job
wanting service. It returns true if the currently running job
should be preempted in favor of one of the queued jobs (probably the
one just added).
- Job remove() returns the next job the scheduler has decided to
run (and removes it from the queue).
- boolean reschedule(Job job) is called on a clock
interrupt. It returns true if there is a reason to stop the current
job and run another instead.
The argument is the current job.
- printStats() prints
queue statistics (maximum length, average length, percent of time spent
at the various lengths)
DiskScheduler: You don't need to worry about the disk scheduler
for this assignment. In brief, it maintains a FIFO queue of jobs and
will provide access to the disk in a FCFS (First Come First Served) order.
- CPU device being scheduled
- clock device for time slicing
- pointer to the last Job in a circular queue
- void add(Job) adds a job to the end of
- Job remove() retrieves and removes the
job most recently served
- Job first() returns the first job in the
queue without removing it
- boolean reschedule() returns true
only if there is at least one other job waiting
The main loop (found in
cycles waiting for interrupts from the various devices. When one occurs,
the loop handles it as described earlier. The picture below shows the main
loop waiting on the various types of devices that can interrupt.
An informal trace of the main loop's code follows:
- Create devices for Job Arrival, CPU, Disk, and Clock.
- Create Schedulers for CPU and Disk.
- Determine which device interrupts next and the time of the interrupt
- If the time of the interrupt is ``infinity,'' terminate the simulation.
- Update the current time
- Stop the device
- If the interrupt is a ....
- Job Interrupt: Remove the job from the JobArrival device,
schedule it with the CPU or Disk Scheduler, and get the next job from the trace
- Disk Interrupt: Remove the job from the Disk and reschedule
it with the CPU or Disk Scheduler (if job is not finished).
- CPU Interrupt: Remove the job from the CPU and reschedule
it with the Disk Scheduler (if job is not finished).
- Clock Interrupt: Ask the CPU Scheduler if it wants to preempt
the current job. If so, remove that job from the CPU and return it to
the CPU scheduler.
- In any case, if any device is idle, try to get a job from the associated
scheduler and start the device running servicing that job.
The simulation is driven by a trace file generated from
an actual Unix system.
The lines of the trace file are sorted by program starting time and are
of the form:
- CommandName: Character string name of the program.
- StartTime: Time in 10 millisecond increments (100ths of a second)
since midnight - this is the time that the program arrived in the system.
- CPUTime: Total CPU time, in seconds, used by this program.
- IOCount: Records the total number of bytes of disk I/O done
by this program. Disk I/O always occurs in full blocks, with blocks being
1K (1024 bytes). The number of disk operations required for a job is IOCount/Sim.BLOCKSIZE
Trace File Example:
sendmail 6724 0.00 6144
df 7509 0.11 447
sh 9888 0.05 1384
ksh 9890 0.06 942
ransleep 9891 0.03 186
sendmail 10325 0.02 6144
condor_v 10647 0.23 23768
Statistics and Debugging Output
On termination, the simulation prints are large number of statistics
about the run, including
A log of significant events is also provided if the -v flag
is included on the command line.
The -v may be repeated.
One -v traces job arrivals and departures.
Two -v's adds events when jobs become blocked or ready.
Three -v's call for a trace of all events, including clock interrupts.
It also causes jobs to be indicated in a more verbose format:
- The utilization of each device.
- Information about each scheduler queue, including the maximum and
average queue lengths, and the percentage of the time it had various
- Information about jobs, including the number of jobs run and throughput,
and summary statistics (min, max, and mean) about the per-job
elapsed time, CPU time, I/O operations, and penalty ratio.
- Information about burst waiting times (elapsed time of the burst
minus duration of the burst). Waiting time includes both queuing delay
(time the burst sits in the CPU Scheduler queue) and scheduling overhead
(2ms for each process switch, in this simulation).
indicates that job tcsh, which was the third job to arrive,
arrived at time 0:00:00.080 (zero hours, zero minutes, zero seconds,
and 1000 milliseconds after start-up). It needs a total of 3.5 seconds
of CPU time, of which 3.266 seconds remain.
The current burst has 234ms of time remaining.
Of a total of 15 I/O operations, 14 remain.
Four -v's prints all queues each time around the main loop.
The -t option requests a trace of significant events for each
job (printed when the job terminates) and for each device (printed
at the end of the simulation).
This option slows the simulation considerably, so you might want
to use a shortened version of the data file.
Sun Nov 23 08:49:20 CST 1997
Copyright © 1996, 1997 by Marvin Solomon. All rights reserved.