mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-04 03:04:40 +02:00
recursive SequenceNumberStats; untested
This commit is contained in:
parent
cdcc6ece04
commit
eba07b03e2
2 changed files with 120 additions and 4 deletions
|
@ -13,22 +13,67 @@
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
SequenceNumberStats::SequenceNumberStats(int statsHistoryLength)
|
SequenceNumberStats::SequenceNumberStats(int statsHistoryLength, int maxRecursion)
|
||||||
: _received(0),
|
: _received(0),
|
||||||
_lastReceivedSequence(0),
|
_lastReceivedSequence(0),
|
||||||
_missingSet(),
|
_missingSet(),
|
||||||
_stats(),
|
_stats(),
|
||||||
_lastSenderUUID(),
|
_lastSenderUUID(),
|
||||||
_statsHistory(statsHistoryLength)
|
_statsHistory(statsHistoryLength),
|
||||||
|
|
||||||
|
_unreasonableTracker(NULL),
|
||||||
|
_maxRecursion(maxRecursion)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SequenceNumberStats::SequenceNumberStats(const SequenceNumberStats& other)
|
||||||
|
: _received(other._received),
|
||||||
|
_lastReceivedSequence(other._lastReceivedSequence),
|
||||||
|
_missingSet(other._missingSet),
|
||||||
|
_stats(other._stats),
|
||||||
|
_lastSenderUUID(other._lastSenderUUID),
|
||||||
|
_statsHistory(other._statsHistory),
|
||||||
|
_unreasonableTracker(NULL),
|
||||||
|
_maxRecursion(other._maxRecursion)
|
||||||
|
{
|
||||||
|
if (other._unreasonableTracker) {
|
||||||
|
_unreasonableTracker = new SequenceNumberStats(*other._unreasonableTracker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SequenceNumberStats& SequenceNumberStats::operator=(const SequenceNumberStats& rhs) {
|
||||||
|
_received = rhs._received;
|
||||||
|
_lastReceivedSequence = rhs._lastReceivedSequence;
|
||||||
|
_missingSet = rhs._missingSet;
|
||||||
|
_stats = rhs._stats;
|
||||||
|
_lastSenderUUID = rhs._lastSenderUUID;
|
||||||
|
_statsHistory = rhs._statsHistory;
|
||||||
|
_maxRecursion = rhs._maxRecursion;
|
||||||
|
|
||||||
|
if (rhs._unreasonableTracker) {
|
||||||
|
_unreasonableTracker = new SequenceNumberStats(*rhs._unreasonableTracker);
|
||||||
|
} else {
|
||||||
|
_unreasonableTracker = NULL;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
SequenceNumberStats::~SequenceNumberStats() {
|
||||||
|
if (_unreasonableTracker) {
|
||||||
|
delete _unreasonableTracker;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SequenceNumberStats::reset() {
|
void SequenceNumberStats::reset() {
|
||||||
_received = 0;
|
_received = 0;
|
||||||
_missingSet.clear();
|
_missingSet.clear();
|
||||||
_stats = PacketStreamStats();
|
_stats = PacketStreamStats();
|
||||||
_lastSenderUUID = QUuid();
|
_lastSenderUUID = QUuid();
|
||||||
_statsHistory.clear();
|
_statsHistory.clear();
|
||||||
|
|
||||||
|
if (_unreasonableTracker) {
|
||||||
|
delete _unreasonableTracker;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const int UINT16_RANGE = std::numeric_limits<uint16_t>::max() + 1;
|
static const int UINT16_RANGE = std::numeric_limits<uint16_t>::max() + 1;
|
||||||
|
@ -78,10 +123,64 @@ SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(qui
|
||||||
} else if (absGap > MAX_REASONABLE_SEQUENCE_GAP) {
|
} else if (absGap > MAX_REASONABLE_SEQUENCE_GAP) {
|
||||||
arrivalInfo._status = Unreasonable;
|
arrivalInfo._status = Unreasonable;
|
||||||
|
|
||||||
|
/*
|
||||||
// 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:" << _lastReceivedSequence;
|
<< "previous:" << _lastReceivedSequence;
|
||||||
_stats._unreasonable++;
|
_stats._unreasonable++;
|
||||||
|
*/
|
||||||
|
|
||||||
|
// do not create a child tracker for unreasonable seq nums if this instance is the last one in the chain.
|
||||||
|
// otherwise, create one if we don't have one.
|
||||||
|
|
||||||
|
if (!_unreasonableTracker && _maxRecursion > 0) {
|
||||||
|
_unreasonableTracker = new SequenceNumberStats(0, _maxRecursion - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (_unreasonableTracker) {
|
||||||
|
|
||||||
|
// track this unreasonable seq number with our _unreasonableTracker.
|
||||||
|
ArrivalInfo unreasonableTrackerArrivalInfo = _unreasonableTracker->sequenceNumberReceived(incoming);
|
||||||
|
|
||||||
|
|
||||||
|
const int UNREASONABLE_TRACKER_RECEIVED_THRESHOLD = 10;
|
||||||
|
const float UNRUNREASONABLE_TRACKER_UNREASONABLE_RATE_THRESHOLD = 0.1f;
|
||||||
|
const float UNREASONABLE_TRACKER_OUT_OF_ORDER_RATE_THRESHOLD = 0.1f;
|
||||||
|
|
||||||
|
// when our _unreasonableTracker has received enough seq nums and doesn't have an _unreasonableTracker of its own,
|
||||||
|
// we'll either inherit its state only if we think its stream is plausible. it will then be deleted.
|
||||||
|
// (if it has an _unreasonableTracker of its own, its _unreasonableTracker may be detecting a plausible stream
|
||||||
|
// while its parent does not, so we should let it accrue seq nums and decide plausibility first)
|
||||||
|
|
||||||
|
if (!_unreasonableTracker->hasUnreasonableTracker() &&
|
||||||
|
_unreasonableTracker->_received >= UNREASONABLE_TRACKER_RECEIVED_THRESHOLD) {
|
||||||
|
|
||||||
|
if (_unreasonableTracker->getUnreasonableRate() < UNRUNREASONABLE_TRACKER_UNREASONABLE_RATE_THRESHOLD &&
|
||||||
|
_unreasonableTracker->getStats().getOutOfOrderRate() < UNREASONABLE_TRACKER_OUT_OF_ORDER_RATE_THRESHOLD) {
|
||||||
|
|
||||||
|
// the _unreasonableTracker has detected a plausible stream of seq numbers;
|
||||||
|
// copy its state to this tracker.
|
||||||
|
|
||||||
|
_received = _unreasonableTracker->_received;
|
||||||
|
_lastReceivedSequence = _unreasonableTracker->_lastReceivedSequence;
|
||||||
|
_missingSet = _unreasonableTracker->_missingSet;
|
||||||
|
_stats = _unreasonableTracker->_stats;
|
||||||
|
|
||||||
|
// don't copy _lastSenderUUID; _unreasonableTracker always has null UUID for that member.
|
||||||
|
// ours should be up-to-date.
|
||||||
|
|
||||||
|
// don't copy _statsHistory; _unreasonableTracker keeps a history of length 0.
|
||||||
|
// simply clear ours.
|
||||||
|
_statsHistory.clear();
|
||||||
|
|
||||||
|
arrivalInfo = unreasonableTrackerArrivalInfo;
|
||||||
|
|
||||||
|
}
|
||||||
|
// remove our _unreasonableTracker
|
||||||
|
delete _unreasonableTracker;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return arrivalInfo;
|
return arrivalInfo;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,10 @@
|
||||||
|
|
||||||
const int MAX_REASONABLE_SEQUENCE_GAP = 1000;
|
const int MAX_REASONABLE_SEQUENCE_GAP = 1000;
|
||||||
|
|
||||||
|
|
||||||
|
const int DEFAULT_MAX_RECURSION = 5;
|
||||||
|
|
||||||
|
|
||||||
class PacketStreamStats {
|
class PacketStreamStats {
|
||||||
public:
|
public:
|
||||||
PacketStreamStats()
|
PacketStreamStats()
|
||||||
|
@ -30,7 +34,7 @@ public:
|
||||||
_duplicate(0)
|
_duplicate(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
float getUnreasonableRate() const { return (float)_unreasonable / _expectedReceived; }
|
float getOutOfOrderRate() const { return (float)(_early + _late) / _expectedReceived; }
|
||||||
float getEaryRate() const { return (float)_early / _expectedReceived; }
|
float getEaryRate() const { return (float)_early / _expectedReceived; }
|
||||||
float getLateRate() const { return (float)_late / _expectedReceived; }
|
float getLateRate() const { return (float)_late / _expectedReceived; }
|
||||||
float getLostRate() const { return (float)_lost / _expectedReceived; }
|
float getLostRate() const { return (float)_lost / _expectedReceived; }
|
||||||
|
@ -61,14 +65,19 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
SequenceNumberStats(int statsHistoryLength = 0);
|
SequenceNumberStats(int statsHistoryLength = 0, int maxRecursion = DEFAULT_MAX_RECURSION);
|
||||||
|
SequenceNumberStats(const SequenceNumberStats& other);
|
||||||
|
SequenceNumberStats& operator=(const SequenceNumberStats& rhs);
|
||||||
|
~SequenceNumberStats();
|
||||||
|
|
||||||
|
public:
|
||||||
void reset();
|
void reset();
|
||||||
ArrivalInfo sequenceNumberReceived(quint16 incoming, QUuid senderUUID = QUuid(), const bool wantExtraDebugging = false);
|
ArrivalInfo sequenceNumberReceived(quint16 incoming, QUuid senderUUID = QUuid(), const bool wantExtraDebugging = false);
|
||||||
void pruneMissingSet(const bool wantExtraDebugging = false);
|
void pruneMissingSet(const bool wantExtraDebugging = false);
|
||||||
void pushStatsToHistory() { _statsHistory.insert(_stats); }
|
void pushStatsToHistory() { _statsHistory.insert(_stats); }
|
||||||
|
|
||||||
quint32 getReceived() const { return _received; }
|
quint32 getReceived() const { return _received; }
|
||||||
|
float getUnreasonableRate() const { return _stats._unreasonable / _received; }
|
||||||
|
|
||||||
quint32 getExpectedReceived() const { return _stats._expectedReceived; }
|
quint32 getExpectedReceived() const { return _stats._expectedReceived; }
|
||||||
quint32 getUnreasonable() const { return _stats._unreasonable; }
|
quint32 getUnreasonable() const { return _stats._unreasonable; }
|
||||||
|
@ -94,6 +103,14 @@ private:
|
||||||
QUuid _lastSenderUUID;
|
QUuid _lastSenderUUID;
|
||||||
|
|
||||||
RingBufferHistory<PacketStreamStats> _statsHistory;
|
RingBufferHistory<PacketStreamStats> _statsHistory;
|
||||||
|
|
||||||
|
|
||||||
|
// to deal with the incoming seq nums going out of sync with this tracker, we'll create another instance
|
||||||
|
// of this class when we encounter an unreasonable
|
||||||
|
SequenceNumberStats* _unreasonableTracker;
|
||||||
|
int _maxRecursion;
|
||||||
|
|
||||||
|
bool hasUnreasonableTracker() const { return _unreasonableTracker != NULL; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_SequenceNumberStats_h
|
#endif // hifi_SequenceNumberStats_h
|
||||||
|
|
Loading…
Reference in a new issue