Skip to content
10 changes: 8 additions & 2 deletions apps/src/bin/quiche-server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -541,8 +541,14 @@ fn main() {
continue_write = false;
for client in clients.values_mut() {
// Reduce max_send_burst by 25% if loss is increasing more than 0.1%.
let loss_rate =
client.conn.stats().lost as f64 / client.conn.stats().sent as f64;
let stats = client.conn.stats();
let finished = stats.acked.saturating_add(stats.lost);
let loss_rate = if finished == 0 {
0.0
} else {
stats.lost as f64 / finished as f64
};

if loss_rate > client.loss_rate + 0.001 {
client.max_send_burst = client.max_send_burst / 4 * 3;
// Minimum bound of 10xMSS.
Expand Down
3 changes: 3 additions & 0 deletions quiche/include/quiche.h
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,9 @@ typedef struct {
// The number of QUIC packets sent on this connection.
size_t sent;

// The number of QUIC packets that were acked.
size_t acked;

// The number of QUIC packets that were lost.
size_t lost;

Expand Down
2 changes: 2 additions & 0 deletions quiche/src/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1335,6 +1335,7 @@ pub extern "C" fn quiche_stream_iter_free(iter: *mut StreamIter) {
pub struct Stats {
recv: usize,
sent: usize,
acked: usize,
lost: usize,
spurious_lost: usize,
retrans: usize,
Expand Down Expand Up @@ -1383,6 +1384,7 @@ pub extern "C" fn quiche_conn_stats(conn: &Connection, out: &mut Stats) {

out.recv = stats.recv;
out.sent = stats.sent;
out.acked = stats.acked;
out.lost = stats.lost;
out.spurious_lost = stats.spurious_lost;
out.retrans = stats.retrans;
Expand Down
10 changes: 10 additions & 0 deletions quiche/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1389,6 +1389,9 @@ where
/// Total number of sent packets.
sent_count: usize,

/// Total number of acked packets.
acked_count: usize,

/// Total number of lost packets.
lost_count: usize,

Expand Down Expand Up @@ -2115,6 +2118,7 @@ impl<F: BufFactory> Connection<F> {

recv_count: 0,
sent_count: 0,
acked_count: 0,
lost_count: 0,
spurious_lost_count: 0,
retrans_count: 0,
Expand Down Expand Up @@ -7792,6 +7796,7 @@ impl<F: BufFactory> Connection<F> {
Stats {
recv: self.recv_count,
sent: self.sent_count,
acked: self.acked_count,
lost: self.lost_count,
spurious_lost: self.spurious_lost_count,
retrans: self.retrans_count,
Expand Down Expand Up @@ -8306,6 +8311,7 @@ impl<F: BufFactory> Connection<F> {
let OnAckReceivedOutcome {
lost_packets,
lost_bytes,
acked_packets,
acked_bytes,
spurious_losses,
} = p.recovery.on_ack_received(
Expand Down Expand Up @@ -8334,6 +8340,7 @@ impl<F: BufFactory> Connection<F> {

self.lost_count += lost_packets;
self.lost_bytes += lost_bytes as u64;
self.acked_count += acked_packets;
self.acked_bytes += acked_bytes as u64;
self.spurious_lost_count += spurious_losses;
}
Expand Down Expand Up @@ -9363,6 +9370,9 @@ pub struct Stats {
/// The number of QUIC packets sent.
pub sent: usize,

/// The number of QUIC packets that were acked.
pub acked: usize,

/// The number of QUIC packets that were lost.
pub lost: usize,

Expand Down
1 change: 1 addition & 0 deletions quiche/src/recovery/congestion/delivery_rate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,7 @@ mod tests {
assert_eq!(ack_outcome, OnAckReceivedOutcome {
lost_packets: 0,
lost_bytes: 0,
acked_packets: packet_count,
acked_bytes: mss * packet_count,
spurious_losses: 0,
});
Expand Down
7 changes: 7 additions & 0 deletions quiche/src/recovery/congestion/recovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ struct RecoveryEpoch {
}

struct AckedDetectionResult {
acked_packets: usize,
acked_bytes: usize,
spurious_losses: usize,
spurious_pkt_thresh: Option<u64>,
Expand All @@ -120,6 +121,7 @@ impl RecoveryEpoch {
) -> Result<AckedDetectionResult> {
newly_acked.clear();

let mut acked_packets = 0;
let mut acked_bytes = 0;
let mut spurious_losses = 0;
let mut spurious_pkt_thresh = None;
Expand Down Expand Up @@ -177,6 +179,8 @@ impl RecoveryEpoch {
has_in_flight_spurious_loss = true;
}
} else {
acked_packets += 1;

if unacked.in_flight {
self.in_flight_count -= 1;
acked_bytes += unacked.size;
Expand Down Expand Up @@ -208,6 +212,7 @@ impl RecoveryEpoch {
self.drain_acked_and_lost_packets(now - rtt_stats.rtt());

Ok(AckedDetectionResult {
acked_packets,
acked_bytes,
spurious_losses,
spurious_pkt_thresh,
Expand Down Expand Up @@ -642,6 +647,7 @@ impl RecoveryOps for LegacyRecovery {
trace_id: &str,
) -> Result<OnAckReceivedOutcome> {
let AckedDetectionResult {
acked_packets,
acked_bytes,
spurious_losses,
spurious_pkt_thresh,
Expand Down Expand Up @@ -719,6 +725,7 @@ impl RecoveryOps for LegacyRecovery {
Ok(OnAckReceivedOutcome {
lost_packets,
lost_bytes,
acked_packets,
acked_bytes,
spurious_losses,
})
Expand Down
8 changes: 8 additions & 0 deletions quiche/src/recovery/gcongestion/recovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ struct RecoveryEpoch {
}

struct AckedDetectionResult {
acked_packets: usize,
acked_bytes: usize,
spurious_losses: usize,
spurious_pkt_thresh: Option<u64>,
Expand Down Expand Up @@ -171,6 +172,7 @@ impl RecoveryEpoch {
) -> Result<AckedDetectionResult> {
newly_acked.clear();

let mut acked_packets = 0;
let mut acked_bytes = 0;
let mut spurious_losses = 0;
let mut spurious_pkt_thresh = None;
Expand Down Expand Up @@ -220,6 +222,8 @@ impl RecoveryEpoch {
ack_eliciting,
..
} => {
acked_packets += 1;

if in_flight {
self.pkts_in_flight -= 1;
acked_bytes += sent_bytes;
Expand Down Expand Up @@ -253,6 +257,7 @@ impl RecoveryEpoch {
self.drain_acked_and_lost_packets();

Ok(AckedDetectionResult {
acked_packets,
acked_bytes,
spurious_losses,
spurious_pkt_thresh,
Expand Down Expand Up @@ -781,6 +786,7 @@ impl RecoveryOps for GRecovery {
let prior_in_flight = self.bytes_in_flight.get();

let AckedDetectionResult {
acked_packets,
acked_bytes,
spurious_losses,
spurious_pkt_thresh,
Expand All @@ -799,6 +805,7 @@ impl RecoveryOps for GRecovery {

if self.newly_acked.is_empty() {
return Ok(OnAckReceivedOutcome {
acked_packets,
acked_bytes,
spurious_losses,
..Default::default()
Expand Down Expand Up @@ -855,6 +862,7 @@ impl RecoveryOps for GRecovery {
Ok(OnAckReceivedOutcome {
lost_packets,
lost_bytes,
acked_packets,
acked_bytes,
spurious_losses,
})
Expand Down
Loading