///|
pub(all) struct BandwidthLink {
src : Int
dst : Int
bandwidth_bps : Double
propagation_latency : Double
buffer_capacity_bytes : Int
mut current_buffer_bytes : Int
mut next_available_time : Double
mut packets_sent : Int
mut packets_delivered : Int
mut overflow_drops : Int
mut total_queueing_delay : Double
}
///|
pub fn BandwidthLink::new(
src : Int,
dst : Int,
bandwidth_bps : Double,
propagation_latency : Double,
buffer_capacity_bytes : Int,
) -> BandwidthLink {
if bandwidth_bps <= 0.0 ||
propagation_latency < 0.0 ||
buffer_capacity_bytes < 0 {
abort("Invalid BandwidthLink parameters")
}
{
src,
dst,
bandwidth_bps,
propagation_latency,
buffer_capacity_bytes,
current_buffer_bytes: 0,
next_available_time: 0.0,
packets_sent: 0,
packets_delivered: 0,
overflow_drops: 0,
total_queueing_delay: 0.0,
}
}
///|
pub fn BandwidthLink::update_buffer(self : BandwidthLink, now : Double) -> Unit {
if now > self.next_available_time {
self.current_buffer_bytes = 0
} else {
// Estimate cleared buffer
let remaining_time = self.next_available_time - now
let remaining_bytes = (remaining_time * self.bandwidth_bps).to_int()
if remaining_bytes < self.current_buffer_bytes {
self.current_buffer_bytes = if remaining_bytes > 0 {
remaining_bytes
} else {
0
}
}
}
}
///|
pub fn BandwidthLink::transmit(
self : BandwidthLink,
now : Double,
size_bytes : Int,
) -> Double? {
self.packets_sent = self.packets_sent + 1
self.update_buffer(now)
if self.current_buffer_bytes + size_bytes > self.buffer_capacity_bytes {
self.overflow_drops = self.overflow_drops + 1
return None
}
self.current_buffer_bytes = self.current_buffer_bytes + size_bytes
let tx_start = if now > self.next_available_time {
now
} else {
self.next_available_time
}
let queue_delay = tx_start - now
self.total_queueing_delay = self.total_queueing_delay + queue_delay
let tx_duration = Double::from_int(size_bytes) / self.bandwidth_bps
self.next_available_time = tx_start + tx_duration
let delivery_time = self.next_available_time + self.propagation_latency
self.packets_delivered = self.packets_delivered + 1
Some(delivery_time)
}
///|
pub fn BandwidthLink::packets_sent(self : BandwidthLink) -> Int {
self.packets_sent
}
///|
pub fn BandwidthLink::packets_delivered(self : BandwidthLink) -> Int {
self.packets_delivered
}
///|
pub fn BandwidthLink::overflow_drops(self : BandwidthLink) -> Int {
self.overflow_drops
}
///|
pub fn BandwidthLink::mean_queueing_delay(self : BandwidthLink) -> Double {
if self.packets_delivered == 0 {
0.0
} else {
self.total_queueing_delay / Double::from_int(self.packets_delivered)
}
}