add output of connection stats in UDTTest

This commit is contained in:
Stephen Birarda 2015-07-31 15:09:30 -07:00
parent e346dbcfee
commit ce21204151
8 changed files with 98 additions and 5 deletions

View file

@ -126,9 +126,17 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) {
ackPacket->writePrimitive((int32_t) udt::CONNECTION_RECEIVE_BUFFER_SIZE_PACKETS);
if (wasCausedBySyncTimeout) {
// grab the up to date packet receive speed and estimated bandwidth
int32_t packetReceiveSpeed = _receiveWindow.getPacketReceiveSpeed();
int32_t estimatedBandwidth = _receiveWindow.getEstimatedBandwidth();
// update those values in our connection stats
_stats.recordReceiveRate(packetReceiveSpeed);
_stats.recordEstimatedBandwidth(estimatedBandwidth);
// pack in the receive speed and estimatedBandwidth
ackPacket->writePrimitive(_receiveWindow.getPacketReceiveSpeed());
ackPacket->writePrimitive(_receiveWindow.getEstimatedBandwidth());
ackPacket->writePrimitive(packetReceiveSpeed);
ackPacket->writePrimitive(estimatedBandwidth);
// record this as the last ACK send time
lastACKSendTime = high_resolution_clock::now();
@ -261,6 +269,7 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber) {
_nakInterval = (_rtt + 4 * _rttVariance);
int receivedPacketsPerSecond = _receiveWindow.getPacketReceiveSpeed();
if (receivedPacketsPerSecond > 0) {
// the NAK interval is at least the _minNAKInterval
// but might be the time required for all lost packets to be retransmitted
@ -371,10 +380,12 @@ void Connection::processACK(std::unique_ptr<ControlPacket> controlPacket) {
// ACK the send queue so it knows what was received
_sendQueue->ack(ack);
// update the RTT
updateRTT(rtt);
// write this RTT to stats
_stats.recordRTT(rtt);
// set the RTT for congestion control
_congestionControl->setRTT(_rtt);
@ -387,6 +398,10 @@ void Connection::processACK(std::unique_ptr<ControlPacket> controlPacket) {
// these are calculated using an EWMA
static const int EMWA_ALPHA_NUMERATOR = 8;
// record these samples in connection stats
_stats.recordReceiveRate(receiveRate);
_stats.recordEstimatedBandwidth(bandwidth);
_deliveryRate = (_deliveryRate * (EMWA_ALPHA_NUMERATOR - 1) + _deliveryRate) / EMWA_ALPHA_NUMERATOR;
_bandwidth = (_bandwidth * (EMWA_ALPHA_NUMERATOR - 1) + _bandwidth) / EMWA_ALPHA_NUMERATOR;
@ -515,4 +530,8 @@ void Connection::updateCongestionControlAndSendQueue(std::function<void ()> cong
// now that we've update the congestion control, update the packet send period and flow window size
_sendQueue->setPacketSendPeriod(_congestionControl->_packetSendPeriod);
_sendQueue->setFlowWindowSize(std::min(_flowWindowSize, (int) _congestionControl->_congestionWindowSize));
// record connection stats
_stats.recordPacketSendPeriod(_congestionControl->_packetSendPeriod);
_stats.recordCongestionWindowSize(_congestionControl->_congestionWindowSize);
}

View file

@ -46,6 +46,8 @@ public:
bool processReceivedSequenceNumber(SequenceNumber sequenceNumber); // returns indicates if this packet was a duplicate
void processControl(std::unique_ptr<ControlPacket> controlPacket);
ConnectionStats::Stats sampleStats() { return _stats.sample(); }
signals:
void packetSent();

View file

@ -89,4 +89,32 @@ void ConnectionStats::recordSentPackets() {
void ConnectionStats::recordReceivedPackets() {
++_currentSample.recievedPackets;
++_total.recievedPackets;
}
}
static const double EWMA_CURRENT_SAMPLE_WEIGHT = 0.125;
static const double EWMA_PREVIOUS_SAMPLES_WEIGHT = 1 - 0.125;
void ConnectionStats::recordReceiveRate(int sample) {
_currentSample.receiveRate = sample;
_total.receiveRate = (_total.receiveRate * EWMA_PREVIOUS_SAMPLES_WEIGHT) + (sample * EWMA_CURRENT_SAMPLE_WEIGHT);
}
void ConnectionStats::recordEstimatedBandwidth(int sample) {
_currentSample.estimatedBandwith = sample;
_total.estimatedBandwith = (_total.estimatedBandwith * EWMA_PREVIOUS_SAMPLES_WEIGHT) + (sample * EWMA_CURRENT_SAMPLE_WEIGHT);
}
void ConnectionStats::recordRTT(int sample) {
_currentSample.rtt = sample;
_total.rtt = (_total.rtt * EWMA_PREVIOUS_SAMPLES_WEIGHT) + (sample * EWMA_CURRENT_SAMPLE_WEIGHT);
}
void ConnectionStats::recordCongestionWindowSize(int sample) {
_currentSample.congestionWindowSize = sample;
_total.congestionWindowSize = (_total.congestionWindowSize * EWMA_PREVIOUS_SAMPLES_WEIGHT) + (sample * EWMA_CURRENT_SAMPLE_WEIGHT);
}
void ConnectionStats::recordPacketSendPeriod(int sample) {
_currentSample.packetSendPeriod = sample;
_total.packetSendPeriod = (_total.packetSendPeriod * EWMA_PREVIOUS_SAMPLES_WEIGHT) + (sample * EWMA_CURRENT_SAMPLE_WEIGHT);
}

View file

@ -36,6 +36,13 @@ public:
int sentPackets { 0 };
int recievedPackets { 0 };
// the following stats are trailing averages in the result, not totals
int receiveRate { 0 };
int estimatedBandwith { 0 };
int rtt { 0 };
int congestionWindowSize { 0 };
int packetSendPeriod { 0 };
};
ConnectionStats();
@ -57,6 +64,12 @@ public:
void recordSentPackets();
void recordReceivedPackets();
void recordReceiveRate(int sample);
void recordEstimatedBandwidth(int sample);
void recordRTT(int sample);
void recordCongestionWindowSize(int sample);
void recordPacketSendPeriod(int sample);
private:
Stats _currentSample;
Stats _total;
@ -64,4 +77,4 @@ private:
}
#endif // hifi_ConnectionStats_h
#endif // hifi_ConnectionStats_h

View file

@ -213,3 +213,20 @@ void Socket::setCongestionControlFactory(std::unique_ptr<CongestionControlVirtua
// update the _synInterval to the value from the factory
_synInterval = _ccFactory->synInterval();
}
void Socket::sampleAndPrintConnectionStats() {
if (thread() != QThread::currentThread()) {
QMetaObject::invokeMethod(this, "sampleAndPrintConnectionStats");
return;
}
for(auto& connection : _connectionsHash) {
ConnectionStats::Stats sampleStats = connection.second->sampleStats();
qDebug() << connection.first
<< sampleStats.receiveRate << sampleStats.rtt
<< sampleStats.congestionWindowSize << sampleStats.packetSendPeriod
<< sampleStats.sentPackets
<< sampleStats.receivedACKs << sampleStats.receivedLightACKs << sampleStats.receivedNAKs;
}
}

View file

@ -63,6 +63,8 @@ public:
void setCongestionControlFactory(std::unique_ptr<CongestionControlVirtualFactory> ccFactory);
void connectToSendSignal(const HifiSockAddr& destinationAddr, QObject* receiver, const char* slot);
void sampleAndPrintConnectionStats();
private slots:
void readPendingDatagrams();

View file

@ -116,6 +116,13 @@ UDTTest::UDTTest(int& argc, char** argv) :
if (!_target.isNull()) {
sendInitialPackets();
// the sender reports stats every 1 second
static const int STATS_SAMPLE_INTERVAL = 1000;
QTimer* statsTimer = new QTimer(this);
connect(statsTimer, &QTimer::timeout, this, &UDTTest::sampleStats);
statsTimer->start(STATS_SAMPLE_INTERVAL);
}
}
@ -198,3 +205,7 @@ void UDTTest::sendPacket() {
++_totalQueuedPackets;
}
void UDTTest::sampleStats() {
_socket.sampleAndPrintConnectionStats();
}

View file

@ -27,6 +27,7 @@ public:
public slots:
void refillPacket() { sendPacket(); } // adds a new packet to the queue when we are told one is sent
void sampleStats();
private:
void parseArguments();