75 lines
3 KiB
Python
75 lines
3 KiB
Python
from pypdevs.DEVS import AtomicDEVS
|
|
|
|
# Define the state of the queue as a structured object
|
|
class QueueState:
|
|
def __init__(self, outputs):
|
|
# Keep a list of all idle processors
|
|
self.idle_procs = range(outputs)
|
|
# Keep a list that is the actual queue data structure
|
|
self.queue = []
|
|
# Keep the process that is currently being processed
|
|
self.processing = None
|
|
# Time remaining for this event
|
|
self.remaining_time = float("inf")
|
|
|
|
class Queue(AtomicDEVS):
|
|
def __init__(self, outputs):
|
|
AtomicDEVS.__init__(self, "Queue")
|
|
# Fix the time needed to process a single event
|
|
self.processing_time = 1.0
|
|
self.state = QueueState(outputs)
|
|
|
|
# Create 'outputs' output ports
|
|
# 'outputs' is a structural parameter!
|
|
self.out_proc = []
|
|
for i in range(outputs):
|
|
self.out_proc.append(self.addOutPort("proc_%i" % i))
|
|
|
|
# Add the other ports: incoming events and finished event
|
|
self.in_event = self.addInPort("in_event")
|
|
self.in_finish = self.addInPort("in_finish")
|
|
|
|
def intTransition(self):
|
|
# Is only called when we are outputting an event
|
|
# Pop the first idle processor and clear processing event
|
|
self.state.idle_procs.pop(0)
|
|
if self.state.queue and self.state.idle_procs:
|
|
# There are still queued elements, so continue
|
|
self.state.processing = self.state.queue.pop(0)
|
|
self.state.remaining_time = self.processing_time
|
|
else:
|
|
# No events left to process, so become idle
|
|
self.state.processing = None
|
|
self.state.remaining_time = float("inf")
|
|
return self.state
|
|
|
|
def extTransition(self, inputs):
|
|
# Update the remaining time of this job
|
|
self.state.remaining_time -= self.elapsed
|
|
# Several possibilities
|
|
if self.in_finish in inputs:
|
|
# Processing a "finished" event, so mark proc as idle
|
|
self.state.idle_procs.append(inputs[self.in_finish])
|
|
if not self.state.processing and self.state.queue:
|
|
# Process first task in queue
|
|
self.state.processing = self.state.queue.pop(0)
|
|
self.state.remaining_time = self.processing_time
|
|
elif self.in_event in inputs:
|
|
# Processing an incoming event
|
|
if self.state.idle_procs and not self.state.processing:
|
|
# Process when idle processors
|
|
self.state.processing = inputs[self.in_event]
|
|
self.state.remaining_time = self.processing_time
|
|
else:
|
|
# No idle processors, so queue it
|
|
self.state.queue.append(inputs[self.in_event])
|
|
return self.state
|
|
|
|
def timeAdvance(self):
|
|
# Just return the remaining time for this event (or infinity else)
|
|
return self.state.remaining_time
|
|
|
|
def outputFnc(self):
|
|
# Output the event to the processor
|
|
port = self.out_proc[self.state.idle_procs[0]]
|
|
return {port: self.state.processing}
|