Simulation
This commit is contained in:
100
src/main.py
100
src/main.py
@@ -1,14 +1,21 @@
|
|||||||
#!/bin/python3
|
#!/bin/python3
|
||||||
import random as rd
|
import random
|
||||||
from heapq import heappush, heappop
|
from heapq import heappush, heappop
|
||||||
|
|
||||||
class Event:
|
class Event:
|
||||||
def __init__(self, event_type, additional_options):
|
def __init__(self, event_type, additional_options):
|
||||||
self.event_type = event_type
|
self.event_type = event_type
|
||||||
if event_type == "request":
|
if event_type == "request":
|
||||||
self.category = additional_options['category']
|
self.request = additional_options['request']
|
||||||
elif event_type == "router_finish":
|
elif event_type == "router_finish":
|
||||||
self.request = additional_options['request']
|
self.request = additional_options['request']
|
||||||
|
elif event_type == "process_finish":
|
||||||
|
self.request = additional_options['request']
|
||||||
|
|
||||||
|
class Request:
|
||||||
|
def __init__(self, category, arrival_time):
|
||||||
|
self.category = category
|
||||||
|
self.arrival_time = arrival_time
|
||||||
|
|
||||||
|
|
||||||
class Simulation:
|
class Simulation:
|
||||||
@@ -16,6 +23,7 @@ class Simulation:
|
|||||||
# C clusters of K servers
|
# C clusters of K servers
|
||||||
self.C = C
|
self.C = C
|
||||||
self.K = 12 // C
|
self.K = 12 // C
|
||||||
|
self.occupied_servers = [0] * self.C
|
||||||
# service rate exponential distribution parameter
|
# service rate exponential distribution parameter
|
||||||
service_rates = {1: 4/20, 2:7/20, 3:10/20, 6:14/20}
|
service_rates = {1: 4/20, 2:7/20, 3:10/20, 6:14/20}
|
||||||
self.service_rate = service_rates[C]
|
self.service_rate = service_rates[C]
|
||||||
@@ -26,33 +34,103 @@ class Simulation:
|
|||||||
|
|
||||||
self.router_state = 'idle' # 'idle', 'processing', 'blocked'
|
self.router_state = 'idle' # 'idle', 'processing', 'blocked'
|
||||||
|
|
||||||
self.event_queue = Queue() # (arrival_time, category)
|
self.event_queue = [] # (time, Event)
|
||||||
self.current_time = 0.0
|
self.current_time = 0.0
|
||||||
|
|
||||||
|
self.router_queue = []
|
||||||
|
|
||||||
self.total_requests = 0
|
self.total_requests = 0
|
||||||
self.lost_requests = 0
|
self.lost_requests = 0
|
||||||
|
self.loss_rate = 0
|
||||||
self.response_times = []
|
self.response_times = []
|
||||||
|
|
||||||
def next_request():
|
def next_request(self):
|
||||||
# exponential distribution, parameter λ
|
# exponential distribution, parameter λ
|
||||||
interval = random.expovariate(self.lambda_val)
|
interval = random.expovariate(self.lambda_val)
|
||||||
new_time = self.current_time + interval
|
new_time = self.current_time + interval
|
||||||
arrival_time = new_time
|
arrival_time = new_time
|
||||||
|
|
||||||
category = rd.randint(1, C) if C>1 else 1
|
category = random.randint(0, self.C-1) if self.C>1 else 0
|
||||||
|
|
||||||
request = Event("request", {"category": category})
|
request = Request(category, arrival_time)
|
||||||
|
request_event = Event("request", {"request": request})
|
||||||
|
|
||||||
heappush(self.event_queue, (arrival_time, request))
|
heappush(self.event_queue, (arrival_time, request_event))
|
||||||
|
|
||||||
def router_process(request):
|
def handle_request(self, request):
|
||||||
|
self.total_requests += 1
|
||||||
|
if len(self.router_queue) == 0 and self.router_state == "idle":
|
||||||
|
self.router_process(request)
|
||||||
|
elif ((len(self.router_queue) + + (self.router_state == "processing")) < 100):
|
||||||
|
self.router_queue.append(request)
|
||||||
|
else:
|
||||||
|
self.lost_requests += 1
|
||||||
|
self.loss_rate = self.lost_requests / self.total_requests
|
||||||
|
if self.loss_rate > 0.05 :
|
||||||
|
raise ValueError("lossrate too high")
|
||||||
|
|
||||||
|
def router_process(self, request):
|
||||||
|
if self.router_state == "idle":
|
||||||
self.router_state = 'processing'
|
self.router_state = 'processing'
|
||||||
router_finish = Event("router_finish", {"request": request})
|
router_finish = Event("router_finish", {"request": request})
|
||||||
heappush(self.event_queue, (arrival_time, router_finish))
|
finish_time = self.current_time + self.router_processing_time
|
||||||
|
heappush(self.event_queue, (finish_time, router_finish))
|
||||||
|
else:
|
||||||
|
raise RuntimeError("shouldn't reach this branch")
|
||||||
|
|
||||||
def process_request(self, request, current_time):
|
|
||||||
|
def router_process_finish(self, request):
|
||||||
|
# send the request to a free server
|
||||||
|
if self.occupied_servers[request.category] < self.K:
|
||||||
|
self.router_state = "idle"
|
||||||
|
self.occupied_servers[request.category] += 1
|
||||||
|
self.process_request(request)
|
||||||
|
else:
|
||||||
|
self.router_state = "blocked"
|
||||||
|
self.router_queue.insert(0, request)
|
||||||
|
|
||||||
|
# router process next request
|
||||||
|
self.router_process_next()
|
||||||
|
|
||||||
|
def router_process_next(self):
|
||||||
|
if (len(self.router_queue) > 0) and (self.router_state == "idle"):
|
||||||
|
self.router_process(self.router_queue.pop(0))
|
||||||
|
|
||||||
|
def process_request(self, request):
|
||||||
interval = random.expovariate(self.service_rate)
|
interval = random.expovariate(self.service_rate)
|
||||||
finish = current_time + interval
|
finish_time = self.current_time + interval
|
||||||
|
process_finish = Event("process_finish", {"request": request})
|
||||||
|
heappush(self.event_queue, (finish_time, process_finish))
|
||||||
|
|
||||||
|
def process_request_finish(self, request):
|
||||||
|
self.response_times.append(self.current_time - request.arrival_time)
|
||||||
|
self.occupied_servers[request.category] -= 1
|
||||||
|
|
||||||
|
if (self.router_state == "blocked") and (request.category == self.router_queue[0].category):
|
||||||
|
self.process_request(self.router_queue.pop(0))
|
||||||
|
self.occupied_servers[request.category] += 1
|
||||||
|
self.router_state = "idle"
|
||||||
|
self.router_process_next()
|
||||||
|
|
||||||
|
|
||||||
|
def run(self, max_time):
|
||||||
|
# first request
|
||||||
|
self.next_request()
|
||||||
|
|
||||||
|
while (self.current_time <= max_time):
|
||||||
|
current_event = heappop(self.event_queue)
|
||||||
|
self.current_time = current_event[0]
|
||||||
|
match current_event[1].event_type:
|
||||||
|
case "request":
|
||||||
|
self.next_request()
|
||||||
|
self.handle_request(current_event[1].request)
|
||||||
|
case "router_finish":
|
||||||
|
self.router_process_finish(current_event[1].request)
|
||||||
|
case "process_finish":
|
||||||
|
self.process_request_finish(current_event[1].request)
|
||||||
|
case _ :
|
||||||
|
raise RuntimeError("shouldn't reach this branch")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user