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