lsalzman / enet

ENet reliable UDP networking library
MIT License
2.71k stars 668 forks source link

fix/improve calculations of roundTripTime[Variance] #117

Closed virt00l closed 4 years ago

virt00l commented 4 years ago

This commit contains several fixes/improvements

1) Calculation of roundTripTimeVariance was performed slightly incorrectly - it used new updated value of roundTripTime, as opposed to prev one, which should be used as described in https://tools.ietf.org/html/rfc6298#section-2 (Pt 2.3)

When a subsequent RTT measurement R' is made, a host MUST set

            RTTVAR <- (1 - beta) * RTTVAR + beta * |SRTT - R'|
            SRTT <- (1 - alpha) * SRTT + alpha * R'

         The value of SRTT used in the update to RTTVAR is its value
         before updating SRTT itself using the second assignment.  That
         is, updating RTTVAR and SRTT MUST be computed in the above
         order.

2) Apply/implement optimization from linux kernel for cases when RTT drops below (SRTT - RTTVAR) threshold, as described in "TCP/IP illustrated Volume 1" by Richard Stevens"

To address this issue, Linux handles the case where the RTT is decreasing by giving
less weight to the new sample if it is below the "lower end" of the estimated RTT
range (srtt - mdev). The complete relationship is as follows:
if (m < (srtt - mdev))
 mdev = (31/32) * mdev + (1/32) * |srtt - m|
else
 mdev = (3/4) * mdev + (1/4) * |srtt - m|
The conditional determines if the new RTT sample is below the bottom of the
range of what an RTT measurement is expected to be. If so, the new sample indicates that the connection may be experiencing a significantly reducing RTT. To
avoid increasing mdev (and consequently rttvar and RTO) in such cases, the new
mean deviation sample, |srtt - m|, is given an 8x reduced weight versus its normal weighting. Overall, this results in avoiding the problem of increasing the RTO
in cases where the RTT is decreasing.

see also https://github.com/torvalds/linux/blob/master/net/ipv4/tcp_input.c#L760

3) Also change initial value & calculation of roundTripTime as described here https://tools.ietf.org/html/rfc6298#section-2 (Pt 2.2)

When the first RTT measurement R is made, the host MUST set

            SRTT <- R
            RTTVAR <- R/2
            RTO <- SRTT + max (G, K*RTTVAR)

         where K = 4.

This should improve handling of RTO, esp on initial messages and/or low latency networks

lsalzman commented 4 years ago

I did a hand merge of these changes, as there were some formatting/style issues I wanted to correct. Also, I wanted to leave the initial roundTripTime value untouched as external users might depend on that, so I tracked initialization of the first ack via lastReceiveTime instead. I credited you in the commit.