Skip to content

Commit b048c85

Browse files
junhochoighedo
authored andcommitted
delivery rate estimation: draft 01
- Update delivery rate implementation to draft 01. - Major rework on delivery rate estimation. - `estimate()` is removed - it will be done in `generate_rate_sample()` after calling `update_rate_sample()` in each ack, as specified in the draft. - Rate estimation is only checked in Application packet number space. - Expose some functions for later use, such as `recovery.delivery_rate.app_limited()` returns `C.app_limited != 0`, `recovery.delivery_rate._delivered()` returns `rs.delivered`, `recovery.delivery_rate.sample_is_app_limited()` returns `rs.is_app_limited`. - `C.app_limited`: now we use the packet number instead of the byte range. `largest_acked` and `last_sent_packet` is added for tracking packet number. This is used for rate sample and separately updated from `recovery.app_limited`. - Custom debug fmt() is removed and use a default Debug trait. - Tests are rewritten.
1 parent be37a83 commit b048c85

File tree

5 files changed

+469
-239
lines changed

5 files changed

+469
-239
lines changed

quiche/src/lib.rs

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,9 @@ pub struct Connection {
10791079
/// Peer's flow control limit for the connection.
10801080
max_tx_data: u64,
10811081

1082+
/// Last tx_data before running a full send() loop.
1083+
last_tx_data: u64,
1084+
10821085
/// Total number of bytes the server can send before the peer's address
10831086
/// is verified.
10841087
max_send_bytes: usize,
@@ -1517,6 +1520,7 @@ impl Connection {
15171520

15181521
tx_data: 0,
15191522
max_tx_data: 0,
1523+
last_tx_data: 0,
15201524

15211525
stream_retrans_bytes: 0,
15221526

@@ -2581,6 +2585,8 @@ impl Connection {
25812585
}
25822586

25832587
if done == 0 {
2588+
self.last_tx_data = self.tx_data;
2589+
25842590
return Err(Error::Done);
25852591
}
25862592

@@ -3460,11 +3466,15 @@ impl Connection {
34603466
in_flight,
34613467
delivered: 0,
34623468
delivered_time: now,
3463-
recent_delivered_packet_sent_time: now,
3469+
first_sent_time: now,
34643470
is_app_limited: false,
34653471
has_data,
34663472
};
34673473

3474+
if in_flight && self.delivery_rate_check_if_app_limited() {
3475+
self.recovery.delivery_rate_update_app_limited(true);
3476+
}
3477+
34683478
self.recovery.on_packet_sent(
34693479
sent_pkt,
34703480
epoch,
@@ -3768,8 +3778,6 @@ impl Connection {
37683778

37693779
self.tx_data += sent as u64;
37703780

3771-
self.recovery.rate_check_app_limited();
3772-
37733781
qlog_with_type!(QLOG_DATA_MV, self.qlog, q, {
37743782
let ev_data = EventData::DataMoved(qlog::events::quic::DataMoved {
37753783
stream_id: Some(stream_id),
@@ -5010,6 +5018,10 @@ impl Connection {
50105018
self.handshake_confirmed = true;
50115019
}
50125020

5021+
if self.delivery_rate_check_if_app_limited() {
5022+
self.recovery.delivery_rate_update_app_limited(true);
5023+
}
5024+
50135025
self.recovery.on_ack_received(
50145026
&ranges,
50155027
ack_delay,
@@ -5441,6 +5453,28 @@ impl Connection {
54415453
self.max_tx_data - self.tx_data,
54425454
) as usize;
54435455
}
5456+
5457+
fn delivery_rate_check_if_app_limited(&self) -> bool {
5458+
// Enter the app-limited phase of delivery rate when these conditions
5459+
// are met:
5460+
//
5461+
// - The remaining capacity is higher than available bytes in cwnd (there
5462+
// is more room to send).
5463+
// - New data since the last send() is smaller than available bytes in
5464+
// cwnd (we queued less than what we can send).
5465+
// - There is room to send more data in cwnd.
5466+
//
5467+
// In application-limited phases the transmission rate is limited by the
5468+
// application rather than the congestion control algorithm.
5469+
//
5470+
// Note that this is equivalent to CheckIfApplicationLimited() from the
5471+
// delivery rate draft. This is also separate from `recovery.app_limited`
5472+
// and only applies to delivery rate calculation.
5473+
self.tx_cap >= self.recovery.cwnd_available() &&
5474+
(self.tx_data - self.last_tx_data) <
5475+
self.recovery.cwnd_available() as u64 &&
5476+
self.recovery.cwnd_available() > 0
5477+
}
54445478
}
54455479

54465480
/// Maps an `Error` to `Error::Done`, or itself.

quiche/src/recovery/cubic.rs

Lines changed: 79 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@ mod tests {
482482
in_flight: true,
483483
delivered: 0,
484484
delivered_time: now,
485-
recent_delivered_packet_sent_time: now,
485+
first_sent_time: now,
486486
is_app_limited: false,
487487
has_data: false,
488488
};
@@ -498,6 +498,11 @@ mod tests {
498498
pkt_num: p.pkt_num,
499499
time_sent: p.time_sent,
500500
size: p.size,
501+
delivered: 0,
502+
delivered_time: now,
503+
first_sent_time: now,
504+
is_app_limited: false,
505+
rtt: Duration::ZERO,
501506
}];
502507

503508
r.on_packets_acked(acked, packet::EPOCH_APPLICATION, now);
@@ -525,7 +530,7 @@ mod tests {
525530
in_flight: true,
526531
delivered: 0,
527532
delivered_time: now,
528-
recent_delivered_packet_sent_time: now,
533+
first_sent_time: now,
529534
is_app_limited: false,
530535
has_data: false,
531536
};
@@ -542,16 +547,31 @@ mod tests {
542547
pkt_num: p.pkt_num,
543548
time_sent: p.time_sent,
544549
size: p.size,
550+
delivered: 0,
551+
delivered_time: now,
552+
first_sent_time: now,
553+
is_app_limited: false,
554+
rtt: Duration::ZERO,
545555
},
546556
Acked {
547557
pkt_num: p.pkt_num,
548558
time_sent: p.time_sent,
549559
size: p.size,
560+
delivered: 0,
561+
delivered_time: now,
562+
first_sent_time: now,
563+
is_app_limited: false,
564+
rtt: Duration::ZERO,
550565
},
551566
Acked {
552567
pkt_num: p.pkt_num,
553568
time_sent: p.time_sent,
554569
size: p.size,
570+
delivered: 0,
571+
delivered_time: now,
572+
first_sent_time: now,
573+
is_app_limited: false,
574+
rtt: Duration::ZERO,
555575
},
556576
];
557577

@@ -626,6 +646,11 @@ mod tests {
626646
pkt_num: 0,
627647
time_sent: now,
628648
size: r.max_datagram_size,
649+
delivered: 0,
650+
delivered_time: now,
651+
first_sent_time: now,
652+
is_app_limited: false,
653+
rtt: Duration::ZERO,
629654
}];
630655

631656
r.on_packets_acked(acked, packet::EPOCH_APPLICATION, now);
@@ -666,6 +691,11 @@ mod tests {
666691
// To exit from recovery
667692
time_sent: now + Duration::from_millis(1),
668693
size: r.max_datagram_size,
694+
delivered: 0,
695+
delivered_time: now,
696+
first_sent_time: now,
697+
is_app_limited: false,
698+
rtt: Duration::ZERO,
669699
}];
670700

671701
r.on_packets_acked(acked, packet::EPOCH_APPLICATION, now);
@@ -698,7 +728,7 @@ mod tests {
698728
in_flight: true,
699729
delivered: 0,
700730
delivered_time: now,
701-
recent_delivered_packet_sent_time: now,
731+
first_sent_time: now,
702732
is_app_limited: false,
703733
has_data: false,
704734
};
@@ -727,6 +757,11 @@ mod tests {
727757
pkt_num: ack_pn,
728758
time_sent: p.time_sent,
729759
size: p.size,
760+
delivered: 0,
761+
delivered_time: now,
762+
first_sent_time: now,
763+
is_app_limited: false,
764+
rtt: Duration::ZERO,
730765
}];
731766

732767
r.on_packets_acked(acked, epoch, now);
@@ -759,6 +794,11 @@ mod tests {
759794
pkt_num: ack_pn,
760795
time_sent: p.time_sent,
761796
size: p.size,
797+
delivered: 0,
798+
delivered_time: now,
799+
first_sent_time: now,
800+
is_app_limited: false,
801+
rtt: Duration::ZERO,
762802
}];
763803

764804
r.on_packets_acked(acked, epoch, now);
@@ -794,6 +834,11 @@ mod tests {
794834
pkt_num: ack_pn,
795835
time_sent: p.time_sent,
796836
size: p.size,
837+
delivered: 0,
838+
delivered_time: now,
839+
first_sent_time: now,
840+
is_app_limited: false,
841+
rtt: Duration::ZERO,
797842
}];
798843

799844
r.on_packets_acked(acked, epoch, now);
@@ -831,7 +876,7 @@ mod tests {
831876
in_flight: true,
832877
delivered: 0,
833878
delivered_time: now,
834-
recent_delivered_packet_sent_time: now,
879+
first_sent_time: now,
835880
is_app_limited: false,
836881
has_data: false,
837882
};
@@ -860,6 +905,11 @@ mod tests {
860905
pkt_num: ack_pn,
861906
time_sent: p.time_sent,
862907
size: p.size,
908+
delivered: 0,
909+
delivered_time: now,
910+
first_sent_time: now,
911+
is_app_limited: false,
912+
rtt: Duration::ZERO,
863913
}];
864914

865915
r.on_packets_acked(acked, epoch, now);
@@ -892,6 +942,11 @@ mod tests {
892942
pkt_num: ack_pn,
893943
time_sent: p.time_sent,
894944
size: p.size,
945+
delivered: 0,
946+
delivered_time: now,
947+
first_sent_time: now,
948+
is_app_limited: false,
949+
rtt: Duration::ZERO,
895950
}];
896951

897952
r.on_packets_acked(acked, epoch, now);
@@ -925,6 +980,11 @@ mod tests {
925980
pkt_num: ack_pn,
926981
time_sent: p.time_sent,
927982
size: p.size,
983+
delivered: 0,
984+
delivered_time: now,
985+
first_sent_time: now,
986+
is_app_limited: false,
987+
rtt: Duration::ZERO,
928988
}];
929989

930990
r.on_packets_acked(acked, epoch, now);
@@ -969,6 +1029,11 @@ mod tests {
9691029
// To exit from recovery
9701030
time_sent: now + rtt,
9711031
size: r.max_datagram_size,
1032+
delivered: 0,
1033+
delivered_time: now,
1034+
first_sent_time: now,
1035+
is_app_limited: false,
1036+
rtt: Duration::ZERO,
9721037
}];
9731038

9741039
// Ack more than cwnd bytes with rtt=100ms
@@ -1006,6 +1071,11 @@ mod tests {
10061071
// To exit from recovery
10071072
time_sent: now + rtt,
10081073
size: r.max_datagram_size,
1074+
delivered: 0,
1075+
delivered_time: now,
1076+
first_sent_time: now,
1077+
is_app_limited: false,
1078+
rtt: Duration::ZERO,
10091079
}];
10101080

10111081
// Ack more than cwnd bytes with rtt=100ms.
@@ -1065,6 +1135,11 @@ mod tests {
10651135
pkt_num: 0,
10661136
time_sent: now,
10671137
size: r.max_datagram_size,
1138+
delivered: 0,
1139+
delivered_time: now,
1140+
first_sent_time: now,
1141+
is_app_limited: false,
1142+
rtt: Duration::ZERO,
10681143
}];
10691144

10701145
r.on_packets_acked(acked, packet::EPOCH_APPLICATION, now);

0 commit comments

Comments
 (0)