Skip to content

Commit

Permalink
Add FFI for path level stats
Browse files Browse the repository at this point in the history
  • Loading branch information
iyangsj committed Jul 14, 2024
1 parent 26c6586 commit ed9140e
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 21 deletions.
103 changes: 103 additions & 0 deletions include/tquic.h
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,100 @@ typedef struct quic_path_address_t {
socklen_t remote_addr_len;
} quic_path_address_t;

/**
* Statistics about path
*/
typedef struct PathStats {
/**
* The number of QUIC packets received.
*/
uint64_t recv_count;
/**
* The number of received bytes.
*/
uint64_t recv_bytes;
/**
* The number of QUIC packets sent.
*/
uint64_t sent_count;
/**
* The number of sent bytes.
*/
uint64_t sent_bytes;
/**
* The number of QUIC packets lost.
*/
uint64_t lost_count;
/**
* The number of lost bytes.
*/
uint64_t lost_bytes;
/**
* Total number of bytes acked.
*/
uint64_t acked_bytes;
/**
* Total number of packets acked.
*/
uint64_t acked_count;
/**
* Initial congestion window in bytes.
*/
uint64_t init_cwnd;
/**
* Final congestion window in bytes.
*/
uint64_t final_cwnd;
/**
* Maximum congestion window in bytes.
*/
uint64_t max_cwnd;
/**
* Minimum congestion window in bytes.
*/
uint64_t min_cwnd;
/**
* Maximum inflight data in bytes.
*/
uint64_t max_inflight;
/**
* Total loss events.
*/
uint64_t loss_event_count;
/**
* Total congestion window limited events.
*/
uint64_t cwnd_limited_count;
/**
* Total duration of congestion windowlimited events in microseconds.
*/
uint64_t cwnd_limited_duration;
/**
* Minimum roundtrip time in microseconds.
*/
uint64_t min_rtt;
/**
* Maximum roundtrip time in microseconds.
*/
uint64_t max_rtt;
/**
* Smoothed roundtrip time in microseconds.
*/
uint64_t srtt;
/**
* Roundtrip time variation in microseconds.
*/
uint64_t rttvar;
/**
* Whether the congestion controller is in slow start status.
*/
bool in_slow_start;
/**
* Pacing rate estimated by congestion control algorithm.
*/
uint64_t pacing_rate;
} PathStats;

/**
* Statistics about a QUIC connection.
*/
Expand Down Expand Up @@ -910,6 +1004,15 @@ bool quic_conn_path_iter_next(struct quic_path_address_iter_t *iter, struct quic
*/
bool quic_conn_active_path(const struct quic_conn_t *conn, struct quic_path_address_t *a);

/**
* Return the latest statistics about the specified path.
*/
const struct PathStats *quic_conn_path_stats(struct quic_conn_t *conn,
const struct sockaddr *local,
socklen_t local_len,
const struct sockaddr *remote,
socklen_t remote_len);

/**
* Return statistics about the connection.
*/
Expand Down
14 changes: 14 additions & 0 deletions src/connection/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ use crate::FourTupleIter;
use crate::MultipathConfig;
use crate::PacketInfo;
use crate::PathEvent;
use crate::PathStats;
use crate::RecoveryConfig;
use crate::Result;
use crate::Shutdown;
Expand Down Expand Up @@ -3584,6 +3585,19 @@ impl Connection {
self.paths.get_active()
}

/// Return an mutable reference to the specified path
pub fn get_path_stats(
&mut self,
local_addr: SocketAddr,
remote_addr: SocketAddr,
) -> Result<&crate::PathStats> {
let pid = self
.paths
.get_path_id(&(local_addr, remote_addr))
.ok_or(Error::InvalidOperation("not found".into()))?;
Ok(self.paths.get_mut(pid)?.stats())
}

/// Migrates the connection to the specified path.
#[doc(hidden)]
pub fn migrate_path(&mut self, local_addr: SocketAddr, remote_addr: SocketAddr) -> Result<()> {
Expand Down
21 changes: 13 additions & 8 deletions src/connection/recovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ pub struct Recovery {
/// Cache pkt size
pub cache_pkt_size: usize,

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

/// Path level Statistics.
pub stats: PathStats,

Expand Down Expand Up @@ -135,6 +138,7 @@ impl Recovery {
pacer: Pacer::build_pacer_controller(conf),
pacer_timer: None,
cache_pkt_size: conf.max_datagram_size,
last_cwnd_limited_time: None,
stats: PathStats::default(),
last_metrics: RecoveryMetrics::default(),
trace_id: String::from(""),
Expand Down Expand Up @@ -903,29 +907,30 @@ impl Recovery {
pub(crate) fn stat_cwnd_limited(&mut self) {
let is_cwnd_limited = !self.can_send();
let now = Instant::now();
if let Some(last_cwnd_limited_time) = self.stats.last_cwnd_limited_time {
if let Some(last_cwnd_limited_time) = self.last_cwnd_limited_time {
// Update duration timely, in case it stays in cwnd limited all the time.
let duration = now.saturating_duration_since(last_cwnd_limited_time);
let duration = duration.as_millis() as u64;
self.stats.cwnd_limited_duration =
self.stats.cwnd_limited_duration.saturating_add(duration);
if is_cwnd_limited {
self.stats.last_cwnd_limited_time = Some(now);
self.last_cwnd_limited_time = Some(now);
} else {
self.stats.last_cwnd_limited_time = None;
self.last_cwnd_limited_time = None;
}
} else if is_cwnd_limited {
// A new cwnd limited event
self.stats.cwnd_limited_count = self.stats.cwnd_limited_count.saturating_add(1);
self.stats.last_cwnd_limited_time = Some(now);
self.last_cwnd_limited_time = Some(now);
}
}

/// Update with the latest values from recovery.
pub(crate) fn stat_lazy_update(&mut self) {
self.stats.min_rtt = self.rtt.min_rtt();
self.stats.max_rtt = self.rtt.max_rtt();
self.stats.srtt = self.rtt.smoothed_rtt();
self.stats.rttvar = self.rtt.rttvar();
self.stats.min_rtt = self.rtt.min_rtt().as_micros() as u64;
self.stats.max_rtt = self.rtt.max_rtt().as_micros() as u64;
self.stats.srtt = self.rtt.smoothed_rtt().as_micros() as u64;
self.stats.rttvar = self.rtt.rttvar().as_micros() as u64;
self.stats.in_slow_start = self.congestion.in_slow_start();
self.stats.pacing_rate = self.congestion.pacing_rate().unwrap_or_default();
}
Expand Down
17 changes: 17 additions & 0 deletions src/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1085,6 +1085,23 @@ pub extern "C" fn quic_conn_active_path(conn: &Connection, a: &mut PathAddress)
false
}

/// Return the latest statistics about the specified path.
#[no_mangle]
pub extern "C" fn quic_conn_path_stats<'a>(
conn: &'a mut Connection,
local: &sockaddr,
local_len: socklen_t,
remote: &sockaddr,
remote_len: socklen_t,
) -> Option<&'a PathStats> {
let local_addr = sock_addr_from_c(local, local_len);
let remote_addr = sock_addr_from_c(remote, remote_len);
if let Ok(stats) = conn.get_path_stats(local_addr, remote_addr) {
return Some(stats);
}
None
}

/// Return statistics about the connection.
#[no_mangle]
pub extern "C" fn quic_conn_stats(conn: &mut Connection) -> &ConnectionStats {
Expand Down
23 changes: 10 additions & 13 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1036,24 +1036,21 @@ pub struct PathStats {
/// Total congestion window limited events.
pub cwnd_limited_count: u64,

/// Total duration of congestion windowlimited events.
pub cwnd_limited_duration: Duration,

/// The time for last congestion window event
last_cwnd_limited_time: Option<Instant>,
/// Total duration of congestion windowlimited events in microseconds.
pub cwnd_limited_duration: u64,

/* Note: the following fields are lazily updated from Recovery */
/// Minimum roundtrip time.
pub min_rtt: Duration,
/// Minimum roundtrip time in microseconds.
pub min_rtt: u64,

/// Maximum roundtrip time.
pub max_rtt: Duration,
/// Maximum roundtrip time in microseconds.
pub max_rtt: u64,

/// Smoothed roundtrip time.
pub srtt: Duration,
/// Smoothed roundtrip time in microseconds.
pub srtt: u64,

/// Roundtrip time variation.
pub rttvar: Duration,
/// Roundtrip time variation in microseconds.
pub rttvar: u64,

/// Whether the congestion controller is in slow start status.
pub in_slow_start: bool,
Expand Down

0 comments on commit ed9140e

Please sign in to comment.