#!/usr/bin/env python # QoS.py: illustration of non-FCFS priorities in Resource class # Communications channel, shared by video and data. Video packets # arrive every 1.0 amount of time, and have transmission time 1.0. Data # packets follow a Poisson process with intensity parameter DArrRate, # and their transmission time is uniformaly distributed on {1,2,3,4,5}. # Video packets have priority over data packets but the latter are not # pre-emptable. A video packet is discarded upon arrival if it would be # sent L or more amount of time late. # usage: python QoS.py DArrRate L MaxSimTime from SimPy.Simulation import * from random import Random,expovariate class G: # globals Rnd = Random(12345) Chnl = None # our one channel VA = None # our one video arrivals process DA = None # our one video arrivals process class ChannelClass(Resource): def __init__(self): # note arguments to parent constructor: Resource.__init__(self,capacity=1,qType=PriorityQ) # if a packet is currently being sent, here is when transmit will end self.TimeEndXMit = None self.NWaitingVid = 0 # number of video packets in queue class VidJob(Process): def __init__(self): Process.__init__(self) def Run(self): Lost = False # if G.Chnl.TimeEndXMit is None, then no jobs in the system # now, so this job will start right away (handled below); # otherwise: if G.Chnl.TimeEndXMit != None: # first check for loss TimeThisPktStartXMit = G.Chnl.TimeEndXMit + G.Chnl.NWaitingVid if TimeThisPktStartXMit - now() > VidArrivals.L: Lost = True VidArrivals.NLost += 1 return G.Chnl.NWaitingVid += 1 yield request,self,G.Chnl,1 # higher priority G.Chnl.NWaitingVid -= 1 G.Chnl.TimeEndXMit = now() + 1.0 yield hold,self,0.999999999999 # to avoid coding "ties" G.Chnl.TimeEndXMit = None yield release,self,G.Chnl class VidArrivals(Process): L = None # threshold for discarding packet NArrived = 0 # number of video packets arrived NLost = 0 # number of video packets lost def __init__(self): Process.__init__(self) def Run(self): while 1: yield hold,self,2.0 VidArrivals.NArrived += 1 V = VidJob() activate(V,V.Run()) class DataJob(Process): def __init__(self): Process.__init__(self) self.ArrivalTime = now() def Run(self): yield request,self,G.Chnl,0 # lower priority XMitTime = G.Rnd.randint(1,5) - 0.000000000001 G.Chnl.TimeEndXMit = now() + XMitTime yield hold,self,XMitTime G.Chnl.TimeEndXMit = None DataArrivals.NSent += 1 DataArrivals.TotWait += now() - self.ArrivalTime yield release,self,G.Chnl class DataArrivals(Process): DArrRate = None # data arrival rate NSent = 0 # number of video packets arrived TotWait = 0.0 # number of video packets lost def __init__(self): Process.__init__(self) def Run(self): while 1: yield hold,self,G.Rnd.expovariate(DataArrivals.DArrRate) D = DataJob() activate(D,D.Run()) # def ShowStatus(): # print 'time', now() # print 'current xmit ends at', G.Chnl.TimeEndXMit # print 'there are now',len(G.Chnl.waitQ), 'in the wait queue' # print G.Chnl.NWaitingVid, 'of those are video packets' def main(): initialize() VidArrivals.L = float(sys.argv[1]) DataArrivals.DArrRate = float(sys.argv[2]) G.Chnl = ChannelClass() G.VA = VidArrivals() activate(G.VA,G.VA.Run()) G.DA = DataArrivals() activate(G.DA,G.DA.Run()) MaxSimtime = float(sys.argv[3]) simulate(until=MaxSimtime) print 'proportion of video packets lost:', \ float(VidArrivals.NLost)/VidArrivals.NArrived print 'mean delay for data packets:', \ DataArrivals.TotWait/DataArrivals.NSent if __name__ == '__main__': main()