Optimize per-packet stats tracking

- Don't increment counters every time we send or receive a packet, instead
do a bit more work to decide if stats need to be sent.

- Move some variables private
This commit is contained in:
Fletcher Dunn
2020-04-06 13:21:35 -07:00
parent 04de38d166
commit bbb2dfe7b0
2 changed files with 69 additions and 83 deletions
@@ -282,8 +282,6 @@ struct LinkStatsTrackerBase
inline void TrackSentPacket( int cbPktSize )
{
m_sent.ProcessPacket( cbPktSize );
++m_nPktsSentSinceSentInstantaneous;
++m_nPktsSentSinceSentLifetime;
}
/// Consume the next sequence number, and record the time at which
@@ -476,31 +474,10 @@ struct LinkStatsTrackerBase
SteamDatagramLinkLifetimeStats m_lifetimeRemote;
SteamNetworkingMicroseconds m_usecTimeRecvLifetimeRemote;
/// Local time when peer last acknowledged instantaneous stats.
SteamNetworkingMicroseconds m_usecPeerAckedInstaneous;
int64 m_pktNumInFlight;
bool m_bInFlightInstantaneous;
bool m_bInFlightLifetime;
/// Number of sequenced packets received since we last sent instantaneous stats
int m_nPktsRecvSeqSinceSentInstantaneous;
/// Number of packets we have sent, since we last sent instantaneous stats
int m_nPktsSentSinceSentInstantaneous;
/// Local time when we last sent lifetime stats.
SteamNetworkingMicroseconds m_usecPeerAckedLifetime;
/// Number of sequenced packets received since we last sent lifetime stats
int m_nPktsRecvSeqSinceSentLifetime;
int m_nPktsSentSinceSentLifetime;
/// We sent lifetime stats on this seq number, has not been acknowledged. <0 if none
//int m_seqnumUnackedSentLifetime;
/// We received lifetime stats at this sequence number, and should ack it soon. <0 if none
//int m_seqnumPendingAckRecvTimelife;
/// Time when the current interval started
SteamNetworkingMicroseconds m_usecIntervalStart;
@@ -545,14 +522,14 @@ struct LinkStatsTrackerBase
inline void PeerAckedInstantaneous( SteamNetworkingMicroseconds usecNow )
{
m_usecPeerAckedInstaneous = usecNow;
m_nPktsRecvSeqSinceSentInstantaneous = 0;
m_nPktsSentSinceSentInstantaneous = 0;
m_nPktsRecvSeqWhenPeerAckInstantaneous = m_nPktsRecvSequenced;
m_nPktsSentWhenPeerAckInstantaneous = m_sent.m_packets.Total();
}
inline void PeerAckedLifetime( SteamNetworkingMicroseconds usecNow )
{
m_usecPeerAckedLifetime = usecNow;
m_nPktsRecvSeqSinceSentLifetime = 0;
m_nPktsSentSinceSentLifetime = 0;
m_nPktsRecvSeqWhenPeerAckLifetime = m_nPktsRecvSequenced;
m_nPktsSentWhenPeerAckLifetime = m_sent.m_packets.Total();
}
void InFlightPktAck( SteamNetworkingMicroseconds usecNow )
@@ -666,6 +643,19 @@ protected:
private:
// Number of lifetime sequenced packets received, and overall packets sent,
// the last time the peer acked stats
int64 m_nPktsRecvSeqWhenPeerAckInstantaneous;
int64 m_nPktsSentWhenPeerAckInstantaneous;
int64 m_nPktsRecvSeqWhenPeerAckLifetime;
int64 m_nPktsSentWhenPeerAckLifetime;
/// Local time when peer last acknowledged lifetime stats.
SteamNetworkingMicroseconds m_usecPeerAckedLifetime;
/// Local time when peer last acknowledged instantaneous stats.
SteamNetworkingMicroseconds m_usecPeerAckedInstaneous;
bool BCheckHaveDataToSendInstantaneous( SteamNetworkingMicroseconds usecNow );
bool BCheckHaveDataToSendLifetime( SteamNetworkingMicroseconds usecNow );
@@ -309,12 +309,10 @@ bool LinkStatsTrackerBase::BCheckPacketNumberOldOrDuplicate( int64 nPktNum )
// Update stats
++m_nPktsRecvSequencedCurrentInterval;
++m_nPktsRecvSequenced;
++m_nPktsRecvSeqSinceSentLifetime;
++m_nPktsRecvSeqSinceSentInstantaneous;
// Packet number is increasing?
// (Maybe by a lot -- we don't handle that here.)
if ( nPktNum > m_nMaxRecvPktNum )
if ( likely( nPktNum > m_nMaxRecvPktNum ) )
return true;
// Which block of 64-bit packets is it in?
@@ -376,7 +374,7 @@ void LinkStatsTrackerBase::TrackProcessSequencedPacket( int64 nPktNum, SteamNetw
// case will be packets delivered in order, we optimize this logic
// for that case.
int64 nGap = nPktNum - m_nMaxRecvPktNum;
if ( nGap == 1 )
if ( likely( nGap == 1 ) )
{
// We've received two packets, in order. Did the sender supply the time between packets on his side?
@@ -398,66 +396,64 @@ void LinkStatsTrackerBase::TrackProcessSequencedPacket( int64 nPktNum, SteamNetw
}
}
else
else if ( unlikely( nGap <= 0 ) )
{
// Classify imperfection based on gap size.
if ( nGap >= 100 )
// Packet number moving backward
// We should have already rejected duplicates
Assert( nGap != 0 );
// Packet number moving in reverse.
// It should be a *small* negative step, e.g. packets delivered out of order.
// If the packet is really old, we should have already discarded it earlier.
Assert( nGap >= -8 * (int64)sizeof(m_recvPktNumberMask) );
++m_nPktsRecvOutOfOrder;
++m_nPktsRecvWeirdSequenceCurrentInterval;
// We previously counted this packet as dropped. Undo that, it wasn't dropped.
if ( m_nPktsRecvDropped > 0 )
{
--m_nPktsRecvDropped;
}
else
{
// This is weird.
AssertMsg8( false,
"No dropped packets, pkt num %lld -> %lld, dup bit not set? recvseq=%lld, lurch=%lld, ooo=%lld, mask=[0x%llx, 0x%llx]. (%s)",
(long long)m_nMaxRecvPktNum, (long long)nPktNum,
(long long)m_nPktsRecvSequenced, (long long)m_nPktsRecvSequenceNumberLurch,
(long long)m_nPktsRecvOutOfOrder,
(unsigned long long)m_recvPktNumberMask[0], (unsigned long long)m_recvPktNumberMask[1],
Describe().c_str()
);
}
if ( m_nPktsRecvDroppedCurrentInterval > 0 ) // Might have marked it in the previous interval. Our stats will be slightly off in this case. Not worth it to try to get this exactly right.
--m_nPktsRecvDroppedCurrentInterval;
return;
}
else
{
// Packet number moving forward, i.e. a dropped packet
// Large gap?
if ( unlikely( nGap >= 100 ) )
{
// Very weird.
++m_nPktsRecvSequenceNumberLurch;
++m_nPktsRecvWeirdSequenceCurrentInterval;
// Continue to code below, reseting the sequence number
// for packets going forward.
// Reset the sequence number for packets going forward.
InitMaxRecvPktNum( nPktNum );
return;
}
else if ( nGap > 0 )
{
// Probably the most common case, we just dropped a packet
int nDropped = nGap-1;
m_nPktsRecvDropped += nDropped;
m_nPktsRecvDroppedCurrentInterval += nDropped;
}
else if ( nGap == 0 )
{
// We should have already rejected duplicates
Assert( false );
}
else
{
// Packet number moving in reverse.
// It should be a *small* negative step, e.g. packets delivered out of order.
// If the packet is really old, we should have already discarded it earlier.
Assert( nGap >= -8 * (int64)sizeof(m_recvPktNumberMask) );
++m_nPktsRecvOutOfOrder;
++m_nPktsRecvWeirdSequenceCurrentInterval;
// We previously counted this packet as dropped. Undo that, it wasn't dropped.
if ( m_nPktsRecvDropped > 0 )
{
--m_nPktsRecvDropped;
}
else
{
// This is weird.
AssertMsg2( false,
"No dropped packets, pkt num %lld -> %lld, dup bit not set? recvseq=%lld, lurch=%lld, ooo=%lld. (%s)",
(long long)m_nMaxRecvPktNum, (long long)nPktNum,
(long long)m_nPktsRecvSequenced, (long long)m_nPktsRecvSequenceNumberLurch,
(long long)m_nPktsRecvOutOfOrder, Describe().c_str()
);
}
if ( m_nPktsRecvDroppedCurrentInterval > 0 ) // Might have marked it in the previous interval. Our stats will be slightly off in this case. Not worth it tro try to get this exactly right.
--m_nPktsRecvDroppedCurrentInterval;
}
// Probably the most common case (after a perfect packet stream), we just dropped a packet or two
int nDropped = nGap-1;
m_nPktsRecvDropped += nDropped;
m_nPktsRecvDroppedCurrentInterval += nDropped;
}
// Save highest known sequence number for next time.
if ( nGap > 0 )
{
m_nMaxRecvPktNum += nGap;
m_usecTimeLastRecvSeq = usecNow;
}
m_nMaxRecvPktNum = nPktNum;
m_usecTimeLastRecvSeq = usecNow;
}
bool LinkStatsTrackerBase::BCheckHaveDataToSendInstantaneous( SteamNetworkingMicroseconds usecNow )
@@ -474,8 +470,8 @@ bool LinkStatsTrackerBase::BCheckHaveDataToSendInstantaneous( SteamNetworkingMic
Assert( usecElapsed >= k_usecLinkStatsInstantaneousReportMinInterval ); // don't call this unless you know it's been long enough!
int nThreshold = usecElapsed / k_usecActiveConnectionSendInterval;
// Have they been trying to talk to us?
if ( m_nPktsRecvSeqSinceSentInstantaneous > nThreshold || m_nPktsSentSinceSentInstantaneous > nThreshold )
// Has there been any traffic worth reporting on in this interval?
if ( m_nPktsRecvSeqWhenPeerAckInstantaneous + nThreshold < m_nPktsRecvSequenced || m_nPktsSentWhenPeerAckInstantaneous + nThreshold < m_sent.m_packets.Total() )
return true;
// Connection has been idle since the last time we sent instantaneous stats.
@@ -491,7 +487,7 @@ bool LinkStatsTrackerBase::BCheckHaveDataToSendLifetime( SteamNetworkingMicrosec
Assert( !m_bPassive );
// Make sure we have something new to report since the last time we sent stats
if ( m_nPktsRecvSeqSinceSentLifetime > 100 || m_nPktsSentSinceSentLifetime > 100 )
if ( m_nPktsRecvSeqWhenPeerAckLifetime + 100 < m_nPktsRecvSequenced || m_nPktsSentWhenPeerAckLifetime + 100 < m_sent.m_packets.Total() )
return true;
// Reset the timer. But do NOT reset the packet counters. So if the connection isn't