Reputation: 3
I have a problem with simulating simple work conserving scheduler in SimPy. I want this scheduler to have 2 queues to work as simple round robin which services packet from queue number 1 and then services packet from queue number 2. If one of the queues is empty it goes to service packets from other queue (work conserving). Packets that were already serviced are sent to 1 common output.
I've already written a code based on this code (https://www.grotto-networking.com/DiscreteEventPython.html) to create such solution but it doesn't work as i wanted. Packets which are sent to queue number 1 are being serviced but packets in queue number 2 aren't. I think the problem might be with having multiple resources for 1 process and i don't know how to resolve this problem.
class RoundRobinQueue(object):
def __init__(self, env, rate, qlimit=None, limit_bytes=True):
self.store = simpy.Store(env)
self.store2 = simpy.Store(env)
self.rate = rate
self.env = env
self.out = None
self.packets_rec = 0
self.packets_drop = 0
self.qlimit = qlimit
self.limit_bytes = limit_bytes
self.byte_size = 0 # Current size of the queue in bytes
self.busy = 0 # Used to track if a packet is currently being sent
self.action = env.process(self.run()) # starts the run() method as a SimPy process
self.trigger = 1
def run(self):
while True:
if (self.trigger == 0 and len(self.store.items)>=0):
self.trigger = 1
msg = (yield self.store.get())
self.byte_size -= msg.size
self.busy = 1
yield self.env.timeout(msg.size * 8.0 / self.rate)
self.out.put(msg)
self.busy = 0
else:
self.trigger = 1
if (self.trigger == 1 and len(self.store2.items)>=0):
self.trigger = 0
msg2 = (yield self.store2.get())
self.byte_size -= msg2.size
self.busy = 1
yield self.env.timeout(msg2.size * 8.0 / self.rate)
self.out.put(msg2)
self.busy = 0
else:
self.trigger = 0
Upvotes: 0
Views: 533
Reputation: 1914
looks like when both queues are empty it falls into a infinite loop, added a check for that. Also includes the fix where it only pulls from a queue if it is not empty
def run(self):
while True:
if len(self.store.items) + len(self.store2.items) ==0:
# both queue are empty, wait a sec to avoid a infinate loop
yield self.env.timeout(1)
else:
if len(self.store.items)>0:
self.trigger = 1
msg = (yield self.store.get())
self.byte_size -= msg.size
self.busy = 1
yield self.env.timeout(msg.size * 8.0 / self.rate)
self.out.put(msg)
self.busy = 0
else:
self.trigger = 1
if len(self.store2.items)>0:
self.trigger = 0
msg2 = (yield self.store2.get())
self.byte_size -= msg2.size
self.busy = 1
yield self.env.timeout(msg2.size * 8.0 / self.rate)
self.out.put(msg2)
self.busy = 0
else:
self.trigger = 0
Upvotes: 1
Reputation: 1914
i think
len(self.store.items)>=0
will always be true because a empty queue will have length of 0
to skip when the queue is empty I think
if (self.trigger == 0 and len(self.store.items)>=0):
should be
if len(self.store.items) > 0:
and
if (self.trigger == 1 and len(self.store2.items)>=0):
should be
if len(self.store2.items) > 0:
Upvotes: 1