fixed >100% loss rate bug in SequenceNumberStats

This commit is contained in:
wangyix 2014-08-01 10:23:03 -07:00
parent c4751d7dd7
commit e1f905cb36
6 changed files with 73 additions and 65 deletions

View file

@ -1424,9 +1424,9 @@ void Audio::renderAudioStreamStats(const AudioStreamStats& streamStats, int hori
sprintf(stringBuffer, " Packet loss | overall: %5.2f%% (%d lost), last_30s: %5.2f%% (%d lost)", sprintf(stringBuffer, " Packet loss | overall: %5.2f%% (%d lost), last_30s: %5.2f%% (%d lost)",
streamStats._packetStreamStats.getLostRate() * 100.0f, streamStats._packetStreamStats.getLostRate() * 100.0f,
streamStats._packetStreamStats._numLost, streamStats._packetStreamStats._lost,
streamStats._packetStreamWindowStats.getLostRate() * 100.0f, streamStats._packetStreamWindowStats.getLostRate() * 100.0f,
streamStats._packetStreamWindowStats._numLost); streamStats._packetStreamWindowStats._lost);
verticalOffset += STATS_HEIGHT_PER_LINE; verticalOffset += STATS_HEIGHT_PER_LINE;
drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color); drawText(horizontalOffset, verticalOffset, scale, rotation, font, stringBuffer, color);

View file

@ -366,13 +366,13 @@ void OctreeStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t ser
QString incomingBytesString = locale.toString((uint)stats.getIncomingBytes()); QString incomingBytesString = locale.toString((uint)stats.getIncomingBytes());
QString incomingWastedBytesString = locale.toString((uint)stats.getIncomingWastedBytes()); QString incomingWastedBytesString = locale.toString((uint)stats.getIncomingWastedBytes());
const SequenceNumberStats& seqStats = stats.getIncomingOctreeSequenceNumberStats(); const SequenceNumberStats& seqStats = stats.getIncomingOctreeSequenceNumberStats();
QString incomingOutOfOrderString = locale.toString((uint)seqStats.getNumOutOfOrder()); QString incomingOutOfOrderString = locale.toString((uint)seqStats.getOutOfOrder());
QString incomingLateString = locale.toString((uint)seqStats.getNumLate()); QString incomingLateString = locale.toString((uint)seqStats.getLate());
QString incomingUnreasonableString = locale.toString((uint)seqStats.getNumUnreasonable()); QString incomingUnreasonableString = locale.toString((uint)seqStats.getUnreasonable());
QString incomingEarlyString = locale.toString((uint)seqStats.getNumEarly()); QString incomingEarlyString = locale.toString((uint)seqStats.getEarly());
QString incomingLikelyLostString = locale.toString((uint)seqStats.getNumLost()); QString incomingLikelyLostString = locale.toString((uint)seqStats.getLost());
QString incomingRecovered = locale.toString((uint)seqStats.getNumRecovered()); QString incomingRecovered = locale.toString((uint)seqStats.getRecovered());
QString incomingDuplicateString = locale.toString((uint)seqStats.getNumDuplicate()); QString incomingDuplicateString = locale.toString((uint)seqStats.getDuplicate());
int clockSkewInMS = node->getClockSkewUsec() / (int)USECS_PER_MSEC; int clockSkewInMS = node->getClockSkewUsec() / (int)USECS_PER_MSEC;
QString incomingFlightTimeString = locale.toString((int)stats.getIncomingFlightTimeAverage()); QString incomingFlightTimeString = locale.toString((int)stats.getIncomingFlightTimeAverage());

View file

@ -212,7 +212,7 @@ SequenceNumberStats::ArrivalInfo InboundAudioStream::frameReceivedUpdateNetworkS
// discard the first few packets we receive since they usually have gaps that aren't represensative of normal jitter // discard the first few packets we receive since they usually have gaps that aren't represensative of normal jitter
const int NUM_INITIAL_PACKETS_DISCARD = 3; const int NUM_INITIAL_PACKETS_DISCARD = 3;
quint64 now = usecTimestampNow(); quint64 now = usecTimestampNow();
if (_incomingSequenceNumberStats.getNumReceived() > NUM_INITIAL_PACKETS_DISCARD) { if (_incomingSequenceNumberStats.getReceived() > NUM_INITIAL_PACKETS_DISCARD) {
quint64 gap = now - _lastFrameReceivedTime; quint64 gap = now - _lastFrameReceivedTime;
_interframeTimeGapStatsForStatsPacket.update(gap); _interframeTimeGapStatsForStatsPacket.update(gap);

View file

@ -108,7 +108,7 @@ public:
int getSilentFramesDropped() const { return _silentFramesDropped; } int getSilentFramesDropped() const { return _silentFramesDropped; }
int getOverflowCount() const { return _ringBuffer.getOverflowCount(); } int getOverflowCount() const { return _ringBuffer.getOverflowCount(); }
int getPacketReceived() const { return _incomingSequenceNumberStats.getNumReceived(); } int getPacketsReceived() const { return _incomingSequenceNumberStats.getReceived(); }
private: private:
void starved(); void starved();

View file

@ -14,7 +14,8 @@
#include <limits> #include <limits>
SequenceNumberStats::SequenceNumberStats(int statsHistoryLength) SequenceNumberStats::SequenceNumberStats(int statsHistoryLength)
: _lastReceived(std::numeric_limits<quint16>::max()), : _received(0),
_lastReceivedSequence(0),
_missingSet(), _missingSet(),
_stats(), _stats(),
_lastSenderUUID(), _lastSenderUUID(),
@ -23,8 +24,10 @@ SequenceNumberStats::SequenceNumberStats(int statsHistoryLength)
} }
void SequenceNumberStats::reset() { void SequenceNumberStats::reset() {
_received = 0;
_missingSet.clear(); _missingSet.clear();
_stats = PacketStreamStats(); _stats = PacketStreamStats();
_lastSenderUUID = QUuid();
_statsHistory.clear(); _statsHistory.clear();
} }
@ -36,7 +39,7 @@ SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(qui
// if the sender node has changed, reset all stats // if the sender node has changed, reset all stats
if (senderUUID != _lastSenderUUID) { if (senderUUID != _lastSenderUUID) {
if (_stats._numReceived > 0) { if (_received > 0) {
qDebug() << "sequence number stats was reset due to new sender node"; qDebug() << "sequence number stats was reset due to new sender node";
qDebug() << "previous:" << _lastSenderUUID << "current:" << senderUUID; qDebug() << "previous:" << _lastSenderUUID << "current:" << senderUUID;
reset(); reset();
@ -45,13 +48,14 @@ SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(qui
} }
// determine our expected sequence number... handle rollover appropriately // determine our expected sequence number... handle rollover appropriately
quint16 expected = _stats._numReceived > 0 ? _lastReceived + (quint16)1 : incoming; quint16 expected = _received > 0 ? _lastReceivedSequence + (quint16)1 : incoming;
_stats._numReceived++; _received++;
if (incoming == expected) { // on time if (incoming == expected) { // on time
arrivalInfo._status = OnTime; arrivalInfo._status = OnTime;
_lastReceived = incoming; _lastReceivedSequence = incoming;
_stats._expectedReceived++;
} else { // out of order } else { // out of order
if (wantExtraDebugging) { if (wantExtraDebugging) {
@ -76,8 +80,8 @@ SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(qui
// ignore packet if gap is unreasonable // ignore packet if gap is unreasonable
qDebug() << "ignoring unreasonable sequence number:" << incoming qDebug() << "ignoring unreasonable sequence number:" << incoming
<< "previous:" << _lastReceived; << "previous:" << _lastReceivedSequence;
_stats._numUnreasonable++; _stats._unreasonable++;
return arrivalInfo; return arrivalInfo;
} }
@ -94,10 +98,11 @@ SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(qui
qDebug() << "this packet is earlier than expected..."; qDebug() << "this packet is earlier than expected...";
qDebug() << ">>>>>>>> missing gap=" << (incomingInt - expectedInt); qDebug() << ">>>>>>>> missing gap=" << (incomingInt - expectedInt);
} }
int skipped = incomingInt - expectedInt;
_stats._numEarly++; _stats._early++;
_stats._numLost += (incomingInt - expectedInt); _stats._lost += skipped;
_lastReceived = incoming; _stats._expectedReceived += (skipped + 1);
_lastReceivedSequence = incoming;
// add all sequence numbers that were skipped to the missing sequence numbers list // add all sequence numbers that were skipped to the missing sequence numbers list
for (int missingInt = expectedInt; missingInt < incomingInt; missingInt++) { for (int missingInt = expectedInt; missingInt < incomingInt; missingInt++) {
@ -114,7 +119,7 @@ SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(qui
qDebug() << "this packet is later than expected..."; qDebug() << "this packet is later than expected...";
} }
_stats._numLate++; _stats._late++;
// do not update _lastReceived; it shouldn't become smaller // do not update _lastReceived; it shouldn't become smaller
@ -125,15 +130,15 @@ SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(qui
if (wantExtraDebugging) { if (wantExtraDebugging) {
qDebug() << "found it in _missingSet"; qDebug() << "found it in _missingSet";
} }
_stats._numLost--; _stats._lost--;
_stats._numRecovered++; _stats._recovered++;
} else { } else {
arrivalInfo._status = Duplicate; arrivalInfo._status = Duplicate;
if (wantExtraDebugging) { if (wantExtraDebugging) {
qDebug() << "sequence:" << incoming << "was NOT found in _missingSet and is probably a duplicate"; qDebug() << "sequence:" << incoming << "was NOT found in _missingSet and is probably a duplicate";
} }
_stats._numDuplicate++; _stats._duplicate++;
} }
} }
} }
@ -148,7 +153,7 @@ void SequenceNumberStats::pruneMissingSet(const bool wantExtraDebugging) {
// some older sequence numbers may be from before a rollover point; this must be handled. // some older sequence numbers may be from before a rollover point; this must be handled.
// some sequence numbers in this list may be larger than _incomingLastSequence, indicating that they were received // some sequence numbers in this list may be larger than _incomingLastSequence, indicating that they were received
// before the most recent rollover. // before the most recent rollover.
int cutoff = (int)_lastReceived - MAX_REASONABLE_SEQUENCE_GAP; int cutoff = (int)_lastReceivedSequence - MAX_REASONABLE_SEQUENCE_GAP;
if (cutoff >= 0) { if (cutoff >= 0) {
quint16 nonRolloverCutoff = (quint16)cutoff; quint16 nonRolloverCutoff = (quint16)cutoff;
QSet<quint16>::iterator i = _missingSet.begin(); QSet<quint16>::iterator i = _missingSet.begin();
@ -159,7 +164,7 @@ void SequenceNumberStats::pruneMissingSet(const bool wantExtraDebugging) {
qDebug() << "old age cutoff:" << nonRolloverCutoff; qDebug() << "old age cutoff:" << nonRolloverCutoff;
} }
if (missing > _lastReceived || missing < nonRolloverCutoff) { if (missing > _lastReceivedSequence || missing < nonRolloverCutoff) {
i = _missingSet.erase(i); i = _missingSet.erase(i);
if (wantExtraDebugging) { if (wantExtraDebugging) {
qDebug() << "pruning really old missing sequence:" << missing; qDebug() << "pruning really old missing sequence:" << missing;
@ -178,7 +183,7 @@ void SequenceNumberStats::pruneMissingSet(const bool wantExtraDebugging) {
qDebug() << "old age cutoff:" << rolloverCutoff; qDebug() << "old age cutoff:" << rolloverCutoff;
} }
if (missing > _lastReceived && missing < rolloverCutoff) { if (missing > _lastReceivedSequence && missing < rolloverCutoff) {
i = _missingSet.erase(i); i = _missingSet.erase(i);
if (wantExtraDebugging) { if (wantExtraDebugging) {
qDebug() << "pruning really old missing sequence:" << missing; qDebug() << "pruning really old missing sequence:" << missing;
@ -202,13 +207,13 @@ PacketStreamStats SequenceNumberStats::getStatsForHistoryWindow() const {
// calculate difference between newest stats and oldest stats to get window stats // calculate difference between newest stats and oldest stats to get window stats
PacketStreamStats windowStats; PacketStreamStats windowStats;
windowStats._numReceived = newestStats->_numReceived - oldestStats->_numReceived; windowStats._expectedReceived = newestStats->_expectedReceived - oldestStats->_expectedReceived;
windowStats._numUnreasonable = newestStats->_numUnreasonable - oldestStats->_numUnreasonable; windowStats._unreasonable = newestStats->_unreasonable - oldestStats->_unreasonable;
windowStats._numEarly = newestStats->_numEarly - oldestStats->_numEarly; windowStats._early = newestStats->_early - oldestStats->_early;
windowStats._numLate = newestStats->_numLate - oldestStats->_numLate; windowStats._late = newestStats->_late - oldestStats->_late;
windowStats._numLost = newestStats->_numLost - oldestStats->_numLost; windowStats._lost = newestStats->_lost - oldestStats->_lost;
windowStats._numRecovered = newestStats->_numRecovered - oldestStats->_numRecovered; windowStats._recovered = newestStats->_recovered - oldestStats->_recovered;
windowStats._numDuplicate = newestStats->_numDuplicate - oldestStats->_numDuplicate; windowStats._duplicate = newestStats->_duplicate - oldestStats->_duplicate;
return windowStats; return windowStats;
} }

View file

@ -21,29 +21,27 @@ const int MAX_REASONABLE_SEQUENCE_GAP = 1000;
class PacketStreamStats { class PacketStreamStats {
public: public:
PacketStreamStats() PacketStreamStats()
: _numReceived(0), : _expectedReceived(0),
_numUnreasonable(0), _unreasonable(0),
_numEarly(0), _early(0),
_numLate(0), _late(0),
_numLost(0), _lost(0),
_numRecovered(0), _recovered(0),
_numDuplicate(0) _duplicate(0)
{} {}
float getUnreasonableRate() const { return (float)_numUnreasonable / _numReceived; } float getUnreasonableRate() const { return (float)_unreasonable / _expectedReceived; }
float getNumEaryRate() const { return (float)_numEarly / _numReceived; } float getEaryRate() const { return (float)_early / _expectedReceived; }
float getLateRate() const { return (float)_numLate / _numReceived; } float getLateRate() const { return (float)_late / _expectedReceived; }
float getLostRate() const { return (float)_numLost / _numReceived; } float getLostRate() const { return (float)_lost / _expectedReceived; }
float getRecoveredRate() const { return (float)_numRecovered / _numReceived; }
float getDuplicateRate() const { return (float)_numDuplicate / _numReceived; }
quint32 _numReceived; quint32 _expectedReceived;
quint32 _numUnreasonable; quint32 _unreasonable;
quint32 _numEarly; quint32 _early;
quint32 _numLate; quint32 _late;
quint32 _numLost; quint32 _lost;
quint32 _numRecovered; quint32 _recovered;
quint32 _numDuplicate; quint32 _duplicate;
}; };
class SequenceNumberStats { class SequenceNumberStats {
@ -70,20 +68,25 @@ public:
void pruneMissingSet(const bool wantExtraDebugging = false); void pruneMissingSet(const bool wantExtraDebugging = false);
void pushStatsToHistory() { _statsHistory.insert(_stats); } void pushStatsToHistory() { _statsHistory.insert(_stats); }
quint32 getNumReceived() const { return _stats._numReceived; } quint32 getReceived() const { return _received; }
quint32 getNumUnreasonable() const { return _stats._numUnreasonable; }
quint32 getNumOutOfOrder() const { return _stats._numEarly + _stats._numLate; } quint32 getExpectedReceived() const { return _stats._expectedReceived; }
quint32 getNumEarly() const { return _stats._numEarly; } quint32 getUnreasonable() const { return _stats._unreasonable; }
quint32 getNumLate() const { return _stats._numLate; } quint32 getOutOfOrder() const { return _stats._early + _stats._late; }
quint32 getNumLost() const { return _stats._numLost; } quint32 getEarly() const { return _stats._early; }
quint32 getNumRecovered() const { return _stats._numRecovered; } quint32 getLate() const { return _stats._late; }
quint32 getNumDuplicate() const { return _stats._numDuplicate; } quint32 getLost() const { return _stats._lost; }
quint32 getRecovered() const { return _stats._recovered; }
quint32 getDuplicate() const { return _stats._duplicate; }
const PacketStreamStats& getStats() const { return _stats; } const PacketStreamStats& getStats() const { return _stats; }
PacketStreamStats getStatsForHistoryWindow() const; PacketStreamStats getStatsForHistoryWindow() const;
const QSet<quint16>& getMissingSet() const { return _missingSet; } const QSet<quint16>& getMissingSet() const { return _missingSet; }
private: private:
quint16 _lastReceived; int _received;
quint16 _lastReceivedSequence;
QSet<quint16> _missingSet; QSet<quint16> _missingSet;
PacketStreamStats _stats; PacketStreamStats _stats;