mirror of
https://github.com/Zenithsiz/ist-ddrs-lab2
synced 2026-02-03 22:23:55 +00:00
187 lines
6.4 KiB
R
187 lines
6.4 KiB
R
# Simulator of packet scheduler with two queues, using a random scheduling
|
|
# algorithm. The queues have independent Poisson arrivals and uniformly
|
|
# distributed packet sizes
|
|
|
|
set.seed(0)
|
|
|
|
# Input parameters
|
|
ArrivalRate <- c(1, 1)
|
|
avg_packet_size <- c(1000, 3000)
|
|
link_capacity <- 1000
|
|
queues_quantum <- c(2000, 1000)
|
|
|
|
# Initialization
|
|
time <- 0
|
|
num_sys_completed <- 0
|
|
link_status <- 0
|
|
num_in_queue <- c(0, 0)
|
|
queues_packet_size <- list(c(), c())
|
|
accum_bits <- c(0, 0)
|
|
event_list <- c(rexp(1, ArrivalRate[1]), rexp(1, ArrivalRate[2]), Inf)
|
|
queues_credit <- c(0, 0)
|
|
|
|
# Link
|
|
served_packet_size <- NULL
|
|
served_queue <- NULL
|
|
|
|
# Simulation loop
|
|
while (num_sys_completed < 10000) {
|
|
# Get next event type
|
|
next_event_type <- which.min(event_list)
|
|
time <- event_list[next_event_type]
|
|
|
|
# If it's an arrival event
|
|
if (next_event_type == 1 || next_event_type == 2) {
|
|
# Add the arrival to the queue
|
|
event_list[next_event_type] <- time + rexp(1, ArrivalRate[next_event_type])
|
|
|
|
# Generate a uniformly sampled packet size
|
|
packet_size <- sample(seq(avg_packet_size[next_event_type] - 500, avg_packet_size[next_event_type] + 500, 100), 1)
|
|
|
|
# If there's someone in the queue, queue the arriving packet
|
|
if (link_status == 1) {
|
|
queues_packet_size[[next_event_type]] <- c(queues_packet_size[[next_event_type]], packet_size)
|
|
num_in_queue[next_event_type] <- num_in_queue[next_event_type] + 1
|
|
}
|
|
|
|
# Else if there's no one in the queue, put them on the link
|
|
# and schedule their departure
|
|
else {
|
|
link_status <- 1
|
|
served_packet_size <- packet_size
|
|
served_queue <- next_event_type
|
|
event_list[3] <- time + served_packet_size / link_capacity
|
|
}
|
|
}
|
|
|
|
# Else it's a departure event
|
|
else {
|
|
num_sys_completed <- num_sys_completed + 1
|
|
accum_bits[served_queue] <- accum_bits[served_queue] + served_packet_size
|
|
|
|
# If all queues are empty
|
|
if (all(num_in_queue == 0)) {
|
|
served_queue <- NULL
|
|
served_packet_size <- NULL
|
|
event_list[3] <- Inf
|
|
link_status <- 0
|
|
}
|
|
|
|
# Else if any are queue
|
|
else if (any(num_in_queue == 0)) {
|
|
# Find the first non-empty queue
|
|
current_queue <- which(num_in_queue != 0)
|
|
|
|
# Set it as being served and add a departure event
|
|
packet_size <- queues_packet_size[[current_queue]][1]
|
|
served_packet_size <- packet_size
|
|
event_list[3] <- time + served_packet_size / link_capacity
|
|
served_queue <- current_queue
|
|
|
|
# Remove the queued packet and set credit to 0, if empty
|
|
queues_packet_size[[current_queue]] <- queues_packet_size[[current_queue]][-1]
|
|
num_in_queue[current_queue] <- num_in_queue[current_queue] - 1
|
|
if (num_in_queue[current_queue] == 0) {
|
|
queues_credit[current_queue] <- 0
|
|
}
|
|
}
|
|
|
|
# Else all are full
|
|
else {
|
|
found_queue <- FALSE
|
|
|
|
# If the last queue still has enough quantum, serve it
|
|
last_queue_next_packet_size <- queues_packet_size[[served_queue]][1]
|
|
if (queues_credit[served_queue] >= last_queue_next_packet_size) {
|
|
# Set the packet as being served
|
|
served_packet_size <- last_queue_next_packet_size
|
|
event_list[3] <- time + served_packet_size / link_capacity
|
|
|
|
# Set credit to 0, if empty, else subtract the used bits
|
|
if (num_in_queue[served_queue] == 1) {
|
|
queues_credit[served_queue] <- 0
|
|
} else {
|
|
queues_credit[served_queue] <- queues_credit[served_queue] - last_queue_next_packet_size
|
|
}
|
|
|
|
# Remove the queued packet
|
|
queues_packet_size[[served_queue]] <- queues_packet_size[[served_queue]][-1]
|
|
num_in_queue[served_queue] <- num_in_queue[served_queue] - 1
|
|
|
|
found_queue <- TRUE
|
|
}
|
|
|
|
# If we aren't at the last queue yet, check them
|
|
if (!found_queue && served_queue < length(queues_credit)) {
|
|
for (queue_idx in (served_queue + 1):length(queues_credit)) {
|
|
# And check if it's enough
|
|
queue_next_packet_size <- queues_packet_size[[queue_idx]][1]
|
|
if (queues_credit[queue_idx] >= queue_next_packet_size) {
|
|
# Set the packet as being served
|
|
served_packet_size <- queue_next_packet_size
|
|
served_queue <- queue_idx
|
|
event_list[3] <- time + served_packet_size / link_capacity
|
|
|
|
# Set credit to 0, if empty, else subtract the used bits
|
|
if (num_in_queue[queue_idx] == 1) {
|
|
queues_credit[queue_idx] <- 0
|
|
} else {
|
|
queues_credit[queue_idx] <- queues_credit[queue_idx] - queue_next_packet_size
|
|
}
|
|
|
|
# Then remove the queued packet
|
|
queues_packet_size[[queue_idx]] <- queues_packet_size[[queue_idx]][-1]
|
|
num_in_queue[queue_idx] <- num_in_queue[queue_idx] - 1
|
|
|
|
found_queue <- TRUE
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
# Otherwise, find a queue to get from
|
|
if (!found_queue) {
|
|
served_queue <- NULL
|
|
while (is.null(served_queue)) {
|
|
# Add quantum to each queue
|
|
for (queue_idx in seq_along(queues_credit)) {
|
|
queues_credit[queue_idx] <- queues_credit[queue_idx] + queues_quantum[queue_idx]
|
|
}
|
|
|
|
# Then get the first queue that has enough credits
|
|
for (queue_idx in seq_along(queues_credit)) {
|
|
# And check if it's enough
|
|
queue_next_packet_size <- queues_packet_size[[queue_idx]][1]
|
|
if (queues_credit[queue_idx] >= queue_next_packet_size) {
|
|
# Set the packet as being served
|
|
served_packet_size <- queue_next_packet_size
|
|
served_queue <- queue_idx
|
|
event_list[3] <- time + served_packet_size / link_capacity
|
|
|
|
# Set credit to 0, if empty, else subtract the used bits
|
|
if (num_in_queue[queue_idx] == 1) {
|
|
queues_credit[queue_idx] <- 0
|
|
} else {
|
|
queues_credit[queue_idx] <- queues_credit[queue_idx] - queue_next_packet_size
|
|
}
|
|
|
|
# Then remove the queued packet
|
|
queues_packet_size[[queue_idx]] <- queues_packet_size[[queue_idx]][-1]
|
|
num_in_queue[queue_idx] <- num_in_queue[queue_idx] - 1
|
|
|
|
found_queue <- TRUE
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
print(queues_credit)
|
|
|
|
# Print results
|
|
cat(sprintf("The throughput of queue 1 is %f\n", accum_bits[1] / time))
|
|
cat(sprintf("The throughput of queue 2 is %f\n", accum_bits[2] / time))
|