Based on the following text:
"L1: Network system simulation
Summary
The purpose of this lab is to simulate the operation of the output link of a router that is
modeled as a queuing system and investigate its performance under variable configurations,
to understand how different parameter settings may affect the system behaviour and how
modifying some parameters of the network system may impact on performance metrics.
In the considered queuing system, representing the output link of a router, the customers
represent the packets that arrive to that output link, whereas the service represents the
transmission on the channel. Finally, the waiting line represents the buffer where packets
are stored before transmission.
Tasks
In order to investigate the performance of the router output link, you should focus on the
following aspects:
a. Derive the metrics describing the system performance in the baseline scenario, considering both the cases with and without packet losses.
b. Modify the baseline scenario varying the size of the buffer and considering a multiserver system, assuming that two transmitters are present in the system. Test the
system behaviour under different buffer sizes (infinite waiting line, medium to short
finite waiting line, no buffer at all) and compare its performance with the single server
scenario.
You can start from the network simulator code available in the course material, that represents the operation of an M/M/1 queuing system with infinite waiting line, either choosing
an event scheduling approach or a process interaction based approach. The simulator is
provided in two versions:
• queueMM1-ES.py: this version is based on an event scheduling approach;
• queueMM1-PI.py: this version is based on process interaction.
You can make your modifications and integration to the code, in order to investigate the
system performance via simulation. Different metrics can be useful to understand the system
operation and evaluate its performance, like:
1
• number of transmitted packets
• number of dropped packets
• average number of packets in the system
• average queuing delay, i.e. the average time spent in the system
• distribution of queuing delay
• average waiting delay per packet, assuming that the packet waiting delay is the
time elapsed from the moment at which a packet enters the system to the instant at
which the service begins.
It is useful to compute both of the following types of waiting delay:
– the average waiting delay experienced by any packet (averaging over all packets);
– the average waiting delay considering only those packets that actually experience some delay, since they enter the system while the server(s) is (are)
busy and are hence buffered.
• average buffer occupancy, i.e. the average number of packets in the buffer.
• loss probability, i.e. the fraction of packets that cannot be transmitted since the
server(s) is (are) currently busy and no buffer is present in the system or, in case of
finite buffer, it is full.
• busy time, i.e. the cumulative time that during the simulation each server spends in
a busy state serving packets requests. In a single-server system, you can observe how
it varies with the buffer size. In a multi-server system, based on the busy time analysis
per each server, you can examine the distribution of the load among servers.
You can think of other metrics that may be helpful in your analysis to highlight specific
aspects or critical issues in the system operation. When running your simulations, pay
attention on setting appropriate values of the simulation duration.
In your analysis of the network operation and performance, you should perform the following
tasks:
1. investigate the system performance under different arrival rates, keeping a fixed
value for the average service rate:
(a) how is the system affected? Highlight your findings by showing the variation of
relevant performance metrics;
(b) set a desired confidence level and, for one of the metrics reported in the graphs
produced in task 1.a, show the confidence intervals of the performed measurements;
(c) are the results of your analysis consistent with theoretical expected values?
2
2. consider a multi-server system, assuming two transmitters and a finite buffer:
(a) compare its performance with the single server case;
(b) test different values of the buffer size: how do they affect the system performance
with respect to an infinite buffer?
3. considering a multi-server scenario, investigate the load distribution among servers.
Test different algorithms to assign each new request to an available server (random
assignment; round robin; assignment to the fastest servers, assuming for example that
each server features a different service rate...) and compare the system performance in
the various cases. How is load distribution affected?
4. try to vary the distribution of the service time, i.e. considering the case of M/G/1,
and observe how the system performance changes, assuming one or more different
distribution types for the service time instead of exponential distribution;
Discuss in your report the main findings emerged from the various investigated scenarios.
Support your claims and observations by plotting graphs that report the most significant
performance metrics from different cases and help to highlight the relevant findings under
variable configuration settings. Remember to always specify the unit of measure for the
parameters and metrics represented in the graphs. For each graph, check that the main
configuration settings that have been adopted to obtain the corresponding simulation results
are reported.
"
and according to the follosing code:
#!/usr/bin/python3


import random
import simpy


# ******************************************************************************
# To take the measurements
# ******************************************************************************
class Measure:
    def __init__(self,Narr,Ndep,NAveraegUser,OldTimeEvent,AverageDelay):
        self.arr = Narr
        self.dep = Ndep
        self.ut = NAveraegUser
        self.oldT = OldTimeEvent
        self.delay = AverageDelay
 
# ******************************************************************************
# Client
# ******************************************************************************       
class Client:
    def __init__(self,Type,ArrivalT):
        self.type = Type
        self.Tarr = ArrivalT
        

# ******************************************************************************
# Constants
# ******************************************************************************

SERVICE = 10.0 # SERVICE is the average service time; service rate = 1/SERVICE
ARRIVAL = 5.0 # ARRIVAL is the average inter-arrival time; arrival rate = 1/ARRIVAL
LOAD=SERVICE/ARRIVAL # This relationship holds for M/M/1

TYPE1 = 1 

SIM_TIME = 500000

arrivals=0
users=0
BusyServer=False # True: server is currently busy; False: server is currently idle

MM1=[]

# ******************************************************************************
# generator yield events to the simulator
# ******************************************************************************

# arrivals *********************************************************************
def arrival_process(environment,queue):
    global users
    global BusyServer
    while True:
        #print("Arrival no. ",data.arr+1," at time ",environment.now," with ",users," users" )
        
        # cumulate statistics 
        data.arr += 1
        data.ut += users*(environment.now-data.oldT)
        data.oldT = environment.now
        
        # sample the time until the next event
        inter_arrival = random.expovariate(1.0/ARRIVAL)
        
        #update state variable and put the client in the queue
        users += 1
        cl=Client(TYPE1,env.now)
        queue.append(cl)
        
        if users == 1: 
            BusyServer = True
            service_time = random.expovariate(1.0/SERVICE)
            env.process(departure_process(env, service_time,queue))
            
        # yield an event to the simulator
        yield environment.timeout(inter_arrival)

        # the execution flow will resume here
        # when the "timeout" event is executed by the "environment"

# ******************************************************************************

# departures *******************************************************************
def departure_process(environment, service_time, queue):
    global users
    global BusyServer

    
    yield environment.timeout(service_time)
    #print("Departure no. ",data.dep+1," at time ",environment.now," with ",users," users" )
    
    # cumulate statistics    
    data.dep += 1
    data.ut += users*(environment.now-data.oldT)
    data.oldT = environment.now

    #update state variable and extract the client in the queue
    users -= 1

    user=queue.pop(0)
    data.delay += (env.now-user.Tarr)
    
    if users==0: 
        BusyServer = False
    else:
        service_time = random.expovariate(1.0/SERVICE)
        env.process(departure_process(env, service_time,queue))

        # the execution flow will resume here
        # when the "timeout" event is executed by the "environment"
       

# ******************************************************************************


# ******************************************************************************
# the main body of the simulation
# ******************************************************************************


# create the environment

random.seed(42)

data = Measure(0,0,0,0,0)

env = simpy.Environment()

# start the arrival processes
env.process(arrival_process(env, MM1))


# simulate until SIM_TIME
env.run(until=SIM_TIME)


# print output data
print("MEASUREMENTS \n\nNo. of users in the queue:",users,"\nNo. of arrivals =",
      data.arr,"- No. of departures =",data.dep)

print("Load: ",SERVICE/ARRIVAL)
print("\nArrival rate: ",data.arr/env.now," - Departure rate: ",data.dep/env.now)

print("\nAverage number of users: ",data.ut/env.now)

print("Average delay: ",data.delay/data.dep)
print("Actual queue size: ",len(MM1))

if len(MM1)>0:
    print("Arrival time of the last element in the queue:",MM1[len(MM1)-1].Tarr)
    

write the report for me