Skip to content

Commit

Permalink
Add application limited checking
Browse files Browse the repository at this point in the history
  • Loading branch information
iyangsj committed Oct 29, 2024
1 parent 8af4622 commit e818720
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 35 deletions.
62 changes: 32 additions & 30 deletions src/congestion_control/delivery_rate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
//! A generic algorithm for a transport protocol sender to estimate the current
//! delivery rate of its data on the fly.
//!
//! See
//! <https://datatracker.ietf.org/doc/html/draft-cheng-iccrg-delivery-rate-estimation-02>.
//! See <https://datatracker.ietf.org/doc/html/draft-cheng-iccrg-delivery-rate-estimation-02>.
use std::time::Duration;
use std::time::Instant;
Expand All @@ -26,33 +25,32 @@ use crate::connection::space::{RateSamplePacketState, SentPacket};

/// Rate sample output.
///
/// See
/// <https://datatracker.ietf.org/doc/html/draft-cheng-iccrg-delivery-rate-estimation-02#section-3.1.3>.
/// See draft-cheng-iccrg-delivery-rate-estimation-02 Section 3.1.3
#[derive(Debug, Default)]
struct RateSample {
/// rs.delivery_rate: The delivery rate sample (in most cases rs.delivered / rs.interval).
/// The delivery rate sample (in most cases rs.delivered / rs.interval).
delivery_rate: u64,

/// rs.is_app_limited: The P.is_app_limited from the most recent packet delivered;
/// The P.is_app_limited from the most recent packet delivered;
/// indicates whether the rate sample is application-limited.
is_app_limited: bool,

/// rs.interval: The length of the sampling interval.
/// The length of the sampling interval.
interval: Duration,

/// rs.delivered: The amount of data marked as delivered over the sampling interval.
/// The amount of data marked as delivered over the sampling interval.
delivered: u64,

/// rs.prior_delivered: The P.delivered count from the most recent packet delivered.
/// The P.delivered count from the most recent packet delivered.
prior_delivered: u64,

/// rs.prior_time: The P.delivered_time from the most recent packet delivered.
/// The P.delivered_time from the most recent packet delivered.
prior_time: Option<Instant>,

/// rs.send_elapsed: Send time interval calculated from the most recent packet delivered.
/// Send time interval calculated from the most recent packet delivered.
send_elapsed: Duration,

/// rs.ack_elapsed: ACK time interval calculated from the most recent packet delivered.
/// ACK time interval calculated from the most recent packet delivered.
ack_elapsed: Duration,

/// sample rtt.
Expand All @@ -61,30 +59,32 @@ struct RateSample {

/// Delivery rate estimator.
///
/// <https://datatracker.ietf.org/doc/html/draft-cheng-iccrg-delivery-rate-estimation-02#section-3.1.1>.
/// See draft-cheng-iccrg-delivery-rate-estimation-02 Section-3.1.1
#[derive(Debug)]
pub struct DeliveryRateEstimator {
/// C.delivered: The total amount of data (measured in octets or in packets) delivered
/// so far over the lifetime of the transport connection. This does not include pure ACK packets.
/// The total amount of data (measured in octets or in packets) delivered so
/// far over the lifetime of the transport connection. This does not include
/// pure ACK packets.
delivered: u64,

/// C.delivered_time: The wall clock time when C.delivered was last updated.
/// The wall clock time when C.delivered was last updated.
delivered_time: Instant,

/// C.first_sent_time: If packets are in flight, then this holds the send time of the packet that
/// was most recently marked as delivered. Else, if the connection was recently idle, then this
/// holds the send time of most recently sent packet.
/// If packets are in flight, then this holds the send time of the packet
/// that was most recently marked as delivered. Else, if the connection was
/// recently idle, then this holds the send time of most recently sent packet.
first_sent_time: Instant,

/// C.app_limited: The index of the last transmitted packet marked as application-limited,
/// The index of the last transmitted packet marked as application-limited,
/// or 0 if the connection is not currently application-limited.
last_app_limited_pkt_num: u64,

/// Record largest acked packet number to determine if app-limited state exits.
/// Record largest acked packet number to determine if app-limited state
/// exits.
largest_acked_pkt_num: u64,

/// The last sent packet number.
/// If application-limited occurs, it will be the end of last_app_limited_pkt_num.
/// The last sent packet number. If application-limited occurs, it will be
/// the end of last_app_limited_pkt_num.
last_sent_pkt_num: u64,

/// Rate sample.
Expand All @@ -93,7 +93,7 @@ pub struct DeliveryRateEstimator {

impl DeliveryRateEstimator {
/// Upon each packet transmission.
/// See <https://datatracker.ietf.org/doc/html/draft-cheng-iccrg-delivery-rate-estimation-02#section-3.2>.
/// See draft-cheng-iccrg-delivery-rate-estimation-02 Section-3.2
pub fn on_packet_sent(
&mut self,
packet: &mut SentPacket,
Expand All @@ -117,7 +117,7 @@ impl DeliveryRateEstimator {
}

/// Update rate sampler (rs) when a packet is SACKed or ACKed.
/// See <https://datatracker.ietf.org/doc/html/draft-cheng-iccrg-delivery-rate-estimation-02#section-3.3>.
/// See draft-cheng-iccrg-delivery-rate-estimation-02 Section-3.3
pub fn update_rate_sample(&mut self, packet: &mut SentPacket) {
if packet.rate_sample_state.delivered_time.is_none() || packet.time_acked.is_none() {
// Packet already SACKed or packet not acked
Expand Down Expand Up @@ -169,11 +169,13 @@ impl DeliveryRateEstimator {
}

/// Upon receiving ACK, fill in delivery rate sample rs.
/// See <https://datatracker.ietf.org/doc/html/draft-cheng-iccrg-delivery-rate-estimation-02#section-3.3>.
/// See draft-cheng-iccrg-delivery-rate-estimation-02 Section-3.3
pub fn generate_rate_sample(&mut self) {
// For each newly SACKed or ACKed packet P,
// `UpdateRateSample(P, rs)`
// It's done before generate_rate_sample is called.
// Note: The following steps should be executed before calling generate_rate_sample()
// ```
// For each newly SACKed or ACKed packet P,
// UpdateRateSample(P, rs)
// ```

// Clear app-limited field if bubble is ACKed and gone.
if self.is_app_limited() && self.largest_acked_pkt_num > self.last_app_limited_pkt_num {
Expand Down Expand Up @@ -213,7 +215,7 @@ impl DeliveryRateEstimator {
}

/// Check if application limited.
/// See <https://datatracker.ietf.org/doc/html/draft-cheng-iccrg-delivery-rate-estimation-02#section-3.4>.
/// See draft-cheng-iccrg-delivery-rate-estimation-02 Section-3.4
pub fn is_app_limited(&self) -> bool {
self.last_app_limited_pkt_num != 0
}
Expand Down
5 changes: 1 addition & 4 deletions src/connection/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1577,6 +1577,7 @@ impl Connection {
}
}

self.paths.mark_app_limited(pid, done == 0);
if done == 0 {
return Err(Error::Done);
}
Expand Down Expand Up @@ -1827,9 +1828,6 @@ impl Connection {
);
}

// TODO: check app limited
// if write_status.in_flight == true and check app limited

let handshake_status = self.handshake_status();
self.paths.get_mut(path_id)?.recovery.on_packet_sent(
sent_pkt,
Expand Down Expand Up @@ -1990,7 +1988,6 @@ impl Connection {

// No frames to be sent
if st.frames.is_empty() {
// TODO: set app-limited
return Err(Error::Done);
}

Expand Down
8 changes: 8 additions & 0 deletions src/connection/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,14 @@ impl PathMap {
left
}

/// Mark whether it's currently limited by the application instead of
/// the connection window.
pub fn mark_app_limited(&mut self, pid: usize, run_out_of_data: bool) {
if let Some(path) = self.paths.get_mut(pid) {
path.recovery.mark_app_limited(run_out_of_data);
}
}

/// Schedule a Ping frame on the specified path or all active paths.
pub fn mark_ping(&mut self, path_addr: Option<FourTuple>) -> Result<()> {
// If multipath is not enabled, schedule a Ping frame on the current
Expand Down
15 changes: 14 additions & 1 deletion src/connection/recovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ pub struct Recovery {
/// Cache pkt size
pub cache_pkt_size: usize,

/// Whether the last `send` call yielded no packet because there was no
/// outgoing application data.
pub(super) is_app_limited: bool,

/// The time for last congestion window event
last_cwnd_limited_time: Option<Instant>,

Expand Down Expand Up @@ -141,6 +145,7 @@ impl Recovery {
pacer: Pacer::build_pacer_controller(conf),
pacer_timer: None,
cache_pkt_size: conf.max_datagram_size,
is_app_limited: false,
last_cwnd_limited_time: None,
stats: PathStats::default(),
#[cfg(feature = "qlog")]
Expand Down Expand Up @@ -365,7 +370,7 @@ impl Recovery {
self.congestion.on_ack(
sent_pkt,
now,
false,
self.is_app_limited,
&self.rtt,
self.bytes_in_flight as u64,
);
Expand Down Expand Up @@ -892,6 +897,14 @@ impl Recovery {
self.pacer_timer.is_none()
}

/// Mark whether the sender is currently limited by the application instead
/// of the congestion window.
pub(crate) fn mark_app_limited(&mut self, run_out_of_data: bool) {
self.is_app_limited = run_out_of_data
&& self.pacer_timer.is_none()
&& self.bytes_in_flight < self.congestion.congestion_window() as usize
}

/// Update statistics for the packet sent event
pub(crate) fn stat_sent_event(&mut self, sent_pkts: u64, sent_bytes: u64) {
self.stats.sent_count = self.stats.sent_count.saturating_add(sent_pkts);
Expand Down

0 comments on commit e818720

Please sign in to comment.