Browse Source

reduce number of retransmits

pull/2101/head
orignal 2 months ago
parent
commit
cb0801fc16
  1. 48
      libi2pd/Streaming.cpp
  2. 7
      libi2pd/Streaming.h

48
libi2pd/Streaming.cpp

@ -76,7 +76,7 @@ namespace stream
m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_LocalDestination (local), m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_LocalDestination (local),
m_RemoteLeaseSet (remote), m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service), m_RemoteLeaseSet (remote), m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service),
m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (port), m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (port),
m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_SlowRTT2 (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0),
m_WindowDropTargetSize (0), m_WindowIncCounter (0), m_RTO (INITIAL_RTO), m_WindowDropTargetSize (0), m_WindowIncCounter (0), m_RTO (INITIAL_RTO),
m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_PrevRTTSample (INITIAL_RTT), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_PrevRTTSample (INITIAL_RTT),
m_Jitter (0), m_MinPacingTime (0), m_Jitter (0), m_MinPacingTime (0),
@ -103,7 +103,7 @@ namespace stream
m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (false), m_IsResendNeeded (false), m_IsFirstRttSample (false), m_IsSendTime (true), m_IsWinDropped (false),
m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_LocalDestination (local), m_IsTimeOutResend (false), m_IsImmediateAckRequested (false), m_LocalDestination (local),
m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service), m_ReceiveTimer (m_Service), m_SendTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service),
m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_SlowRTT2 (INITIAL_RTT),
m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowDropTargetSize (0), m_WindowIncCounter (0), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowDropTargetSize (0), m_WindowIncCounter (0),
m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()),
m_PrevRTTSample (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (0), m_PrevRTTSample (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (0),
@ -550,11 +550,18 @@ namespace stream
{ {
m_RTT = rttSample; m_RTT = rttSample;
m_SlowRTT = rttSample; m_SlowRTT = rttSample;
m_SlowRTT2 = rttSample;
m_PrevRTTSample = rttSample; m_PrevRTTSample = rttSample;
m_Jitter = rttSample / 10; // 10%
m_Jitter += 5; // for low-latency connections
m_IsFirstRttSample = false; m_IsFirstRttSample = false;
} }
else else
m_RTT = RTT_EWMA_ALPHA * rttSample + (1.0 - RTT_EWMA_ALPHA) * m_RTT; m_RTT = (m_PrevRTTSample + rttSample) / 2;
if (!m_IsWinDropped)
{
m_SlowRTT = SLOWRTT_EWMA_ALPHA * m_RTT + (1.0 - SLOWRTT_EWMA_ALPHA) * m_SlowRTT;
m_SlowRTT2 = RTT_EWMA_ALPHA * m_RTT + (1.0 - RTT_EWMA_ALPHA) * m_SlowRTT2;
// calculate jitter // calculate jitter
double jitter = 0; double jitter = 0;
if (rttSample > m_PrevRTTSample) if (rttSample > m_PrevRTTSample)
@ -562,15 +569,15 @@ namespace stream
else if (rttSample < m_PrevRTTSample) else if (rttSample < m_PrevRTTSample)
jitter = m_PrevRTTSample - rttSample; jitter = m_PrevRTTSample - rttSample;
else else
jitter = std::round (rttSample / 10); // 10% jitter = rttSample / 10; // 10%
jitter += 1; // for low-latency connections jitter += 5; // for low-latency connections
m_Jitter = (0.025 * jitter) + (1.0 - 0.025) * m_Jitter; m_Jitter = (0.05 * jitter) + (1.0 - 0.05) * m_Jitter;
}
// //
// delay-based CC // delay-based CC
if ((m_RTT > m_SlowRTT + m_Jitter && rttSample > m_RTT && rttSample > m_PrevRTTSample) && !m_IsWinDropped) // Drop window if RTT grows too fast, late detection if ((m_SlowRTT2 > m_SlowRTT + m_Jitter && rttSample > m_SlowRTT2 && rttSample > m_PrevRTTSample) && !m_IsWinDropped) // Drop window if RTT grows too fast, late detection
ProcessWindowDrop (); ProcessWindowDrop ();
UpdatePacingTime (); UpdatePacingTime ();
m_SlowRTT = SLOWRTT_EWMA_ALPHA * rttSample + (1.0 - SLOWRTT_EWMA_ALPHA) * m_SlowRTT;
m_PrevRTTSample = rttSample; m_PrevRTTSample = rttSample;
bool wasInitial = m_RTO == INITIAL_RTO; bool wasInitial = m_RTO == INITIAL_RTO;
@ -579,18 +586,23 @@ namespace stream
if (wasInitial) if (wasInitial)
ScheduleResend (); ScheduleResend ();
} }
if (ackThrough > m_DropWindowDelaySequenceNumber && m_WindowSize <= m_WindowDropTargetSize) if (m_IsWinDropped && ackThrough > m_DropWindowDelaySequenceNumber)
{
m_IsFirstRttSample = true;
m_IsWinDropped = false; m_IsWinDropped = false;
if (acknowledged && m_IsWinDropped && m_WindowSize > m_WindowDropTargetSize) }
if (m_WindowDropTargetSize && m_WindowSize <= m_WindowDropTargetSize)
{ {
if (ackCount > 1) m_WindowDropTargetSize = 0;
m_WindowSize = m_SentPackets.size () + 1; m_DropWindowDelaySequenceNumber = m_SequenceNumber;
else }
if (acknowledged && m_WindowDropTargetSize && m_WindowSize > m_WindowDropTargetSize)
{ {
m_WindowSize = m_SentPackets.size (); m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.5 + m_Jitter)); // we assume that the next rtt sample may be much larger than the current
m_IsResendNeeded = true; m_IsResendNeeded = true;
} m_WindowSize = m_SentPackets.size () + 1; // if there are no packets to resend, just send one regular packet
if (m_WindowSize < MIN_WINDOW_SIZE) m_WindowSize = MIN_WINDOW_SIZE; if (m_WindowSize < MIN_WINDOW_SIZE) m_WindowSize = MIN_WINDOW_SIZE;
if (m_WindowSize > MAX_WINDOW_SIZE) m_WindowSize = MAX_WINDOW_SIZE;
m_WindowIncCounter = 0; m_WindowIncCounter = 0;
UpdatePacingTime (); UpdatePacingTime ();
} }
@ -598,10 +610,10 @@ namespace stream
{ {
ScheduleResend (); ScheduleResend ();
} }
if ((m_SendBuffer.IsEmpty () && m_SentPackets.size () > 0) // tail loss if (m_SendBuffer.IsEmpty () && m_SentPackets.size () > 0) // tail loss
|| int(m_SentPackets.size ()) > m_WindowSize) // or we drop window
{ {
m_IsResendNeeded = true; m_IsResendNeeded = true;
m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.5 + m_Jitter)); // to prevent spurious retransmit
} }
if (m_SentPackets.empty () && m_SendBuffer.IsEmpty ()) if (m_SentPackets.empty () && m_SendBuffer.IsEmpty ())
{ {
@ -1304,7 +1316,7 @@ namespace stream
if (m_NumResendAttempts == 1 && m_RTO != INITIAL_RTO) if (m_NumResendAttempts == 1 && m_RTO != INITIAL_RTO)
{ {
// loss-based CC // loss-based CC
if (!m_IsWinDropped) if (!m_IsWinDropped && LOSS_BASED_CONTROL_ENABLED)
ProcessWindowDrop (); ProcessWindowDrop ();
} }
else if (m_IsTimeOutResend) else if (m_IsTimeOutResend)

7
libi2pd/Streaming.h

@ -56,8 +56,8 @@ namespace stream
const int INITIAL_WINDOW_SIZE = 10; const int INITIAL_WINDOW_SIZE = 10;
const int MIN_WINDOW_SIZE = 2; const int MIN_WINDOW_SIZE = 2;
const int MAX_WINDOW_SIZE = 512; const int MAX_WINDOW_SIZE = 512;
const double RTT_EWMA_ALPHA = 0.25; const double RTT_EWMA_ALPHA = 0.5;
const double SLOWRTT_EWMA_ALPHA = 0.125; const double SLOWRTT_EWMA_ALPHA = 0.05;
const double PREV_SPEED_KEEP_TIME_COEFF = 0.35; // 0.1 - 1 // how long will the window size stay around the previous drop level, less is longer const double PREV_SPEED_KEEP_TIME_COEFF = 0.35; // 0.1 - 1 // how long will the window size stay around the previous drop level, less is longer
const int MIN_RTO = 20; // in milliseconds const int MIN_RTO = 20; // in milliseconds
const int INITIAL_RTT = 8000; // in milliseconds const int INITIAL_RTT = 8000; // in milliseconds
@ -72,6 +72,7 @@ namespace stream
const uint64_t SEND_INTERVAL = 1000; // in microseconds const uint64_t SEND_INTERVAL = 1000; // in microseconds
const uint64_t REQUEST_IMMEDIATE_ACK_INTERVAL = 7500; // in milliseconds const uint64_t REQUEST_IMMEDIATE_ACK_INTERVAL = 7500; // in milliseconds
const uint64_t REQUEST_IMMEDIATE_ACK_INTERVAL_VARIANCE = 3200; // in milliseconds const uint64_t REQUEST_IMMEDIATE_ACK_INTERVAL_VARIANCE = 3200; // in milliseconds
const bool LOSS_BASED_CONTROL_ENABLED = 1; // 0/1
struct Packet struct Packet
{ {
@ -282,7 +283,7 @@ namespace stream
uint16_t m_Port; uint16_t m_Port;
SendBufferQueue m_SendBuffer; SendBufferQueue m_SendBuffer;
double m_RTT, m_SlowRTT; double m_RTT, m_SlowRTT, m_SlowRTT2;
float m_WindowSize, m_LastWindowDropSize, m_WindowDropTargetSize; float m_WindowSize, m_LastWindowDropSize, m_WindowDropTargetSize;
int m_WindowIncCounter, m_RTO, m_AckDelay, m_PrevRTTSample; int m_WindowIncCounter, m_RTO, m_AckDelay, m_PrevRTTSample;
double m_Jitter; double m_Jitter;

Loading…
Cancel
Save