Round-robin CPU scheduling emulator

dvanhorn <[email protected]>
Newsgroups gmane.org.ballistichelmet.lambda
Message-ID <[email protected]>
There has got to be a better way to run this than with this silly shell
interpreter business.  After all, this is a strongly typed language; let's
compile the goddamn thing.  Unfortunately the interpreter was easier to do
than actually reading to docs for ocamlc to figure out how to set an entry
point for the module (if that is indeed the way to do it).  So anyway, to
create the interp do:

  ocamlmktop -custom -o mocaml str.cma

(str.cma is need for regular expressions.)  Change the #! at the start of this
file to point to the mocaml file you just created.  Make sure the privleges on
rr.ml include execute.  Then do:

  ./rr.ml <file>

There is something nice about writing an ML program: you know when you're
done.  It's like the feeling that comes with fitting the last peice into place
on a jigsaw puzzle.

This file should be available at:

   http://www.cs.uvm.edu/~dvanhorn/ocaml/os/rr.ml

-d

----rr.ml----

#!/home/cs/csugrads/dvanhorn/local/bin/mocaml

(**
   Round-robin CPU scheduling emulator

   Copyright (c) 2003 David Van Horn
   Licensed under the Academic Free License version 2.0

   A work of art is a machine with an aesthetic purpose.
   -- James Boyk

   This program simulates the events in a multiprogrammed computer system
   according to the following guidelines: Round-Robin scheduling is used.
   Time Slice = 5.  The number of processes is unbounded.  A counter
   implements the logical clock.  At each increment of the counter the program
   checks if the current counter value (time) matches with an arrival time of
   any process, and enter arriving process(es) automatically into the tail of
   the ready queue.  If a process finishes completely then it leaves the
   system, and the process at the head of the ready queue is allocated the
   CPU.  If time slice is expired and the process does not finish then the
   process is inserted into the tail of the queue, and a process (possibly the
   one just inserted) at the head of the queue is allocated the CPU.

   Simulation will continue until all processes finish completely.  An input
   file includes information for all processes, their arrival times, and a
   CPU-burst.  Input lines are of four possible formats (Assume that there is
   exactly one line of input for CPU burst):

   BEGIN <process number (<=10)> <arrival time>
   CPU <CPU burst>
   END /* Process description ends */

   The following is an example:

   BEGIN 1 0
   CPU 7
   END
   BEGIN 2 5
   CPU 4
   END

   The program reports which process executes as there occurs a change, or at
   the beginning of every time slice.  For example see the output below for
   the input given above.  Events are reported in the following format:

   TIME: 0 PRO 1 EXEC
   TIME: 5 PRO 2 EXEC
   TIME: 9 PRO 1 EXEC

   @author David Van Horn
*)

module Rr =
  struct
    open List
    open Printf
    open Str

    (**
       A process (or PCB) is either the null process or consists of a process
       number, an arrival time, and burst time.
    *)
    type process =
      | Process of int * int * int
      | NullProcess	

    let arrive_now_p t = function
      | Process(_,a,_) when a=t -> true
      | _ -> false

    let time_slice = 5
	
    let print_event t p =
      printf "TIME %d PRO %d EXEC\n" t (match p with Process(n,_,_) -> n)

    (**
       The step function transitions from machine configuration to machine
       configuration.  A machine configuration is a 5-tuple consisting of a
       queue of processes that have arrived and are waiting to be swapped into
       the cpu, a process that is currently running on the cpu, the current
       time, the time slice for current process, and a list of process that
       have yet to arrive.
    *)
    let step (q,p,t,s,j) =

     (*
	We push all processes that are scheduled to arrive at the current time
	onto the queue.
     *)
      let q = append q (filter (arrive_now_p t) j) in

     (*
	We remove from the list of processes that have yet to arrive those
	processes which are scheduled to arrive at the current time.
     *)
      let j = filter (fun x -> (not (arrive_now_p t x))) j in

      match (q,p,t,s) with
	
      (*
	 If the queue is empty and the null process is currently executing
	 (the cpu is idle), we have nothing to do, so increment the time and
	 continue.
      *)
      | [], NullProcess, t, s -> [], NullProcess, t+1, s, j

      (*
	 If the queue is non-empty and the null process is currently executing
	 (the cpu is idle), we take the next process from the queue and swap
	 it into the cpu (reseting the time slice).  This operation does not
	 increment the time.
      *)
      | p::q, NullProcess, t, _ ->
	  print_event t p;
	  q, p, t, time_slice, j
	
      (*
	 If the currently executing process has exhausted its burst time, the
	 cpu becomes idle.  This operation does not increment the time.
      *)
      | q, Process(n,a,0), t, s -> q, NullProcess, t, s, j

      (*
	 If the currently executing process has exhausted its time slice, the
	 cpu becomes idle and the process is pushed onto the queue.  This
	 operation does not increment the time.
      *)
      | q, p, t, 0 -> q@[p], NullProcess, t, 0, j

      (*
	 If the current process has burst time remaining and time slice
	 remaining, we let the cpu continue to run the process, decrementing
	 the burst and time slice and incrementing the time.
      *)
      | q, Process(n,a,b), t, s -> q, Process(n,a,b-1), t+1, s-1, j

    let parse file_name =
      let in_channel = (open_in file_name) in
      let rec loop ps =
	try
	  match (split (regexp "[ \t]+") (input_line in_channel)) with
	  | ["BEGIN"; n; i] ->
	      let burst =
		match (split (regexp "[ \t]+") (input_line in_channel)) with
		| ["CPU"; b] -> (int_of_string b)
	      in
	      loop ((Process(int_of_string n, int_of_string i, burst))::ps)
	  | ["END"] -> loop ps
	with End_of_file -> ps
      in
      loop []
	
    (**
       A machine runs until it is in a final configuration, which is defined
       as a configuration with no processes in the waiting queue, an idle cpu,
       and no processes yet to arrive.
    *)
    let main file_name =
      let rec loop = function
	| [], NullProcess, _, _, [] -> ()
	| state -> loop (step state)
      in
      let proc_list = parse file_name in
      loop ([], NullProcess, 0, 0, (parse file_name))

end
;;

Rr.main(Sys.argv.(1));;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.