     [file vers-uman.texi not included]

Learn how to operate SGPEMv2
****************************

This is SGPEMv2 User Manual (version VERSION, UPDATED).

Copyright © 2005-2006 University of Padova, dept. of Pure and Applied Mathematics

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.  A copy of the license is included in the section entitled ``GNU Free Documentation License''.

History
*******

2006, September 8th -- Matteo Settenvini
     Update chapters about building and installation. Rewrite some of the chapter about extending SGPEMv2 with custom CPU policies, and add a more complex example.

2006, September 7th --- Luca Vezzaro
     First attempt at expanding the manual structure with the stuff we'll need in the forthcoming beta testing

2006, March 10th --- Djina Verbanac
     Added chapter Writing new policies

2006, March 9th --- Djina Verbanac
     Add chapters Overview of SGPEM and Starting with SGPEM.

2006, January 26th --- Matteo Settenvini
     Add subsection about how to generate code documentation via Doxygen.

2005, December 11th --- Matteo Settenvini
     Added full license text.

2005, November 8th --- Matteo Settenvini
     First draft of this document.

Overview of SGPEM
*****************

Description and aims
====================

SGPEM is an Italian acronym, standing for ``Simulatore della Gestione dei Processi in un Elaboratore Multiprogrammato'' (in English, ``Process Management Simulator for a Multitasking Computer''). It was initially developed for use inside the ``Operating Systems'' teaching, part of the Computer Science course of the University of Padova, Italy. The aim of SGPEM is to provide an easy-to-use environment  for simulating process scheduling policies, and for assigning resources in a multitasking computer. SGPEMv2 is an educational software, and it can help students to better understand the functionality of operating systems.

How to read this manual?
========================

We recommend that you read the manual following the the structure that we layed out for it. You will be gently led trough Installation, Configuration and Usage of SGPEMv2. If you find yourself in trouble reading the manual, please don't hesitate to contact us at swe@thgnet.it.

Reporting Bugs
==============

We welcome bug reports and suggestions for any aspect of the SGPEM v2 system, program in general, documentation, installation... anything. Please email us at swe@thgnet.it. For bug reporters, include enough information for us to reproduce the problem. In general:

  * version and number of SGPEM v2.

  * hardware and operating system name and version.

  * the content of any file neccesary to reproduce the bug.

  * description of the problem and any erroneous output.

  * any unusual option you gave to configure.

  * anything else you think might be helpful.

If you are ambitious you can try to fix the problem yourself, but we warmly recommend that you read the Developer Manual first.

Features
========

Main features are:

  * For now you can use only prompt commands to start the simulation and change some parameters. For more information see SGPEM Commands.

  * You can use the program from your own shell, or if you prefer you can use the minimal GUI that SGPEM offers, at this moment.

  * The output of the simulation is textual, and you can see it on the main GUI window or on your Terminal window.

  * The policy in use is First Come First Served.

  * You can write your own policies. For more information see Writing new policies.

Installation
************

Prerequisites
=============

Some software is needed in order to build and install SGPEM on your personal computer. You will have the need of different pieces of software installed, whether you are a developer, a user building it from sources, or just a user that's running the binary a packager has given to him.

And if you find this section misses something / it lists the wrong version of a program, please let us know!

Runtime dependencies
--------------------

To run SGPEMv2, you require:

Gtkmm >= 2.8 with Cairo support
     The popular C++ jacket for the even-more popular GIMP ToolKit. We use Cairo to draw our custom widgets.

Python >= 2.3
     We use Python to let the user write her own policies in a simple and complete language.

libXML2 >= 2.6.10
     An XML library we use to save and load files to/from disk.

Building from source
--------------------

Other than the runtime dependencies, you'll need:

SWIG >= 1.3.21
     SWIG generates the C++ sources needed to build a module that Python can use, starting from a simple interface specification.

Developers
----------

Other than the tools needed by users building from sources, you'll need:

GCC with C++ support
     as well as the other standard GNU binutils and tools: make, sed, ld... GCC version >=3.4 is highly recommended. Please don't report compiling-related problems with any previous version. There are some known issues with certain versions of GCC 4.0. See Building.

Automake >= 1.9
     We use a single Makefile.am to avoid recursive make. Older versions of automake didn't play right with it. See http://aegis.sourceforge.net/auug97.pdf for the motivations that led to this choice.

Autoconf, libtool, autopoint ...
     The standard autotool family.

Subversion >= 1.2
     If you need to update the sources from our repository, or commit your changes, you'll need Subversion built with SSL support.

Dejagnu >= 1.4
     The testsuite framework we use as a platform for running tests.

Building
========

To ensure a clean build, follow these steps:

     cd <the package root directory>
     mkdir =build
     cd =build
     CXXFLAGS="what you want" ../configure --prefix=/usr/local

This will check you have all the needed software installed.

Choose good CXXFLAGS to optimize your build. For example, on my machine, I would use:

     CXXFLAGS="-O3 -pipe -march=pentium4" ../configure --prefix=/usr/local

Being a developer, though, if I had to debug SGPEM, I would type:

     ../configure --prefix=`pwd`/../=inst --enable-debug

Please note that those around ``pwd'' are backticks, and not normal apostrophes.

Warning: at the moment, we are aware that passing --disable-shared to configure doesn't work. We'll look into it sooner or later, but in the meantime just build shared libraries.

Once succesfully configured SGPEMv2, just type:

     make

Some versions of GCC 4, usually those before the 4.1 series, present some problems with the newly-added visibility support for DSO object symbols. For example, OpenSuSE 10.0 is known to have such issues. If you encounter problems during building and in linking stage about unresolved symbols in libraries, please re-run configure  with the --disable-visibility-support option. You'll then have to run make clean && make.

Upon a succesful build, you can install SGPEMv2 just by hitting:

     su -c "make install"

Root password will be required (of course, if you're installing it with a prefix placed inside your home directory, you won't need administrative rights, and just ``make install'' will sufficit).

See the ``INSTALL'' file in this folder for an overview of other (less common) autoconf options.

Generating API documentation
----------------------------

We added Doxygen support to the project. If you've installed it, you can simply run make apidox from the package top source directory. The documentation will be outputted into the ${BUILD_DIR}/docs/API/ dir.

If you'd like to generate nicier inheritance graphs, you've just to install dot, part of the Graphviz package. If you didn't have it previously installed, you may need to re-run configure.

Basics
******

Policies
========

What is a policy in SGPEM?
--------------------------

What kind of policies are there?
--------------------------------

Built-in policies
-----------------

The Scheduler
=============

Using SGPEM
***********

From the GUI
============

Overall view of the main window
-------------------------------

The Schedulables/Requests tree
------------------------------

The Resources list
------------------

The Simulation widget
---------------------

The Holt graph
--------------

The Preferences dialog
----------------------

Controlling the simulation
--------------------------

From the commandline
====================

SGPEM Commands
--------------

help <string>
     If <string> is a valid command, it prints the usage instructions for that specific command

run
     Advances the simulation by one or more steps, depending on the actual state and on the value set ed with setmode

pause
     It is useful only when the advancement mode is continue. Calling again run will cause the simulation to start from the current simulation step.

stop
     Stops the simulation.

setmode <bool>
     This methods allows to change the way the simulation progresses. If the input value is 0 (false), the simulation will advance a single time step for each call to run. If the input value is 1 (true), the simulation will advance contiuosly, waiting the time defined with settimer between each step, until all processes terminate, or some error occurs.

getmode
     Prints the simulation advancement mode: 0 if step-to-step, 1 if continue.

settimer <int>
     This command is used to define how a single time unit is to be interpreted when the simulation advancement mode is continue. The input value is in milliseconds, and it must be in range [0, 10000].

gettimer
     Prints the value of the current timer

reset
     Resets the simulation.Erases the state of the simulation, and takes care of removing any residual or temporary data to ensure the simulation has reached a clean and stable state.

jumpto <int>
     Causes the simulation to jump to a given time unit.

getpolicy
     Prints the current policy.

getpolicyattributes
     Prints the name and the value of the policy's attributes

SGPEM Output
------------

You can see the textual output of the simulation in your console window or on the GUI window provided with SGPEM v2. The output of RUN gives you one or more rows, each one representing the state of schedulable entities. The possible states are: RUNNING, READY, BLOCKED, FUTURE or TERMINATED. The row begins with the number of the instant described by the following lists of states:

  * instant 0 - represents the INITIAL STATE during which no process is running.

  * instant 1 - the scheduler activity begins.

Each schedulable entity is represented by its name followed by its priority enclosed between round parenthesis.

Extending SGPEM
***************

Writing new policies
====================

All built-in policies are implemented in Python, but don't worry: you don't have to be a Python expert to write a new policy. We'll explain you how to write a new policy on an simple example of FCFS policy. Then a more complex example will follow: a Round Robin policy that uses pre-emption by priority.

Now let's get started, all you have to do to create your own policy is to change the few bold lines of the following example. Also remember that the name of the class have to be the same of the name of the file (minus the .py file extension, of course).

A beginner example: First Come First Served
-------------------------------------------

     01 from CPUPolicy import CPUPolicy
     02 class fcfs(Policy) :
     03     def __init__(self):
     04         pass;

     05     def configure(self):
     06         print 'No options to configure for fcfs'

     07     def is_preemptive(self):
     08         return False

     09     def get_time_slice(self):
     10         return -1

     11     def sort_queue(self, event, queue):
     12         cmpf = lambda a, b: \
                   a.get_schedulable().get_arrival_time() <= \
                   b.get_schedulable().get_arrival_time()
     13         self.sort(queue,cmpf)

body of def configure(self): line 06

     Configure policy to initial values. This is called just before a simulation starts, and it is responsible to define the parameters the policy wants to expose to the user. For example, it may make the return value returned by is_preemptive() configurable, or to register an integer value for a the time slice duration.

body of def is_preemptive(self): line 08

     It says whether the policy wants to be preemptive, other than by normal time slice termination (if a positive time slice has been provided).

     The possible return values are:

      1. True: If the policy returns True, it declares that it wants the running thread to be released if a thread at higher priority is put at the beginning of the ready threads queue.

          This is achieved by putting the current running thread, if there is one, onto the ready queue. It is up to you, into the sort_queue() method, to manage this special case.

      2. False: The policy always waits the end of the time slice (or a thread blocking/termination) before selecting a new running thread, even if it has greater priority than the current one.

          There will never be a running thread in the ready queue passed to sort_queue().

     Please note how the word ``priority'' here has a general meaning: it indicates every thread than can bubble up the sorted ready queue and come before another. So it's up to Policy.sort_queue() to give it a precise meaning.

body of def get_time_slice(self): line 10

     Returns how long is a time-slice for this policy. A time sliced policy should return a positive integer value, a policy which doesn't use slices should instead return -1. You're encouraged to use a user-configurable parameter via Policy.configure() if the policy is time-sliced, to ensure greater flexibility.

body of  def sort_queue(self, event, queue): line 12,13

     Sort the queue of ready threads. This method is called by the scheduler at each step of the simulation to sort the ready threads queue. It is the core of your policy: when scheduler has to select a new thread it will always try to take the first of the queue. If it cannot run for some reason (for example, it immediately blocks), the second is selected and so on, until the end of the queue.

     Remember that if is_preemptible() returns True, you may have a running thread in the queue. See the following example for some tips about how to manage this case.

     Pay attention to the fact that we used the <= relation at line 12, and not a simple <. This is because queue.sort() uses a in-place implementation of quicksort, which is stable only when employed with a minor-or-equal relation. Otherwise the queue would be sorted, but two adjacent threads that have the same value for a given priority would be swapped. If your policy behaves strangely, this may be the cause.

Exposed interface: what you can use
-----------------------------------

Configuring parameters
......................

TODO: list and describe all methods exposed from PolicyParameters.

Methods for manipulating the ready queue
........................................

TODO: list and describe all methods exposed from ReadyQueue.

Properties of schedulable entities
..................................

TODO: list and describe all methods exposed from Schedulable, Thread and Process

A more complete example: Round Robin with priority
--------------------------------------------------

Now, let's see a more interesting (and a little more complex) example: a Round Robin by priority policy that can optionally also work with pre-emption by priority.

     00  from CPUPolicy import CPUPolicy
     01
     02  class rr_priority(CPUPolicy) :
     03     """Round Robin scheduling policy that takes priority in account.
     04
     05  No lower priority thread can run if a higher
     06  priority thread exists. If pre-emptive by priority, a
     07  higher-priority thread becoming ready even in the middle
     08  of a time slice will pre-empt the running thread. Else,
     09  the time slice will have to end before the former can run."""
     10
     11     def __init__(self):
     12         pass;
     13
     14     def configure(self):
     15         param = self.get_parameters()
     16         param.register_int("Time slice", 1, 10000, True, 2)
     17         param.register_int("Is preemptive?", 0, 1, True, 1)
     18
     19     def is_preemptive(self):
     20         value = self.get_parameters().get_int("Is preemptive?")
     21         if value == 0:
     22             return False
     23         else:
     24             return True
     25
     26     def get_time_slice(self):
     27         return self.get_parameters().get_int("Time slice")
     28
     29     def sort_queue(self, queue):
     30         by_ltime = lambda a, b: \
     31             a.get_last_acquisition() <= \
     32             b.get_last_acquisition()
     33         by_prio = lambda a, b: \
     34             a.get_current_priority() <= \
     35             b.get_current_priority()
     36
     37         self.sort(queue,by_ltime)
     38         self.sort(queue,by_prio)
     39
     40         # manage preemption: see if we've a running thread
     41         # in the ready queue, and if it can still run
     42         if self.is_preemptive() == True:
     43             higher_prio = queue.get_item_at(0).get_current_priority()
     44             i = 0
     45             while i < queue.size():
     46                 sched = queue.get_item_at(i)
     47                 priority = sched.get_current_priority()
     48                 if(priority != higher_prio):
     49                     break
     50                 if sched.get_state() == "running":
     51                     queue.bubble_to_front(i)
     52                 i += 1

We've also added a description of the class immediately following the class declaration (lines 03-09). This is what is returned as the policy description in the frontend. You may want to document your policies in the same way too.

Now, let's see the most complex parts together:

configure()

     There are three types of parameters you can register in the value returned by self.get_parameters(), and they are integer parameters, float parameters and strings. Usually boolean values can be simulated by registering a integer parameter limited in the interval [0, 1]. See Configuring parameters for the exposed interface.

is_preemptive()

     TODO: write me

sort_queue()

     Here there are quite a lot of things going on, so let's tackle them one by one.

     At line 30 we create a lambda-function that says to sort the queue by last aquisition time, so that threads that have been aquired recently end up at the back of the queue (which is exactly what a Round Robin policy should do).

     Then, at line 33, we create another lambda-function, this time because we want to sort the queue by priority, too.

     Done this, we let quicksort do the hard job at lines 37-38.

     Since we may have pre-emption enabled, we may have a running thread on the ready queue (if one exists at the current instant). But what happens if the running thread was put in the queue, and we just sorted it?

     Unfortunately, having the greatest last aquisition time, the running thread would end at the back of the queue, thus never being selected to run for more than a single time unit if the queue is non-empty and there are other threads with the same priority!

     The solution is to check if there is a thread with state ``running'' at the beginning of the queue, between those that have the same priority. If there's one, we make it bubble to the top of the queue.

     This is the explanation for lines 42-52.

Writing plugins
===============

TODO: write me

     [file fdl.texi not included]