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

Source Code for Module SimPy.SimulationRT

  1  #!/usr / bin / env python 
  2  # coding=utf-8 
  3  # $Revision: 485 $ $Date: 2010-05-10 09:23:24 +0200 (Mon, 10 May 2010) $ kgm 
  4  """SimulationRT 2.1 Provides synchronization of real time and SimPy simulation time. 
  5  Implements SimPy Processes, resources, and the backbone simulation scheduling 
  6  by coroutine calls.  
  7  Based on generators (Python 2.3 and later; not 3.0) 
  8   
  9  LICENSE: 
 10  Copyright (C) 2002, 2005, 2006, 2007, 2008, 2009, 2010  Klaus G. Muller, Tony Vignaux 
 11  mailto: kgmuller at xs4all.nl and Tony.Vignaux at vuw.ac.nz 
 12   
 13      This library is free software; you can redistribute it and / or 
 14      modify it under the terms of the GNU Lesser General Public 
 15      License as published by the Free Software Foundation; either 
 16      version 2.1 of the License, or (at your option) any later version. 
 17   
 18      This library is distributed in the hope that it will be useful, 
 19      but WITHOUT ANY WARRANTY; without even the implied warranty of 
 20      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
 21      Lesser General Public License for more details. 
 22   
 23      You should have received a copy of the GNU Lesser General Public 
 24      License along with this library; if not, write to the Free Software 
 25      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111 - 1307  USA 
 26  END OF LICENSE 
 27  """ 
 28  import time 
 29   
 30  from SimPy.Simulation import * 
 31   
 32   
 33  __TESTING = False 
 34  version = __version__ = '2.1 $Revision: 485 $ $Date: 2010-05-10 09:23:24 +0200 (Mon, 10 May 2010) $' 
 35  if __TESTING:  
 36      print 'SimPy.SimulationRT %s' %__version__, 
 37      if __debug__: 
 38          print '__debug__ on' 
 39      else: 
 40          print 
 41   
42 -class SimulationRT(Simulation):
43 - def __init__(self):
44 if sys.platform == 'win32': #take care of differences in clock accuracy 45 self.wallclock = time.clock 46 else: 47 self.wallclock = time.time 48 Simulation.__init__(self)
49
50 - def rtnow(self):
51 return self.wallclock() - self.rtstart
52
53 - def rtset(self, rel_speed=1):
54 """ 55 Resets the ratio simulation time over clock time(seconds). 56 """ 57 # Ensure relative speed is a float. 58 self.rel_speed = float(rel_speed)
59
60 - def simulate(self, until=0, real_time=False, rel_speed=1):
61 """ 62 Simulates until simulation time reaches ``until``. If ``real_time`` is 63 ``True`` a simulation time unit is matched with real time by the factor 64 1 / ``rel_speed``. 65 """ 66 try: 67 self.rtstart = self.wallclock() 68 self.rtset(rel_speed) 69 70 while self._timestamps and not self._stop: 71 next_event_time = self.peek() 72 if next_event_time > until: break 73 74 if real_time: 75 delay = ( 76 next_event_time / self.rel_speed - 77 (self.wallclock() - self.rtstart) 78 ) 79 if delay > 0: time.sleep(delay) 80 81 self.step() 82 83 # There are still events in the timestamps list and the simulation 84 # has not been manually stopped. This means we have reached the stop 85 # time. 86 if not self._stop and self._timestamps: 87 self._t = until 88 return 'SimPy: Normal exit' 89 else: 90 return 'SimPy: No activities scheduled' 91 except Simerror, error: 92 return 'SimPy: ' + error.value 93 finally: 94 self._stop = True
95 96 97 98 # For backward compatibility 99 Globals.sim = SimulationRT() 100
101 -def rtnow():
102 return Globals.sim.rtnow()
103 104 rtset = Globals.sim.rtset 105
106 -def simulate(until = 0, real_time = False, rel_speed = 1):
107 return Globals.sim.simulate(until = until, real_time = real_time, rel_speed = rel_speed)
108 109 wallclock = Globals.sim.wallclock 110 # End backward compatibility 111 112 if __name__ == '__main__': 113 print 'SimPy.SimulationRT %s' %__version__ 114 ############# Test / demo functions #############
115 - def test_demo():
116 class Aa(Process): 117 sequIn = [] 118 sequOut = [] 119 def __init__(self, holdtime, name): 120 Process.__init__(self, name) 121 self.holdtime = holdtime
122 123 def life(self, priority): 124 for i in range(1): 125 Aa.sequIn.append(self.name) 126 print now(),rrr.name, 'waitQ:', len(rrr.waitQ),'activeQ:',\ 127 len(rrr.activeQ) 128 print 'waitQ: ',[(k.name, k._priority[rrr]) for k in rrr.waitQ] 129 print 'activeQ: ',[(k.name, k._priority[rrr]) \ 130 for k in rrr.activeQ] 131 assert rrr.n + len(rrr.activeQ) == rrr.capacity, \ 132 'Inconsistent resource unit numbers' 133 print now(),self.name, 'requests 1 ', rrr.unitName 134 yield request, self, rrr, priority 135 print now(),self.name, 'has 1 ', rrr.unitName 136 print now(),rrr.name, 'waitQ:', len(rrr.waitQ),'activeQ:',\ 137 len(rrr.activeQ) 138 print now(),rrr.name, 'waitQ:', len(rrr.waitQ),'activeQ:',\ 139 len(rrr.activeQ) 140 assert rrr.n + len(rrr.activeQ) == rrr.capacity, \ 141 'Inconsistent resource unit numbers' 142 yield hold, self, self.holdtime 143 print now(),self.name, 'gives up 1', rrr.unitName 144 yield release, self, rrr 145 Aa.sequOut.append(self.name) 146 print now(),self.name, 'has released 1 ', rrr.unitName 147 print 'waitQ: ',[(k.name, k._priority[rrr]) for k in rrr.waitQ] 148 print now(),rrr.name, 'waitQ:', len(rrr.waitQ),'activeQ:',\ 149 len(rrr.activeQ) 150 assert rrr.n + len(rrr.activeQ) == rrr.capacity, \ 151 'Inconsistent resource unit numbers' 152 153 class Observer(Process): 154 def __init__(self): 155 Process.__init__(self) 156 157 def observe(self, step, processes, res): 158 while now() < 11: 159 for i in processes: 160 print ' %s %s: act:%s, pass:%s, term: %s, interr:%s, qu:%s'\ 161 %(now(),i.name, i.active(),i.passive(),i.terminated()\ 162 ,i.interrupted(),i.queuing(res)) 163 print 164 yield hold, self, step 165 166 print'\n+++test_demo output' 167 print '****First case == priority queue, resource service not preemptable' 168 initialize() 169 rrr = Resource(5, name = 'Parking', unitName = 'space(s)', qType = PriorityQ, 170 preemptable = 0) 171 procs = [] 172 for i in range(10): 173 z = Aa(holdtime = i, name = 'Car ' + str(i)) 174 procs.append(z) 175 activate(z, z.life(priority = i)) 176 o = Observer() 177 activate(o, o.observe(1, procs, rrr)) 178 a = simulate(until = 10000, real_time = True, rel_speed = 1) 179 print a 180 print 'Input sequence: ', Aa.sequIn 181 print 'Output sequence: ', Aa.sequOut 182 183 print '\n****Second case == priority queue, resource service preemptable' 184 initialize() 185 rrr = Resource(5, name = 'Parking', unitName = 'space(s)', qType = PriorityQ, 186 preemptable = 1) 187 procs = [] 188 for i in range(10): 189 z = Aa(holdtime = i, name = 'Car ' + str(i)) 190 procs.append(z) 191 activate(z, z.life(priority = i)) 192 o = Observer() 193 activate(o, o.observe(1, procs, rrr)) 194 Aa.sequIn = [] 195 Aa.sequOut = [] 196 a = simulate(until = 10000) 197 print a 198 print 'Input sequence: ', Aa.sequIn 199 print 'Output sequence: ', Aa.sequOut 200
201 - def test_interrupt():
202 class Bus(Process): 203 def __init__(self, name): 204 Process.__init__(self, name)
205 206 def operate(self, repairduration = 0): 207 print now(),rtnow(),'>> %s starts' % (self.name) 208 tripleft = 1000 209 while tripleft > 0: 210 yield hold, self, tripleft 211 if self.interrupted(): 212 print 'interrupted by %s' %self.interruptCause.name 213 print '%s(%s): %s breaks down ' %(now(),rtnow(),self.name) 214 tripleft = self.interruptLeft 215 self.interruptReset() 216 print 'tripleft ', tripleft 217 reactivate(br, delay = repairduration) # breakdowns only during operation 218 yield hold, self, repairduration 219 print now(),rtnow(),' repaired' 220 else: 221 break # no breakdown, ergo bus arrived 222 print now(),'<< %s done' % (self.name) 223 224 class Breakdown(Process): 225 def __init__(self, myBus): 226 Process.__init__(self, name = 'Breakdown ' + myBus.name) 227 self.bus = myBus 228 229 def breakBus(self, interval): 230 231 while True: 232 yield hold, self, interval 233 if self.bus.terminated(): break 234 self.interrupt(self.bus) 235 236 print'\n\n+++test_interrupt' 237 initialize() 238 b = Bus('Bus 1') 239 activate(b, b.operate(repairduration = 20)) 240 br = Breakdown(b) 241 activate(br, br.breakBus(200)) 242 print simulate(until = 4000, real_time = True, rel_speed = 200) 243
244 - def testSimEvents():
245 class Waiter(Process): 246 def waiting(self, theSignal): 247 while True: 248 yield waitevent, self, theSignal 249 print '%s: process \'%s\' continued after waiting for %s' % (now(),self.name, theSignal.name) 250 yield queueevent, self, theSignal 251 print '%s: process \'%s\' continued after queueing for %s' % (now(),self.name, theSignal.name)
252 253 class ORWaiter(Process): 254 def waiting(self, signals): 255 while True: 256 yield waitevent, self, signals 257 print now(),'one of %s signals occurred' % [x.name for x in signals] 258 print '\t%s (fired / param)'%[(x.name, x.signalparam) for x in self.eventsFired] 259 yield hold, self, 1 260 261 class Caller(Process): 262 def calling(self): 263 while True: 264 signal1.signal('wake up!') 265 print '%s: signal 1 has occurred'%now() 266 yield hold, self, 10 267 signal2.signal('and again') 268 signal2.signal('sig 2 again') 269 print '%s: signal1, signal2 have occurred'%now() 270 yield hold, self, 10 271 print'\n\n+++testSimEvents output' 272 initialize() 273 signal1 = SimEvent('signal 1') 274 signal2 = SimEvent('signal 2') 275 signal1.signal('startup1') 276 signal2.signal('startup2') 277 w1 = Waiter('waiting for signal 1') 278 activate(w1, w1.waiting(signal1)) 279 w2 = Waiter('waiting for signal 2') 280 activate(w2, w2.waiting(signal2)) 281 w3 = Waiter('also waiting for signal 2') 282 activate(w3, w3.waiting(signal2)) 283 w4 = ORWaiter('waiting for either signal 1 or signal 2') 284 activate(w4, w4.waiting([signal1, signal2]),prior = True) 285 c = Caller('Caller') 286 activate(c, c.calling()) 287 print simulate(until = 100) 288
289 - def testwaituntil():
290 """ 291 Demo of waitUntil capability. 292 293 Scenario: 294 Three workers require sets of tools to do their jobs. Tools are shared, scarce 295 resources for which they compete. 296 """ 297 298 299 class Worker(Process): 300 def __init__(self, name, heNeeds = []): 301 Process.__init__(self, name) 302 self.heNeeds = heNeeds
303 def work(self): 304 305 def workerNeeds(): 306 for item in self.heNeeds: 307 if item.n == 0: 308 return False 309 return True 310 311 while now() < 8 * 60: 312 yield waituntil, self, workerNeeds 313 for item in self.heNeeds: 314 yield request, self, item 315 print '%s %s has %s and starts job' % (now(),self.name, 316 [x.name for x in self.heNeeds]) 317 yield hold, self, random.uniform(10, 30) 318 for item in self.heNeeds: 319 yield release, self, item 320 yield hold, self, 2 #rest 321 322 print '\n+++\nwaituntil demo output' 323 initialize() 324 brush = Resource(capacity = 1, name = 'brush') 325 ladder = Resource(capacity = 2, name = 'ladder') 326 hammer = Resource(capacity = 1, name = 'hammer') 327 saw = Resource(capacity = 1, name = 'saw') 328 painter = Worker('painter',[brush, ladder]) 329 activate(painter, painter.work()) 330 roofer = Worker('roofer',[hammer, ladder, ladder]) 331 activate(roofer, roofer.work()) 332 treeguy = Worker('treeguy',[saw, ladder]) 333 activate(treeguy, treeguy.work()) 334 for who in (painter, roofer, treeguy): 335 print '%s needs %s for his job' % (who.name,[x.name for x in who.heNeeds]) 336 print 337 print simulate(until = 9 * 60) 338 test_demo() 339 # Run tests 340 test_interrupt() 341 #testSimEvents() 342 #testwaituntil() 343