Closed WesleyRosenblum closed 3 years ago
I really like the simplicity of the Chromium/Linux approach. It makes the change self-contained rather than introducing more complex state tracking. I also think it's always something we can go back and change if we're ok with the added complexity as well.
Agreed. And given I think we'll need to revisit some of this code anyway when implementing pacing it makes sense to start with a simpler approach until we have a better idea of how pacing will work.
I implemented something close to the Chromium approach, and while the results are much better, in the "Slow Start Unlimited" simulation we are still not doubling the congestion window each transmission round. The reason for this is that this simulation sends the full congestion window, and then acks the full congestion window (send and receive are not interleaved at all). Is such a scenario realistic?
Chromium approach:
Completely unconstrained:
I've implemented approach 4 in #474
With #474 the congestion window grows as expected in slow start:
If the application sends a burst of packets up to the congestion window size, when those packets are acked only the first one or two may result in an increased window as the window during the processing of the later acks will be considered "under utilized". This is because the acks may be processed in a burst before the application is able to send again. The result would be the congestion window increasing only by the MTU despite a full congestion window's worth of data being acknowledged.
The purpose of checking if the congestion window is under utilized before increasing the window is to ensure that we don't increase the window if the current window size has not been "tested" or "validated" by actually sending and acknowledging that many bytes. If we don't have this check, then the application may suddenly send a large amount of data, much larger than had been successfully sent before, and congestion may result. On the other hand, if this check is too strict (as it is now), we will not allow the window to grow fast enough.
See https://github.com/quinn-rs/quinn/pull/975 ("Extra slow slow start")
QUIC WG References
RFC 7661: Updating TCP to Support Rate-Limited Traffic
Congestion control during application limited state #2554
Define "under-utilization" of cwnd #2630
Other Implementsations
Chromium: TcpCubicSenderBytes::IsCwndLimited
Linux TCP: tcp_is_cwnd_limited
Facebook MVFST updateAppIdleState
Quiche update_app_limited
s2n-quic Implementation Options
Track application idle state in the Congestion Controller
This gets a little tricky, as there are several reasons why a non-idle application may not be able to send data (amplification limited, retransmissions only, etc). We'd only want to consider the connection to be application idle if the connection does not want to send anything, regardless of other limitations.
Follow the Chromium approach and just have more generous thresholds for deciding when application limited
on_packet_ack
, we check if we are under_utilized as we do today. If not, we set a timestamp to 1 RTT from now, and consider under_utilized to be false until we reach that timestamp, at which point we check it again.