Rev 418 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
/*******************************************************************************
* Scheduler.java
*
* Holds the Scheduler class, which has a generic scheduler class, from which
* all schedulers should be derived.
*
* Copyright (c) 2006, Ira W. Snyder (devel@irasnyder.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
******************************************************************************/
import java.util.Vector;
/**
* Base class for all of the specific Schedulers used in Project #1.
*
* @class CS431 Fall 2006
* @author Ira W. Snyder (devel@irasnyder.com)
*/
public abstract class Scheduler
{
/** The Processes currently waiting to enter the scheduler */
protected Vector<Process> waiting_queue;
/** The Processes that can currently be scheduled */
protected Vector<Process> run_queue;
/** A log of important transitions in the Scheduler */
protected Vector<LogEntry> log;
/** The current time in this scheduler */
protected int cur_time = 0;
/** The process that is currently running on the CPU */
protected Process cur_proc;
/**
* Constructor of the Scheduler class.
*/
public Scheduler ()
{
this.waiting_queue = new Vector<Process> ();
this.run_queue = new Vector<Process> ();
this.log = new Vector<LogEntry> ();
}
/**
* This method must be overridden by an implementer of a Scheduler. It
* will implement the specific behaivior of the specific Scheduler that
* is being implemented.
*
* @return true if we have more things to do, false if we are done
*/
protected abstract boolean step ();
/**
* Add a new process to the run queue.
* <p>
* If you need to support time-delayed processes, then you must override
* this method, and handle pulling them into the run_queue yourself.
*
* @param proc the Process to add
* @param add_time the time that this process should be added to the run queue
*/
public void addProcess (Process proc, int add_time)
{
waiting_queue.add (new Process (proc.name, proc.timeslice, add_time));
}
/**
* Expire the currently running process.
* <p>
* This removes the current process from the CPU and re-adds it to the
* run_queue. It also logs the expiration.
*/
protected void expireCurrent ()
{
assert (cur_proc.time_left > 0);
cur_proc.finished_at = cur_time;
run_queue.add (cur_proc);
log.add (new LogEntry (cur_proc, cur_time, LogEntry.MsgType.EXPIRE));
cur_proc = null;
}
/**
* Terminate the currently running process.
* <p>
* This should be called if the process has no time left to run.
*/
protected void completeCurrent ()
{
assert (cur_proc.time_left == 0);
cur_proc.finished_at = cur_time;
log.add (new LogEntry (cur_proc, cur_time, LogEntry.MsgType.COMPLETE));
cur_proc = null;
}
/**
* Move a process from the run_queue to the CPU. This removes it from the
* run_queue. Then it adds a log entry.
*
* @param proc move this process from the run_queue to the CPU
*/
protected void startProcess (Process proc)
{
cur_proc = proc;
run_queue.remove (cur_proc);
log.add (new LogEntry (cur_proc, cur_time, LogEntry.MsgType.START));
}
/**
* Run the current process, increment the current time, and update the wait
* times for all of the processes that are waiting.
*/
protected void scheduleCurrent ()
{
/* Update the wait times for all waiting processes */
for (Process p : run_queue)
p.time_wait++;
/* Run the current process for one tick */
cur_proc.time_left--;
/* Update the time */
cur_time++;
}
/**
* Pull any Process that was delayed into the Scheduler if it is the
* appropriate time.
*/
protected void queueWaitingProcesses ()
{
Vector<Process> wq_clone = (Vector<Process>)waiting_queue.clone ();
for (Process p : wq_clone)
if (p.entered_at == cur_time)
{
run_queue.add (p);
waiting_queue.remove (p);
log.add (new LogEntry (p, cur_time, LogEntry.MsgType.ADDED));
}
}
/**
* Check if the Scheduler is finished running.
*
* @return true if the scheduler is finished, false otherwise
*/
protected boolean schedulerFinished ()
{
if (cur_proc == null && run_queue.isEmpty() && waiting_queue.isEmpty())
return true;
return false;
}
/**
* Print a Gantt Chart detailing the results of this scheduler's run.
*/
protected void printGanttChart ()
{
GanttChart gc = new GanttChart (log);
gc.printGanttChart ();
}
/**
* Find the average wait time of processes.
*/
protected void printWaitTimes ()
{
int numprocs = 0;
int totalwait = 0;
for (LogEntry e : log)
{
if (e.msg == LogEntry.MsgType.COMPLETE)
{
numprocs++;
totalwait += e.proc.time_wait;
}
}
System.out.printf ("Average wait time: %d wait time / %d procs = %.2f\n",
totalwait, numprocs, (float)totalwait / (float)numprocs);
}
/**
* Find the average turnaround time of this scheduler.
* <p>
* Turnaround time is defined as the mean time from submission
* until completion of a process.
*/
protected void printTurnaroundTimes ()
{
int totalturnaround = 0;
int totalprocs = 0;
for (LogEntry e : log)
{
if (e.msg == LogEntry.MsgType.COMPLETE)
{
totalturnaround += (e.proc.finished_at - e.proc.entered_at);
totalprocs++;
}
}
System.out.printf ("Average Turnaround time: %.2f\n",
(float)totalturnaround / (float)totalprocs);
}
/**
* Run the simulation of the scheduler. Note that this only works once,
* if you try to run it twice, it is unlikely that it will work.
*/
public void run ()
{
/* Keep step()ing until we're done */
while (step ())
; // do nothing
/* Verbose print of each log entry */
//for (LogEntry e : log)
// System.out.println (e);
/* Gantt Chart */
printGanttChart ();
/* Print time taken */
printWaitTimes ();
printTurnaroundTimes ();
System.out.println ("Simulation took " + cur_time + " time units to complete!");
}
}
/* vim: set ts=4 sts=4 sw=4 expandtab: */