Line data Source code
1 : #ifndef HEADER_fd_waltz_fd_rtt_est_h 2 : #define HEADER_fd_waltz_fd_rtt_est_h 3 : 4 : /* fd_rtt_est.h provides an API to estimate RTT (round trip time) for 5 : packet transmissions to a single destination. The 'duration' unit in 6 : this file is arbitrary. Typically, it is measured in TSC ticks or 7 : nanoseconds. */ 8 : 9 : #include "../util/bits/fd_bits.h" 10 : #include <math.h> 11 : 12 : /* fd_rtt_estimate_t calculates RTT from samples according to RFC 9002 13 : Section 5: https://datatracker.ietf.org/doc/html/rfc9002#section-5 */ 14 : 15 : struct fd_rtt_estimate { 16 : /* Nanoseconds */ 17 : float latest_rtt; /* Latest sample */ 18 : float min_rtt; /* Smallest end-to-end RTT (trusted) */ 19 : float smoothed_rtt; /* EMA of last few samples */ 20 : float var_rtt; /* EMA of sample variance */ 21 : 22 : /* is_rtt_valid indicates at least one proper sample exists of rtt */ 23 : int is_rtt_valid; 24 : }; 25 : 26 : typedef struct fd_rtt_estimate fd_rtt_estimate_t; 27 : 28 : FD_PROTOTYPES_BEGIN 29 : 30 : /* fd_rtt_sample adds a RTT sample to the estimate. 31 : 32 : latest_rtt is the duration elapsed since a request was sent and a 33 : corresponding reply was received (this value originates from local 34 : timestamping). ack_delay is the duration that the peer delayed the 35 : reply by after receiving the request (this value is reported by the 36 : peer in the response). Outside of QUIC, ack_delay is typically 37 : zero/unknown. 38 : 39 : est->{latest_rtt,min_rtt,smoothed_rtt,var_rtt} are updated on return. 40 : fd_rtt_sample is robust against a maliciously chosen ack_delay. 41 : smoothed_rtt and latest_rtt are bounded by the smallest end-to-end 42 : RTT observation _before_ adjusting by ack_delay (min_rtt). */ 43 : 44 : static inline void 45 : fd_rtt_sample( fd_rtt_estimate_t * est, 46 : float latest_rtt, 47 243810 : float ack_delay ) { 48 243810 : float prev_min_rtt = fd_float_if( est->is_rtt_valid, est->min_rtt, FLT_MAX ); 49 : 50 : /* min_rtt is estimated from rtt_ticks without adjusting for ack_delay */ 51 243810 : est->min_rtt = fminf( prev_min_rtt, latest_rtt ); 52 : 53 : /* smoothed_rtt is calculated from adjusted rtt_ticks 54 : except: ack_delay must not be subtracted if the result would be less than minrtt */ 55 243810 : float adj_rtt = fmaxf( est->min_rtt, latest_rtt - ack_delay ); 56 : 57 243810 : est->latest_rtt = adj_rtt; 58 : 59 : /* Taken directly from RFC 9002 Section 5.3 */ 60 243810 : if( FD_UNLIKELY( !est->is_rtt_valid ) ) { 61 30 : est->smoothed_rtt = adj_rtt; 62 30 : est->var_rtt = adj_rtt * 0.5f; 63 30 : est->is_rtt_valid = 1; 64 243780 : } else { 65 243780 : est->smoothed_rtt = (7.f/8.f) * est->smoothed_rtt + (1.f/8.f) * adj_rtt; 66 243780 : float var_rtt_sample = fabsf( est->smoothed_rtt - adj_rtt ); 67 243780 : est->var_rtt = (3.f/4.f) * est->var_rtt + (1.f/4.f) * var_rtt_sample; 68 243780 : } 69 243810 : } 70 : 71 : FD_PROTOTYPES_END 72 : 73 : #endif /* HEADER_fd_waltz_fd_rtt_est_h */