Package SimPy :: Module SimulationTrace |
[hide private]
[frames] | no frames]

# Source Code for Module SimPy.SimulationTrace

      1  #!/usr / bin / env python
      2  # coding=utf-8
      3  # $Revision: 444 $ $Date: 2010-04-02 05:59:43 +0200 (Fri, 02 Apr 2010) $ kgm
      4  """SimulationTrace 2.1 Traces execution of SimPy models.
      5  Implements SimPy Processes, Resources, Buffers, and the backbone simulation
      6  scheduling by coroutine calls. Provides data collection through classes
      7  Monitor and Tally.
      8  Based on generators (Python 2.3 and later; not 3.0)
      9
     10  LICENSE:
     11  Copyright (C) 2002, 2005, 2006, 2007, 2008  Klaus G. Muller, Tony Vignaux
     12  mailto: kgmuller@xs4all.nl and Tony.Vignaux@vuw.ac.nz
     13
     14      This library is free software; you can redistribute it and / or
     15      modify it under the terms of the GNU Lesser General Public
     16      License as published by the Free Software Foundation; either
     17      version 2.1 of the License, or (at your option) any later version.
     18
     19      This library is distributed in the hope that it will be useful,
     20      but WITHOUT ANY WARRANTY; without even the implied warranty of
     21      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     22      Lesser General Public License for more details.
     23
     24      You should have received a copy of the GNU Lesser General Public
     25      License along with this library; if not, write to the Free Software
     26      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111 - 1307  USA
     27  END OF LICENSE
     28  """
     29
     30  from SimPy.Lister import *
     31  from SimPy.Simulation import *
     32
     33
     34  __TESTING = False
     35  version = __version__ = '2.1 $Revision: 444 $ $Date: 2010-04-02 05:59:43 +0200 (Fri, 02 Apr 2010) $'
     36  if __TESTING:
     37      print 'SimPy.SimulationTrace %s' %__version__,
     38      if __debug__:
     39          print '__debug__ on'
     40      else:
     41          print
     42
     43 -def trace_dispatch(trace, command, func):
     44      """
     45      Returns a wrapper for ``func`` which will record the dispatch in the trace
     46      log.
     47      """
     48      def dispatch(event):
     49          func(event)
     50          trace.recordEvent(command, event)
     51
     52      return dispatch
     53
     54 -class SimulationTrace(Simulation):
     55 -    def __init__(self):
     56          Simulation.__init__(self)
     57          self.trace = Trace(sim=self)
     58          # Trace method to be called on _post calls.
     59          self._post_tracing = None
     60
     61          # We use our own instance of the command dictionary.
     62          self._dispatch = dict(Simulation._dispatch)
     63
     64          # Now wrap all commands in a tracing call.
     65          for command, func in self._dispatch.items():
     66              self._dispatch[command] = trace_dispatch(self.trace, command, func)
     67
     68 -    def initialize(self):
     69          Simulation.initialize(self)
     70
     71
     72 -    def _post(self, what, at, prior=False):
     73          if self._post_tracing is not None: self._post_tracing(what, at, prior)
     74          Simulation._post(self, what, at, prior)
     75
     76 -    def activate(
     77              self, obj, process, at='undefined', delay='undefined', prior=False):
     78          # Activate _post tracing.
     79          self._post_tracing = self.trace.recordActivate
     80          Simulation.activate(self, obj, process, at, delay, prior)
     81          self._post_tracing = None
     82
     83 -    def reactivate(
     84              self, obj, at='undefined', delay='undefined', prior=False):
     85          # Activate _post tracing.
     86          self._post_tracing = self.trace.recordReactivate
     87          Simulation.reactivate(self, obj, at, delay, prior)
     88          self._post_tracing = None
     89
     90 -    def _terminate(self, process):
     91          self.trace.tterminated(process)
     92          Simulation._terminate(self, process)
     93
     94 -    def simulate(self, until=0):
     95          try:
     96              return Simulation.simulate(self, until)
     97          finally:
     98              if not(self.trace.outfile is sys.stdout):
     99                  self.trace.outfile.close()
    100
    101 -class Trace(Lister):
    102      commands={hold:'hold', passivate:'passivate', request:'request', release:'release',
    103                waitevent:'waitevent', queueevent:'queueevent', waituntil:'waituntil',
    104              get:'get', put:'put'}
    105
    106 -    def __init__(self, start = 0, end = 10000000000L, toTrace=\
    107                   ['hold', 'activate', 'cancel', 'reactivate', 'passivate', 'request',
    108                    'release', 'interrupt', 'terminated', 'waitevent', 'queueevent',
    109                    'signal', 'waituntil', 'put', 'get'
    110                   ],outfile = sys.stdout,sim=None):
    111
    112          Trace.commandsproc={hold:Trace.thold, passivate:Trace.tpassivate,
    113                              request:Trace.trequest, release:Trace.trelease,
    114                              waitevent:Trace.twaitevent,
    115                              queueevent:Trace.tqueueevent,
    116                              waituntil:Trace.twaituntil,
    117                              get:Trace.tget, put:Trace.tput}
    118          if sim is None: sim=Globals.sim
    119          self.sim=sim
    120          self.start = start
    121          self.end = end
    122          self.toTrace = toTrace
    123          self.tracego = True
    124          self.outfile = outfile
    125          self._comment = None
    126
    127 -    def treset(self):
    128          Trace.commandsproc={hold:Trace.thold, passivate:Trace.tpassivate,
    129                              request:Trace.trequest, release:Trace.trelease,
    130                              waitevent:Trace.twaitevent,
    131                              queueevent:Trace.tqueueevent,
    132                              waituntil:Trace.twaituntil,
    133                              get:Trace.tget, put:Trace.tput}
    134          self.start = 0
    135          self.end = 10000000000L
    136          self.toTrace = ['hold', 'activate', 'cancel', 'reactivate', 'passivate', 'request',
    137                          'release', 'interrupt', 'terminated', 'waitevent', 'queueevent',
    138                          'signal', 'waituntil', 'put', 'get']
    139          self.tracego = True
    140          self.outfile = sys.stdout
    141          self._comment = None
    142
    143 -    def tchange(self,**kmvar):
    144          for v in kmvar.keys():
    145              if v == 'start':
    146                  self.start = kmvar[v]
    147              elif v == 'end':
    148                  self.end = kmvar[v]
    149              elif v == 'toTrace':
    150                  self.toTrace = kmvar[v]
    151              elif v == 'outfile':
    152                  self.outfile = kmvar[v]
    153
    154 -    def tstart(self):
    155          self.tracego = True
    156
    157 -    def tstop(self):
    158          self.tracego = False
    159
    160 -    def ifTrace(self, cond):
    161          if self.tracego and (self.start <= self.sim.now() <= self.end)\
    162             and cond:
    163              return True
    164
    165 -    def thold(self, par):
    166          try:
    167              return 'delay: %s'%par[0][2]
    168          except:
    169              return 'delay: 0'
    170      thold = classmethod(thold)
    171
    172 -    def trequest(self, par):
    173          res = par[0][2]
    174          if len(par[0]) == 4:
    175              priority = ' priority: ' + str(par[0][3])
    176          else:
    177              priority = ' priority: default'
    178          wQ = [x.name for x in res.waitQ]
    179          aQ = [x.name for x in res.activeQ]
    180          return '<%s> %s \n. . .waitQ: %s \n. . .activeQ: %s' % (res.name, priority, wQ, aQ)
    181      trequest = classmethod(trequest)
    182
    183 -    def trelease(self, par):
    184          res = par[0][2]
    185          wQ = [x.name for x in res.waitQ]
    186          aQ = [x.name for x in res.activeQ]
    187          return '<%s> \n. . .waitQ: %s \n. . .activeQ: %s' % (res.name, wQ, aQ)
    188      trelease = classmethod(trelease)
    189
    190 -    def tpassivate(self, par):
    191          return ""
    192      tpassivate = classmethod(tpassivate)
    193
    194 -    def tactivate(self, par):
    195          pass
    196      tactivate = classmethod(tactivate)
    197
    198 -    def twaitevent(self, par):
    199          evt = par[0][2]
    200          if type(evt) == list or type(evt) == tuple:
    201              enames = [x.name for x in evt]
    202              return 'waits for events <%s > '%enames
    203          else:
    204              return 'waits for event <%s > '%evt.name
    205      twaitevent = classmethod(twaitevent)
    206
    207 -    def tqueueevent(self, par):
    208          evt = par[0][2]
    209          if type(evt) == list or type(evt) == tuple:
    210              enames = [x.name for x in evt]
    211              return 'queues for events <%s > '%enames
    212          else:
    213              return 'queues for event <%s > '%evt.name
    214      tqueueevent = classmethod(tqueueevent)
    215
    216 -    def tsignal(self, evt):
    217          wQ = [x.name for x in evt.waits]
    218          qQ = [x.name for x in evt.queues]
    219          return '<%s> \n. . .  occurred: %s\n. . .  waiting: %s\n. . .  queueing: %s'\
    220                  %(evt.name, evt.occurred, wQ, qQ)
    221          pass
    222      tsignal = classmethod(tsignal)
    223
    224 -    def twaituntil(self, par):
    225          condition = par[0][2]
    226          return 'for condition <%s > '%condition.func_name
    227      twaituntil = classmethod(twaituntil)
    228
    229 -    def tget(self, par):
    230          buff = par[0][2]
    231          if len(par[0]) == 5:
    232              priority = ' priority: ' + str(par[0][4])
    233          else:
    234              priority = ' priority: default'
    235          if len(par[0]) == 3:
    236              nrToGet = 1
    237          else:
    238              nrToGet = par[0][3]
    239          toGet = 'to get: %s %s from' % (nrToGet, buff.unitName)
    240          getQ = [x.name for x in buff.getQ]
    241          putQ = [x.name for x in buff.putQ]
    242          try:
    243              inBuffer = buff.amount
    244          except:
    245              inBuffer = buff.nrBuffered
    246          return '%s <%s> %s \n. . .getQ: %s \n. . .putQ: %s \n. . .in buffer: %s'\
    247              %(toGet, buff.name, priority, getQ, putQ, inBuffer)
    248      tget = classmethod(tget)
    249
    250 -    def tput(self, par):
    251          buff = par[0][2]
    252          if len(par[0]) == 5:
    253              priority = ' priority: ' + str(par[0][4])
    254          else:
    255              priority = ' priority: default'
    256          if len(par[0]) == 3:
    257              nrToPut = 1
    258          else:
    259              if type(par[0][3]) == type([]):
    260                  nrToPut = len(par[0][3])
    261              else:
    262                  nrToPut = par[0][3]
    263          getQ = [x.name for x in buff.getQ]
    264          putQ = [x.name for x in buff.putQ]
    265          toPut = 'to put: %s %s into' % (nrToPut, buff.unitName)
    266          try:
    267              inBuffer = buff.amount
    268          except:
    269              inBuffer = buff.nrBuffered
    270          return '%s <%s> %s \n. . .getQ: %s \n. . .putQ: %s \n. . .in buffer: %s'\
    271              %(toPut, buff.name, priority, getQ, putQ, inBuffer)
    272      tput = classmethod(tput)
    273
    274 -    def recordEvent(self, command, whole):
    275          if self.ifTrace(Trace.commands[command] in self.toTrace):
    276              if not type(whole[0][0]) == tuple:
    277                  print >> self.outfile, whole[0][1].sim.now(),\
    278                      Trace.commands[command],\
    279                      ' < ' + whole[0][1].name + ' > ',\
    280                      Trace.commandsproc[command](whole)
    281                  if self._comment:
    282                      print >> self.outfile, '----', self._comment
    283              else:
    284                  print >> self.outfile, whole[0][0][1].sim.now(),\
    285                           Trace.commands[command],\
    286                           ' < ' + whole[0][0][1].name + ' > '+\
    287                           Trace.commandsproc[command](whole[0])
    288                  print >> self.outfile, '|| RENEGE COMMAND:'
    289                  command1 = whole[0][1][0]
    290                  print >> self.outfile, '||\t', Trace.commands[command1],\
    291                      ' < ' + whole[0][1][1].name + ' > ',\
    292                        Trace.commandsproc[command1]((whole[0][1],))
    293                  if self._comment:
    294                      print >> self.outfile, '----', self._comment
    295
    296          self._comment = None
    297
    298 -    def recordInterrupt(self, who, victim):
    299          if self.ifTrace('interrupt' in self.toTrace):
    300              print >> self.outfile, '%s interrupt by: <%s > of: <%s >'\
    301                                     %(who.sim.now(),who.name, victim.name)
    302              if self._comment:
    303                  print >> self.outfile, '----', self._comment
    304          self._comment = None
    305
    306 -    def recordCancel(self, who, victim):
    307          if self.ifTrace('cancel' in self.toTrace):
    308              print >> self.outfile, '%s cancel by: <%s > of: <%s > '\
    309              %(who.sim.now(),who.name, victim.name)
    310              if self._comment:
    311                  print >> self.outfile, '----', self._comment
    312          self._comment = None
    313
    314 -    def recordActivate(self, who, when, prior):
    315          if self.ifTrace('activate' in self.toTrace):
    316              print >> self.outfile, '%s activate <%s > at time: %s prior: %s'\
    317                       %(who.sim.now(),who.name,when, prior)
    318              if self._comment:
    319                  print >> self.outfile, '----', self._comment
    320          self._comment = None
    321
    322 -    def recordReactivate(self, who, when, prior):
    323          if self.ifTrace('reactivate' in self.toTrace):
    324              print >> self.outfile, '%s reactivate <%s > time: %s prior: %s'\
    325                       %(who.sim.now(),who.name,when, prior)
    326              if self._comment:
    327                  print >> self.outfile, '----', self._comment
    328          self._comment = None
    329
    330 -    def recordSignal(self, evt):
    331          if self.ifTrace('signal' in self.toTrace):
    332              print >> self.outfile, '%s event <%s > is signalled' \
    333                                     %(evt.sim.now(),evt.name)
    334              if self._comment:
    335                  print >> self.outfile, '----', self._comment
    336          self._comment = None
    337
    338 -    def tterminated(self, who):
    339          if self.ifTrace('terminated' in self.toTrace):
    340              print >> self.outfile, '%s <%s > terminated'\
    341                       %(who.sim.now(),who.name)
    342              if self._comment:
    343                  print >> self.outfile, '----', self._comment
    344          self._comment = None
    345
    346 -    def ttext(self, par):
    347          self._comment = par
    348
    349  # For backward compatibility
    350  Globals.sim = SimulationTrace()
    351  trace = Globals.sim.trace
    352  step = Globals.sim.step
    353  peek = Globals.sim.peek
    354  # End backward compatibility
    355
    356  if __name__ == '__main__':
    357      print 'SimPy.SimulationTrace %s' %__version__
    358      ############# Test / demo functions #############
    359 -    def test_demo():
    360          class Aa(Process):
    361              sequIn = []
    362              sequOut = []
    363              def __init__(self, holdtime, name,sim=None):
    364                  Process.__init__(self, name,sim=sim)
    365                  self.holdtime = holdtime
    366
    367              def life(self, priority):
    368                  for i in range(1):
    369                      Aa.sequIn.append(self.name)
    370                      print self.sim.now(),rrr.name, 'waitQ:', len(rrr.waitQ),'activeQ:',\
    371                            len(rrr.activeQ)
    372                      print 'waitQ: ',[(k.name, k._priority[rrr]) for k in rrr.waitQ]
    373                      print 'activeQ: ',[(k.name, k._priority[rrr]) \
    374                                 for k in rrr.activeQ]
    375                      assert rrr.n + len(rrr.activeQ) == rrr.capacity, \
    376                     'Inconsistent resource unit numbers'
    377                      print self.sim.now(),self.name, 'requests 1 ', rrr.unitName
    378                      yield request, self, rrr, priority
    379                      print self.sim.now(),self.name, 'has 1 ', rrr.unitName
    380                      print self.sim.now(),rrr.name, 'waitQ:', len(rrr.waitQ),'activeQ:',\
    381                            len(rrr.activeQ)
    382                      print self.sim.now(),rrr.name, 'waitQ:', len(rrr.waitQ),'activeQ:',\
    383                            len(rrr.activeQ)
    384                      assert rrr.n + len(rrr.activeQ) == rrr.capacity, \
    385                     'Inconsistent resource unit numbers'
    386                      yield hold, self, self.holdtime
    387                      print self.sim.now(),self.name, 'gives up 1', rrr.unitName
    388                      yield release, self, rrr
    389                      Aa.sequOut.append(self.name)
    390                      print self.sim.now(),self.name, 'has released 1 ', rrr.unitName
    391                      print 'waitQ: ',[(k.name, k._priority[rrr]) for k in rrr.waitQ]
    392                      print self.sim.now(),rrr.name, 'waitQ:', len(rrr.waitQ),'activeQ:',\
    393                            len(rrr.activeQ)
    394                      assert rrr.n + len(rrr.activeQ) == rrr.capacity, \
    395                             'Inconsistent resource unit numbers'
    396
    397          class Observer(Process):
    398              def __init__(self,**vars):
    399                  Process.__init__(self,**vars)
    400
    401              def observe(self, step, processes, res):
    402                  while self.sim.now() < 11:
    403                      for i in processes:
    404                          print '++ %s process: %s: active:%s, passive:%s, terminated: %s, interrupted:%s, queuing:%s'\
    405                                %(self.sim.now(),i.name, i.active(),i.passive(),\
    406                                  i.terminated(),i.interrupted(),i.queuing(res))
    407                      print
    408                      yield hold, self, step
    409
    410          print'\n+++test_demo output'
    411          print '****First case == priority queue, resource service not preemptable'
    412          s=SimulationTrace()
    413          s.initialize()
    414          rrr = Resource(5, name = 'Parking', unitName = 'space(s)', qType = PriorityQ,
    415                       preemptable = 0,sim=s)
    416          procs = []
    417          for i in range(10):
    418              z = Aa(holdtime = i, name = 'Car ' + str(i),sim=s)
    419              procs.append(z)
    420              s.activate(z, z.life(priority = i))
    421          o = Observer(sim=s)
    422          s.activate(o, o.observe(1, procs, rrr))
    423          a = s.simulate(until = 10000)
    424          print a
    425          print 'Input sequence: ', Aa.sequIn
    426          print 'Output sequence: ', Aa.sequOut
    427
    428          print '\n****Second case == priority queue, resource service preemptable'
    429          s=SimulationTrace()
    430          s.initialize()
    431          rrr = Resource(5, name = 'Parking', unitName = 'space(s)', qType = PriorityQ,
    432                       preemptable = 1,sim=s)
    433          procs = []
    434          for i in range(10):
    435              z = Aa(holdtime = i, name = 'Car ' + str(i),sim=s)
    436              procs.append(z)
    437              s.activate(z, z.life(priority = i))
    438          o = Observer(sim=s)
    439          s.activate(o, o.observe(1, procs, rrr))
    440          Aa.sequIn = []
    441          Aa.sequOut = []
    442          a = s.simulate(until = 10000)
    443          print a
    444          print 'Input sequence: ', Aa.sequIn
    445          print 'Output sequence: ', Aa.sequOut
    446
    447 -    def test_interrupt():
    448          class Bus(Process):
    449              def __init__(self, **vars):
    450                  Process.__init__(self, **vars)
    451
    452              def operate(self, repairduration = 0):
    453                  print self.sim.now(),'>> %s starts' % (self.name)
    454                  tripleft = 1000
    455                  while tripleft > 0:
    456                      yield hold, self, tripleft
    457                      if self.interrupted():
    458                          print 'interrupted by %s' %self.interruptCause.name
    459                          print '%s: %s breaks down ' %(now(),self.name)
    460                          tripleft = self.interruptLeft
    461                          self.interruptReset()
    462                          print 'tripleft ', tripleft
    463                          s.reactivate(br, delay = repairduration) # breakdowns only during operation
    464                          yield hold, self, repairduration
    465                          print self.sim.now(),' repaired'
    466                      else:
    467                          break # no breakdown, ergo bus arrived
    468                  print self.sim.now(),'<< %s done' % (self.name)
    469
    470          class Breakdown(Process):
    471              def __init__(self, myBus,sim=None):
    472                  Process.__init__(self, name = 'Breakdown ' + myBus.name,sim=sim)
    473                  self.bus = myBus
    474
    475              def breakBus(self, interval):
    476
    477                  while True:
    478                      yield hold, self, interval
    479                      if self.bus.terminated(): break
    480                      self.interrupt(self.bus)
    481
    482          print'\n\n+++test_interrupt'
    483          s=SimulationTrace()
    484          s.initialize()
    485          b = Bus(name='Bus 1',sim=s)
    486          s.activate(b, b.operate(repairduration = 20))
    487          br = Breakdown(b,sim=s)
    488          s.activate(br, br.breakBus(200))
    489          print s.simulate(until = 4000)
    490
    491 -    def testSimEvents():
    492          class Waiter(Process):
    493              def __init__(self,**vars):
    494                  Process.__init__(self,**vars)
    495              def waiting(self, theSignal):
    496                  while True:
    497                      yield waitevent, self, theSignal
    498                      print '%s: process \'%s\' continued after waiting for %s' %\
    499                            (self.sim.now(),self.name, theSignal.name)
    500                      yield queueevent, self, theSignal
    501                      print '%s: process \'%s\' continued after queueing for %s' % (now(),self.name, theSignal.name)
    502
    503          class ORWaiter(Process):
    504              def __init__(self,**vars):
    505                  Process.__init__(self,**vars)
    506              def waiting(self, signals):
    507                  while True:
    508                      yield waitevent, self, signals
    509                      print self.sim.now(),'one of %s signals occurred' %\
    510                            [x.name for x in signals]
    511                      print '\t%s (fired / param)'%\
    512                            [(x.name, x.signalparam) for x in self.eventsFired]
    513                      yield hold, self, 1
    514
    515          class Caller(Process):
    516              def __init__(self,**vars):
    517                  Process.__init__(self,**vars)
    518              def calling(self):
    519                  while True:
    520                      signal1.signal('wake up!')
    521                      print '%s: signal 1 has occurred'%now()
    522                      yield hold, self, 10
    523                      signal2.signal('and again')
    524                      signal2.signal('sig 2 again')
    525                      print '%s: signal1, signal2 have occurred'%now()
    526                      yield hold, self, 10
    527          print'\n+++testSimEvents output'
    528          s=SimulationTrace()
    529          s.initialize()
    530          signal1 = SimEvent('signal 1',sim=s)
    531          signal2 = SimEvent('signal 2',sim=s)
    532          signal1.signal('startup1')
    533          signal2.signal('startup2')
    534          w1 = Waiter(name='waiting for signal 1',sim=s)
    535          s.activate(w1, w1.waiting(signal1))
    536          w2 = Waiter(name='waiting for signal 2',sim=s)
    537          s.activate(w2, w2.waiting(signal2))
    538          w3 = Waiter(name='also waiting for signal 2',sim=s)
    539          s.activate(w3, w3.waiting(signal2))
    540          w4 = ORWaiter(name='waiting for either signal 1 or signal 2',sim=s)
    541          s.activate(w4, w4.waiting([signal1, signal2]),prior = True)
    542          c = Caller(name='Caller',sim=s)
    543          s.activate(c, c.calling())
    544          print s.simulate(until = 100)
    545
    546 -    def testwaituntil():
    547          """
    548          Demo of waitUntil capability.
    549
    550          Scenario:
    551          Three workers require sets of tools to do their jobs. Tools are shared,
    552          scarce resources for which they compete.
    553          """
    554          class Worker(Process):
    555              def __init__(self, name, heNeeds = [],sim=None):
    556                  Process.__init__(self, name,sim=sim)
    557                  self.heNeeds = heNeeds
    558              def work(self):
    559                  def workerNeeds():
    560                      for item in self.heNeeds:
    561                          if item.n == 0:
    562                              return False
    563                      return True
    564
    565                  while self.sim.now() < 8 * 60:
    566                      yield waituntil, self, workerNeeds
    567                      for item in self.heNeeds:
    568                          yield request, self, item
    569                      print '%s %s has %s and starts job' % (self.sim.now(),self.name,
    570                          [x.name for x in self.heNeeds])
    571                      yield hold, self, random.uniform(10, 30)
    572                      for item in self.heNeeds:
    573                          yield release, self, item
    574                      yield hold, self, 2 #rest
    575
    576          print '\n+++ nwaituntil demo output'
    577          random.seed(12345)
    578          s=SimulationTrace()
    579          s.initialize()
    580          brush = Resource(capacity = 1, name = 'brush',sim=s)
    581          ladder = Resource(capacity = 2, name = 'ladder',sim=s)
    582          hammer = Resource(capacity = 1, name = 'hammer',sim=s)
    583          saw = Resource(capacity = 1, name = 'saw',sim=s)
    584          painter = Worker('painter',[brush, ladder],sim=s)
    585          s.activate(painter, painter.work())
    586          roofer = Worker('roofer',[hammer, ladder, ladder],sim=s)
    587          s.activate(roofer, roofer.work())
    588          treeguy = Worker('treeguy',[saw, ladder],sim=s)
    589          s.activate(treeguy, treeguy.work())
    590          for who in (painter, roofer, treeguy):
    591              print '%s needs %s for his job' %\
    592                    (who.name,[x.name for x in who.heNeeds])
    593          print
    594          print s.simulate(until = 9 * 60)
    595
    596      ## -------------------------------------------------------------
    597      ##                    TEST COMPOUND 'YIELD REQUEST' COMMANDS
    598      ## -------------------------------------------------------------
    599
    600      ## -------------------------------------------------------------
    601      ##             TEST 'yield (request, self, res),(hold, self, delay)'
    602      ##                   == timeout renege
    603      ## -------------------------------------------------------------
    604
    605 -    class JobTO(Process):
    606         """ Job class for testing timeout reneging
    607         """
    608 -       def __init__(self, server = None, name = '',sim=None):
    609              Process.__init__(self, name,sim=sim)
    610              self.res = server
    611              self.gotResource = None
    612
    613 -       def execute(self, timeout, usetime):
    614              yield (request, self, self.res),(hold, self, timeout)
    615              if self.acquired(self.res):
    616                  self.gotResource = True
    617                  yield hold, self, usetime
    618                  yield release, self, self.res
    619              else:
    620                  self.gotResource = False
    621
    622
    623 -    def testNoTimeout():
    624          """Test that resource gets acquired without timeout
    625          """
    626          s=SimulationTrace()
    627          s.initialize()
    628          res = Resource(name = 'Server', capacity = 1,sim=s)
    629          usetime = 5
    630          timeout = 1000000
    631          j1 = JobTO(server = res, name = 'Job_1',sim=s)
    632          s.activate(j1, j1.execute(timeout = timeout, usetime = usetime))
    633          j2 = JobTO(server = res, name = 'Job_2',sim=s)
    634          s.activate(j2, j2.execute(timeout = timeout, usetime = usetime))
    635          s.simulate(until = 2 * usetime)
    636          assert s.now() == 2 * usetime, 'time not == 2 * usetime'
    637          assert j1.gotResource and j2.gotResource,\
    638              'at least one job failed to get resource'
    639          assert not (res.waitQ or res.activeQ),\
    640              'job waiting or using resource'
    641
    642 -    def testTimeout1():
    643          """Test that timeout occurs when resource busy
    644          """
    645          s=SimulationTrace()
    646          s.initialize()
    647          res = Resource(name = 'Server', capacity = 1, monitored = True,sim=s)
    648          usetime = 5
    649          timeout = 3
    650          j1 = JobTO(server = res, name = 'Job_1',sim=s)
    651          s.activate(j1, j1.execute(timeout = timeout, usetime = usetime))
    652          j2 = JobTO(server = res, name = 'Job_2',sim=s)
    653          s.activate(j2, j2.execute(timeout = timeout, usetime = usetime))
    654          s.simulate(until = 2 * usetime)
    655          assert(s.now() == usetime),'time not == usetime'
    656          assert(j1.gotResource),'Job_1 did not get resource'
    657          assert(not j2.gotResource),'Job_2 did not renege'
    658          assert not (res.waitQ or res.activeQ),\
    659              'job waiting or using resource'
    660
    661 -    def testTimeout2():
    662          """Test that timeout occurs when resource has no capacity free
    663          """
    664          s=SimulationTrace()
    665          s.initialize()
    666          res = Resource(name = 'Server', capacity = 0,sim=s)
    667          usetime = 5
    668          timeout = 3
    669          j1 = JobTO(server = res, name = 'Job_1',sim=s)
    670          s.activate(j1, j1.execute(timeout = timeout, usetime = usetime))
    671          j2 = JobTO(server = res, name = 'Job_2',sim=s)
    672          s.activate(j2, j2.execute(timeout = timeout, usetime = usetime))
    673          s.simulate(until = 2 * usetime)
    674          assert s.now() == timeout, 'time %s not == timeout'%now()
    675          assert not j1.gotResource, 'Job_1 got resource'
    676          assert not j2.gotResource, 'Job_2 got resource'
    677          assert not (res.waitQ or res.activeQ),\
    678              'job waiting or using resource'
    679
    680      ## ------------------------------------------------------------------
    681      ##             TEST 'yield (request, self, res),(waitevent, self, event)'
    682      ##                   == event renege
    683      ## ------------------------------------------------------------------
    684 -    class JobEvt(Process):
    685         """ Job class for testing event reneging
    686         """
    687 -       def __init__(self, server = None, name = '',sim=None):
    688              Process.__init__(self, name,sim=sim)
    689              self.res = server
    690              self.gotResource = None
    691
    692 -       def execute(self, event, usetime):
    693              yield (request, self, self.res),(waitevent, self, event)
    694              if self.acquired(self.res):
    695                  self.gotResource = True
    696                  yield hold, self, usetime
    697                  yield release, self, self.res
    698              else:
    699                  self.gotResource = False
    700
    701 -    class JobEvtMulti(Process):
    702         """ Job class for testing event reneging with multi - event lists
    703         """
    704 -       def __init__(self, server = None, name = '',sim=None):
    705              Process.__init__(self, name,sim=sim)
    706              self.res = server
    707              self.gotResource = None
    708
    709 -       def execute(self, eventlist, usetime):
    710              yield (request, self, self.res),(waitevent, self, eventlist)
    711              if self.acquired(self.res):
    712                  self.gotResource = True
    713                  yield hold, self, usetime
    714                  yield release, self, self.res
    715              else:
    716                  self.gotResource = False
    717
    718 -    class FireEvent(Process):
    719          """Fires reneging event
    720          """
    721 -        def __init__(self,**vars):
    722              Process.__init__(self,**vars)
    723 -        def fire(self, fireDelay, event):
    724              yield hold, self, fireDelay
    725              event.signal()
    726
    727 -    def testNoEvent():
    728          """Test that processes acquire resource normally if no event fires
    729          """
    730          s=SimulationTrace()
    731          s.initialize()
    732          res = Resource(name = 'Server', capacity = 1,sim=s)
    733          event = SimEvent(name='Renege_trigger',sim=s) #never gets fired
    734          usetime = 5
    735          j1 = JobEvt(server = res, name = 'Job_1',sim=s)
    736          s.activate(j1, j1.execute(event = event, usetime = usetime))
    737          j2 = JobEvt(server = res, name = 'Job_2',sim=s)
    738          s.activate(j2, j2.execute(event = event, usetime = usetime))
    739          s.simulate(until = 2 * usetime)
    740          # Both jobs should get server (in sequence)
    741          assert s.now() == 2 * usetime, 'time not == 2 * usetime'
    742          assert j1.gotResource and j2.gotResource,\
    743              'at least one job failed to get resource'
    744          assert not (res.waitQ or res.activeQ),\
    745              'job waiting or using resource'
    746
    747 -    def testWaitEvent1():
    748          """Test that signalled event leads to renege when resource busy
    749          """
    750          s=SimulationTrace()
    751          s.initialize()
    752          res = Resource(name = 'Server', capacity = 1,sim=s)
    753          event = SimEvent('Renege_trigger',sim=s)
    754          usetime = 5
    755          eventtime = 1
    756          j1 = JobEvt(server = res, name = 'Job_1',sim=s)
    757          s.activate(j1, j1.execute(event = event, usetime = usetime))
    758          j2 = JobEvt(server = res, name = 'Job_2',sim=s)
    759          s.activate(j2, j2.execute(event = event, usetime = usetime))
    760          f = FireEvent(name = 'FireEvent',sim=s)
    761          s.activate(f, f.fire(fireDelay = eventtime, event = event))
    762          s.simulate(until = 2 * usetime)
    763          # Job_1 should get server, Job_2 renege
    764          assert(s.now() == usetime),'time not == usetime'
    765          assert(j1.gotResource),'Job_1 did not get resource'
    766          assert(not j2.gotResource),'Job_2 did not renege'
    767          assert not (res.waitQ or res.activeQ),\
    768              'job waiting or using resource'
    769
    770 -    def testWaitEvent2():
    771          """Test that renege - triggering event can be one of an event list
    772          """
    773          s=SimulationTrace()
    774          s.initialize()
    775          res = Resource(name = 'Server', capacity = 1,sim=s)
    776          event1 = SimEvent('Renege_trigger_1',sim=s)
    777          event2 = SimEvent('Renege_trigger_2',sim=s)
    778          usetime = 5
    779          eventtime = 1 #for both events
    780          j1 = JobEvtMulti(server = res, name = 'Job_1',sim=s)
    781          s.activate(j1, j1.execute(eventlist = [event1, event2],usetime = usetime))
    782          j2 = JobEvtMulti(server = res, name = 'Job_2',sim=s)
    783          s.activate(j2, j2.execute(eventlist = [event1, event2],usetime = usetime))
    784          f1 = FireEvent(name = 'FireEvent_1',sim=s)
    785          s.activate(f1, f1.fire(fireDelay = eventtime, event = event1))
    786          f2 = FireEvent(name = 'FireEvent_2',sim=s)
    787          s.activate(f2, f2.fire(fireDelay = eventtime, event = event2))
    788          s.simulate(until = 2 * usetime)
    789          # Job_1 should get server, Job_2 should renege
    790          assert(s.now() == usetime),'time not == usetime'
    791          assert(j1.gotResource),'Job_1 did not get resource'
    792          assert(not j2.gotResource),'Job_2 did not renege'
    793          assert not (res.waitQ or res.activeQ),\
    794              'job waiting or using resource'
    795
    796      testNoTimeout()
    797      testTimeout1()
    798      testTimeout2()
    799      testNoEvent()
    800      testWaitEvent1()
    801      testWaitEvent2()
    802      test_demo()
    803      test_interrupt()
    804      testSimEvents()
    805      testwaituntil()
    806