Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[core] New moving average value for sent/recv rates over last second #3009

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions srtcore/buffer_tools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,5 +273,48 @@ int CSndRateEstimator::incSampleIdx(int val, int inc) const
return val;
}

CMobileRateEstimator::CMobileRateEstimator()
: m_iCurSampleIdx(0)
, m_iRateKbps(0)
{
resetMeasuresTable();
}

void CMobileRateEstimator::addSample(int pkts, double bytes)
{
const time_point now = steady_clock::now();
const int iSampleDeltaIdx = (int) count_milliseconds(now - lastTimestamp) / SAMPLE_DURATION_MS;

if((m_iCurSampleIdx + iSampleDeltaIdx) < NUM_PERIODS)
resetMeasuresTable(m_iCurSampleIdx+1,m_iCurSampleIdx + iSampleDeltaIdx);
else {
int loopbackDiff = m_iCurSampleIdx + iSampleDeltaIdx - NUM_PERIODS;
resetMeasuresTable(m_iCurSampleIdx+1,NUM_PERIODS);
resetMeasuresTable(0,loopbackDiff);
}

m_iCurSampleIdx = ((m_iCurSampleIdx + iSampleDeltaIdx) % NUM_PERIODS);
m_Samples[m_iCurSampleIdx].m_iBytesCount = bytes;
m_Samples[m_iCurSampleIdx].m_iPktsCount = pkts;

lastTimestamp = now;

computeAverageValueFromTable();
}

void CMobileRateEstimator::resetMeasuresTable(int from, int to)
{
for(int i = max(0, from); i < min(int(NUM_PERIODS), to); i++)
m_Samples[i].reset();
}

void CMobileRateEstimator::computeAverageValueFromTable(){
m_iRateKbps = 0;

for(int i = 0; i < NUM_PERIODS; i++)
m_iRateKbps += (m_Samples[i].m_iBytesCount + (CPacket::HDR_SIZE * m_Samples[i].m_iPktsCount)) * 8;

m_iRateKbps = m_iRateKbps / (NUM_PERIODS * SAMPLE_DURATION_MS);
}
}

46 changes: 42 additions & 4 deletions srtcore/buffer_tools.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ class CSndRateEstimator

public:
CSndRateEstimator(const time_point& tsNow);
CSndRateEstimator() {};

/// Add sample.
/// @param [in] time sample (sending) time.
Expand All @@ -148,9 +149,7 @@ class CSndRateEstimator
/// including the current sampling interval.
int getCurrentRate() const;

private:
static const int NUM_PERIODS = 10;
static const int SAMPLE_DURATION_MS = 100; // 100 ms
protected:
struct Sample
{
int m_iPktsCount; // number of payload packets
Expand Down Expand Up @@ -188,14 +187,53 @@ class CSndRateEstimator
bool empty() const { return m_iPktsCount == 0; }
};

int incSampleIdx(int val, int inc = 1) const;
private:
static const int NUM_PERIODS = 10;
static const int SAMPLE_DURATION_MS = 100; // 100 ms

Sample m_Samples[NUM_PERIODS];

time_point m_tsFirstSampleTime; //< Start time of the first sample.
int m_iFirstSampleIdx; //< Index of the first sample.
int m_iCurSampleIdx; //< Index of the current sample being collected.
int m_iRateBps; //< Rate in Bytes/sec.

int incSampleIdx(int val, int inc = 1) const;
};

class CMobileRateEstimator:CSndRateEstimator
{
typedef sync::steady_clock::time_point time_point;

public:
CMobileRateEstimator();

/// Add sample.
/// @param [in] pkts number of packets in the sample.
/// @param [in] bytes number of payload bytes in the sample.
void addSample(int pkts = 0, double bytes = 0);

/// Clean the mobile measures table to reset average value.
void resetMeasuresTable() {resetMeasuresTable(0,NUM_PERIODS);};

/// Retrieve estimated bitrate in kilobits per second
int getRateKbps() const { return m_iRateKbps; }

private:
static const int NUM_PERIODS = 100; // To get 1s of values
static const int SAMPLE_DURATION_MS = 10; // 10 ms
time_point lastTimestamp; // Used to compute the delta between 2 calls
int m_iCurSampleIdx; // Index of the current sample being collected.
int m_iRateKbps; // The average value over the period (1s) in Kb
Sample m_Samples[NUM_PERIODS]; // Table of stored data

/// This method will compute the average value based on all table's measures and the period (NUM_PERIODS*SAMPLE_DURATION_MS)
void computeAverageValueFromTable();

/// Reset a part of the stored measures
/// @param from The beginning where the reset have to be applied
/// @param to The last data that have to be reset
void resetMeasuresTable(int from, int to);
};

} // namespace srt
Expand Down
7 changes: 7 additions & 0 deletions srtcore/core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7569,6 +7569,13 @@ void srt::CUDT::bstats(CBytePerfMon *perf, bool clear, bool instantaneous)
perf->pktRcvUndecryptTotal = m_stats.rcvr.undecrypted.total.count();
perf->byteRcvUndecryptTotal = m_stats.rcvr.undecrypted.total.bytes();


// Average values management
m_stats.sndr.fulfillMeasuresTable(perf->pktSent, double(perf->byteSent));
m_stats.rcvr.fulfillMeasuresTable(perf->pktRecv, double(perf->byteRecv));
perf->mbpsSendRate = m_stats.sndr.getAverageValueFromTable();
perf->mbpsRecvRate = m_stats.rcvr.getAverageValueFromTable();

// TODO: The following class members must be protected with a different mutex, not the m_StatsLock.
const double interval = (double) count_microseconds(currtime - m_stats.tsLastSampleTime);
perf->mbpsSendRate = double(perf->byteSent) * 8.0 / interval;
Expand Down
29 changes: 29 additions & 0 deletions srtcore/stats.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#include "platform_sys.h"
#include "packet.h"
#include "buffer_tools.h"

namespace srt
{
Expand Down Expand Up @@ -144,6 +145,8 @@ struct Sender
Metric<Packets> recvdAck; // The number of ACK packets received by the sender.
Metric<Packets> recvdNak; // The number of ACK packets received by the sender.

CMobileRateEstimator mobileRateEstimator; // The average Mbps over last second

void reset()
{
sent.reset();
Expand All @@ -167,6 +170,18 @@ struct Sender
recvdNak.resetTrace();
sentFilterExtra.resetTrace();
}

void fulfillMeasuresTable(int pkts, double bytes) {
mobileRateEstimator.addSample(pkts, bytes);
}

void resetMeasuresTable() {
mobileRateEstimator.resetMeasuresTable();
}

int getAverageValueFromTable(){
return mobileRateEstimator.getRateKbps();
}
};

/// Receiver-side statistics.
Expand All @@ -187,6 +202,8 @@ struct Receiver
Metric<Packets> sentAck; // The number of ACK packets sent by the receiver.
Metric<Packets> sentNak; // The number of NACK packets sent by the receiver.

CMobileRateEstimator mobileRateEstimator; // The average Mbps over last second

void reset()
{
recvd.reset();
Expand Down Expand Up @@ -218,6 +235,18 @@ struct Receiver
sentAck.resetTrace();
sentNak.resetTrace();
}

void fulfillMeasuresTable(int pkts, double bytes) {
mobileRateEstimator.addSample(pkts, bytes);
}

void resetMeasuresTable() {
mobileRateEstimator.resetMeasuresTable();
}

int getAverageValueFromTable(){
return mobileRateEstimator.getRateKbps();
}
};

} // namespace stats
Expand Down
Loading