simpylogo SimPy Cheatsheet

Author: Tony Vignaux <Vignaux@users.sourceforge.net>,
Author: Klaus Muller <Muller@users.sourceforge.net>
Date: 2005-June-6
SimPy version:1.6
Web-site:http://simpy.sourceforge.net/
Python-Version:2.2, 2.3, 2.4

SimPy

This document outlines the commands available in version 1.6 of SimPy. Python 2.2 or later is required. (When using Python 2.2, the following import statement must be used at the head of SimPy scripts: from __future__ import generators)

A SimPy model is made up of Processes, Resources and Monitors and operations on them.

Basic structure of a SimPy simulation:

now() always returns the current simulation time and stopSimulation() will stop all simulation activity.

Processes

Processes inherit from class Process, imported from SimPy.Simulation.

Starting and stopping SimPy Processes

By the process itself:

  • yield passivate,self suspends the process itself.

By other processes:

  • activate(p,p.execute(args),at=t,delay=period,prior=boolean) activates the execution method p.execute()* of Process p with arguments args. The default action is to activate at the current time, otherwise one of the optional timing clauses operate. If prior==True, the process will be activated before any others in the event list at the specified time.
  • reactivate(p,at=t,delay=period,prior=boolean) will reactivate p after it has been passivated. The optional timing clauses work as for activate.
  • self.cancel(p) deletes all scheduled future events for process p. Note: This new format replaces the p.cancel() form of earlier SimPy versions.

Asynchronous interruptions

  • self.interrupt(victim) interrupts another process. The interrupt is just a signal. After this statement, the interrupting process immediately continues its current method.

    The victim must be active to be interrupted (that is executing a yield hold,self,t) otherwise the interruption has no effect.

    The introduction of interrupts changes the semantics of yield hold. After before=now(); yield hold,self,T, we have the post-condition now()== before+T OR (self.interrupted() AND now()< before+T). The program must allow for this, i.e., for interrupted, incomplete activities.

    When interrupted, the victim prematurely and immediately returns from its yield hold. It can sense if it has been interrupted by calling:

  • self.interrupted() which returns True if it has been interrupted. If so:

    • self.interruptCause gives the interruptor instance.
    • self.interruptLeft is the time remaining in the interrupted yield hold,

    The interruption is reset at the victims next call to a yield hold,. Alternatively it can be reset by calling

  • self.interruptReset()

Advanced synchronisation/scheduling capabilities

These include signalling between processes using events and a general wait-until command.

Signalling between processes

Events in SimPy are implemented by class SimEvent. A new event, myEvent, is generated by:

myEvent=SimEvent("MyEvent").

Associated with a SimEvent are

  • a boolean occurred to show whether an event has happened (has been signalled)
  • a list waits, implementing a set of processes waiting for the event
  • a list queues, implementing a FIFO queue of processes queueing for the event
  • an attribute signalparam to receive an (optional) payload from the signal method

Processes can wait for events by issuing:

yield waitevent,self,<events part>

<events part> can be:

  • an event variable, e.g. myEvent)
  • a tuple of events, e.g. (myEvent,myOtherEvent,TimeOut), or
  • a list of events, e.g. [myEvent,myOtherEvent,TimeOut]

Processes can queue for events by issuing:

yield queueevent,self,<events part> (with <events part> as defined above)

If one of the events in <events part> has already happened, the process continues. The occurred flag of the event(s) is toggled to False.

If none of the events in the <events part> has happened, the process is passivated after joining the FIFO queue of processes queuing for all the events.

The occurrence of an event is signalled by:

<event>.signal(<payload parameter>)

The optional <payload parameter> can be of any Python type.

When issued, signal causes the occurred flag of the event to be toggled to True, if waiting set and and queue are empty. Otherwise, all processes in the event's waits list are reactivated at the current time, as well as the first process in its queues FIFO queue.

"wait until" synchronisation -- waiting for any condition

A process can wait for an arbitrary condition by issuing:

yield waituntil,self,<cond>

where <cond> is a reference to a function (without parameters) which returns the state of the condition to be waited for as a boolean value.

Resources

The modeller may define Resources. These inherit from class Resource which is imported at the start of the program: from SimPy.Simulation import Resource

A Resource, r, is established using the command:

A Resource, r, has the following attributes:

A unit of resource, r, can be requested and later released by a process using the following yield commands:

Requesting resources with priority

If a Resource, r is defined with priority queueing (that is qType==PriorityQ) a request can be made for a unit by:

  • yield request,self,r,priority, where priority is real or integer. Larger values of priority represent higher priorities and these will go to the head of the r.waitQ if there not enough units immediately.

Requesting a resource with preemptive priority

If a Resource, r, is defined with priority queueing (that is qType=PriorityQ) and also preemption (that is preemptable=1) a request can be made for a unit by:

  • yield request,self,r,priority, where priority is real or integer. Larger values of priority represent higher priorities and if there are not enough units available immediately, one of the active processes may be preempted.

If there are several lower priority processes, that with the lowest priority is suspended, put at the front of the waitQ and the higher priority, preempting process gets its resource unit and is put into the activeQ. The preempted process is the next one to get a resource unit (unless another preemption occurs). The time for which the preempted process had the resource unit is taken into account when the process gets into the activeQ again. Thus, the total hold time is always the same, regardless of whether or not a process gets preempted.

Reneging -- leaving a queue before acquiring a resource

SimPy provides an extended (compound) yield request statement form to model reneging.

yield (request,self,resource[,priority]),(<reneging clause>).

The structure of a SimPy model with reneging is:

yield (request,self,resource),(<reneging clause>)
if self.acquired(resource):
   ## process got resource and did not renege
   . . . . 
   yield release,self,resource
else:
   ## process reneged before acquiring resource
   . . . . . 

A call to method (self.acquired(resource)) is mandatory after a compound yield request statement. It is not only a predicate which indicates whether or not the process has acquired the resource, but it also removes the reneging process from the resource's waitQ.

SimPy 1.6 implements two reneging clauses, one for reneging after a certain time and one for reneging when an event has happened.

Reneging after a time limit

The reneging clause used is (hold,self,waittime)

  • yield (request,self,resource[,priority]),(hold,self,waittime)

If the resource unit has not been acquired by waittime, the process leaves the queue (reneges) and its execution continues. Method self.acquired(resource) must be called to check whether the resource has been acquired or not.

Reneging when an event has happened

The reneging clause used is (waitevent,self,events).

  • yield (request,self,resource[,priority]),(waitevent,self,events)

where events is an event or list of events (see events). If one of the events has been signalled before the unit of resource has been acquired the process reneges. As before, self.acquired(resource) must be called to check whether the resource has been acquired or not

Random variates

SimPy uses the standard random variate routines in the Python random module. To use them, import methods from the random module:

A good range of distributions is available. For example:

Monitors

Monitors are part of the SimPy package.

To define a new Monitor object:

Methods:

Simple data summaries:

Deprecated methods:

The following methods are retained for backwards compatibility but are not recommended. They may be removed in future releases of SimPy:

Error Messages

Advisory messages

These messages are returned by simulate(), as in message=simulate(until=123).

Upon a normal end of a simulation, simulate() returns the message:

  • SimPy: Normal exit. This means that no errors have occurred and the simulation has run to the time specified by the until parameter.

The following messages, returned by simulate(), are produced at a premature termination of the simulation but allow continuation of the program.

  • SimPy: No more events at time x. All processes were completed prior to the endtime given in simulate(until=endtime).
  • SimPy: No activities scheduled. No activities were scheduled when simulate() was called.

Fatal error messages

These messages are generated when SimPy-related fatal exceptions occur. They end the SimPy program. Fatal SimPy error messages are output to sysout.

  • Fatal SimPy error: activating function which is not a generator (contains no 'yield'). A process tried to (re)activate a function which is not a SimPy process (=Python generator). SimPy processes must contain at least one yield . . . statement.
  • Fatal SimPy error: Simulation not initialized. The SimPy program called simulate() before calling initialize().

Monitor error messages

  • SimPy: No observations for mean. No observations were made by the monitor before attempting to calculate the mean.
  • SimPy: No observations for sample variance. No observations were made by the monitor before attempting to calculate the sample variance.
  • SimPy: No observations for timeAverage, No observations were made by the monitor before attempting to calculate the time-average.
  • SimPy: No elapsed time for timeAverage. No simulation time has elapsed before attempting to calculate the time-average.

Acknowledgements

We will be grateful for any corrections or suggestions for improvements to the document.

Version:$Revision: 1.1.1.2.2.1.6.2 $
Python-Version:2.2, 2.3, 2.5
Created:2002-December-10