in neqo-transport/src/cc/classic_cc.rs [1059:1136]
fn app_limited_slow_start() {
const BELOW_APP_LIMIT_PKTS: usize = 5;
const ABOVE_APP_LIMIT_PKTS: usize = BELOW_APP_LIMIT_PKTS + 1;
let mut cc = ClassicCongestionControl::new(NewReno::default(), Pmtud::new(IP_ADDR, MTU));
let cwnd = cc.congestion_window;
let mut now = now();
let mut next_pn = 0;
// simulate packet bursts below app_limit
for packet_burst_size in 1..=BELOW_APP_LIMIT_PKTS {
// always stay below app_limit during sent.
let mut pkts = Vec::new();
for _ in 0..packet_burst_size {
let p = SentPacket::new(
PacketType::Short,
next_pn,
now,
true,
Vec::new(),
cc.max_datagram_size(),
);
next_pn += 1;
cc.on_packet_sent(&p, now);
pkts.push(p);
}
assert_eq!(
cc.bytes_in_flight(),
packet_burst_size * cc.max_datagram_size()
);
now += RTT;
cc.on_packets_acked(&pkts, &RttEstimate::default(), now);
assert_eq!(cc.bytes_in_flight(), 0);
assert_eq!(cc.acked_bytes, 0);
assert_eq!(cwnd, cc.congestion_window); // CWND doesn't grow because we're app limited
}
// Fully utilize the congestion window by sending enough packets to
// have `bytes_in_flight` above the `app_limited` threshold.
let mut pkts = Vec::new();
for _ in 0..ABOVE_APP_LIMIT_PKTS {
let p = SentPacket::new(
PacketType::Short,
next_pn,
now,
true,
Vec::new(),
cc.max_datagram_size(),
);
next_pn += 1;
cc.on_packet_sent(&p, now);
pkts.push(p);
}
assert_eq!(
cc.bytes_in_flight(),
ABOVE_APP_LIMIT_PKTS * cc.max_datagram_size()
);
now += RTT;
// Check if congestion window gets increased for all packets currently in flight
for (i, pkt) in pkts.into_iter().enumerate() {
cc.on_packets_acked(&[pkt], &RttEstimate::default(), now);
assert_eq!(
cc.bytes_in_flight(),
(ABOVE_APP_LIMIT_PKTS - i - 1) * cc.max_datagram_size()
);
// increase acked_bytes with each packet
qinfo!(
"{} {}",
cc.congestion_window,
cwnd + i * cc.max_datagram_size()
);
assert_eq!(
cc.congestion_window,
cwnd + (i + 1) * cc.max_datagram_size()
);
assert_eq!(cc.acked_bytes, 0);
}
}