From db0d8a18527265a978766c3cbfed2b5ec2b49795 Mon Sep 17 00:00:00 2001 From: Nicolas Panhaleux Date: Mon, 19 Aug 2024 14:04:49 +0200 Subject: [PATCH 01/12] [core] Average values for sent/recv bitrate are now over last second. --- srtcore/buffer_tools.cpp | 43 +++++++++++++++++++++++++++++++++ srtcore/buffer_tools.h | 52 +++++++++++++++++++++++++++++++++++----- srtcore/core.cpp | 7 ++++++ srtcore/stats.h | 29 ++++++++++++++++++++++ 4 files changed, 125 insertions(+), 6 deletions(-) diff --git a/srtcore/buffer_tools.cpp b/srtcore/buffer_tools.cpp index 3f7a77be6..235766fc3 100644 --- a/srtcore/buffer_tools.cpp +++ b/srtcore/buffer_tools.cpp @@ -272,5 +272,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; + + m_iRateKbps = m_iRateKbps * 8 / (NUM_PERIODS * SAMPLE_DURATION_MS); +} } diff --git a/srtcore/buffer_tools.h b/srtcore/buffer_tools.h index aacbd8310..fa35c6c8d 100644 --- a/srtcore/buffer_tools.h +++ b/srtcore/buffer_tools.h @@ -134,6 +134,7 @@ class CSndRateEstimator public: CSndRateEstimator(const time_point& tsNow); + CSndRateEstimator() {}; /// Add sample. /// @param [in] time sample (sending) time. @@ -147,9 +148,7 @@ class CSndRateEstimator /// Retrieve estimated bitrate in bytes per second inluding 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 @@ -187,14 +186,55 @@ class CSndRateEstimator bool empty() const { return m_iPktsCount == 0; } }; - int incSampleIdx(int val, int inc = 1) const; - - Sample m_Samples[NUM_PERIODS]; +private: + static const int NUM_PERIODS = 10; + static const int SAMPLE_DURATION_MS = 100; // 100 ms time_point m_tsFirstSampleTime; //< Start time of the first sameple. int m_iFirstSampleIdx; //< Index of the first sample. int m_iCurSampleIdx; //< Index of the current sample being collected. int m_iRateBps; // Input Rate in Bytes/sec + Sample m_Samples[NUM_PERIODS]; + + 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 diff --git a/srtcore/core.cpp b/srtcore/core.cpp index 7067e195c..6bfa76001 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -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; diff --git a/srtcore/stats.h b/srtcore/stats.h index 947489eb1..4de3b9188 100644 --- a/srtcore/stats.h +++ b/srtcore/stats.h @@ -13,6 +13,7 @@ #include "platform_sys.h" #include "packet.h" +#include "buffer_tools.h" namespace srt { @@ -144,6 +145,8 @@ struct Sender Metric recvdAck; // The number of ACK packets received by the sender. Metric recvdNak; // The number of ACK packets received by the sender. + CMobileRateEstimator mobileRateEstimator; // The average Mbps over last second + void reset() { sent.reset(); @@ -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. @@ -187,6 +202,8 @@ struct Receiver Metric sentAck; // The number of ACK packets sent by the receiver. Metric sentNak; // The number of NACK packets sent by the receiver. + CMobileRateEstimator mobileRateEstimator; // The average Mbps over last second + void reset() { recvd.reset(); @@ -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 From 78b3412ca6d600792e33348dab40817c1c383883 Mon Sep 17 00:00:00 2001 From: Nicolas Panhaleux Date: Mon, 19 Aug 2024 14:23:20 +0200 Subject: [PATCH 02/12] [core] Adding packet header size in average measure --- srtcore/buffer_tools.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/srtcore/buffer_tools.cpp b/srtcore/buffer_tools.cpp index e9f15013b..f9d8a3d06 100644 --- a/srtcore/buffer_tools.cpp +++ b/srtcore/buffer_tools.cpp @@ -312,9 +312,9 @@ void CMobileRateEstimator::computeAverageValueFromTable(){ m_iRateKbps = 0; for(int i = 0; i < NUM_PERIODS; i++) - m_iRateKbps += m_Samples[i].m_iBytesCount; + m_iRateKbps += (m_Samples[i].m_iBytesCount + (CPacket::HDR_SIZE * m_Samples[i].m_iPktsCount)) * 8; - m_iRateKbps = m_iRateKbps * 8 / (NUM_PERIODS * SAMPLE_DURATION_MS); + m_iRateKbps = m_iRateKbps / (NUM_PERIODS * SAMPLE_DURATION_MS); } } From cd42a9bed4b666e1d5c001e5e96421a31512eb94 Mon Sep 17 00:00:00 2001 From: Nicolas Panhaleux Date: Mon, 19 Aug 2024 14:37:39 +0200 Subject: [PATCH 03/12] [core] Fixing auto merge removed methode --- srtcore/buffer_tools.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/srtcore/buffer_tools.h b/srtcore/buffer_tools.h index 430b4a612..168b068b2 100644 --- a/srtcore/buffer_tools.h +++ b/srtcore/buffer_tools.h @@ -197,6 +197,8 @@ class CSndRateEstimator 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 From ba4181505961187641e7d34c3f98ee78421075dc Mon Sep 17 00:00:00 2001 From: Nicolas Panhaleux Date: Thu, 22 Aug 2024 11:55:12 +0200 Subject: [PATCH 04/12] [core] Refactoring pull request --- srtcore/buffer_tools.cpp | 69 ++++++++++++++++++++++++---------------- srtcore/buffer_tools.h | 41 +++++++++++------------- srtcore/core.cpp | 8 ++--- srtcore/stats.h | 28 +++++----------- 4 files changed, 71 insertions(+), 75 deletions(-) diff --git a/srtcore/buffer_tools.cpp b/srtcore/buffer_tools.cpp index f9d8a3d06..57e028f11 100644 --- a/srtcore/buffer_tools.cpp +++ b/srtcore/buffer_tools.cpp @@ -273,48 +273,61 @@ int CSndRateEstimator::incSampleIdx(int val, int inc) const return val; } -CMobileRateEstimator::CMobileRateEstimator() - : m_iCurSampleIdx(0) - , m_iRateKbps(0) +CMovingRateEstimator::CMovingRateEstimator() + : CSndRateEstimator(sync::steady_clock::now()) + , m_Samples(NUM_PERIODS) { - resetMeasuresTable(); + resetRate(0, NUM_PERIODS); } -void CMobileRateEstimator::addSample(int pkts, double bytes) +void CMovingRateEstimator::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); + const time_point now = steady_clock::now(); + const int iSampleDeltaIdx = (int)count_milliseconds(now - lastSlotTimestamp) / SAMPLE_DURATION_MS; + + if (iSampleDeltaIdx == 0) + { + m_Samples[m_iCurSampleIdx].m_iBytesCount += bytes; + m_Samples[m_iCurSampleIdx].m_iPktsCount += pkts; } + else + { + if ((m_iCurSampleIdx + iSampleDeltaIdx) < NUM_PERIODS) + resetRate(m_iCurSampleIdx + 1, m_iCurSampleIdx + iSampleDeltaIdx); + else + { + int loopbackDiff = m_iCurSampleIdx + iSampleDeltaIdx - NUM_PERIODS; + resetRate(m_iCurSampleIdx + 1, NUM_PERIODS); + resetRate(0, loopbackDiff); + } - m_iCurSampleIdx = ((m_iCurSampleIdx + iSampleDeltaIdx) % NUM_PERIODS); - m_Samples[m_iCurSampleIdx].m_iBytesCount = bytes; - m_Samples[m_iCurSampleIdx].m_iPktsCount = pkts; + m_iCurSampleIdx = ((m_iCurSampleIdx + iSampleDeltaIdx) % NUM_PERIODS); + m_Samples[m_iCurSampleIdx].m_iBytesCount = bytes; + m_Samples[m_iCurSampleIdx].m_iPktsCount = pkts; - lastTimestamp = now; + lastSlotTimestamp = now; + } - computeAverageValueFromTable(); + computeAverageValue(); } -void CMobileRateEstimator::resetMeasuresTable(int from, int to) +void CMovingRateEstimator::resetRate(int from, int to) { - for(int i = max(0, from); i < min(int(NUM_PERIODS), to); i++) + for (int i = max(0, from); i < min(int(NUM_PERIODS), to); i++) m_Samples[i].reset(); } -void CMobileRateEstimator::computeAverageValueFromTable(){ - m_iRateKbps = 0; +void CMovingRateEstimator::computeAverageValue() +{ + const time_point now = steady_clock::now(); + const int startDelta = count_milliseconds(now - m_tsFirstSampleTime); + const bool isFirstPeriod = startDelta < 1000; + m_iRateBps = 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; + for (int i = 0; i < NUM_PERIODS; i++) + m_iRateBps += (m_Samples[i].m_iBytesCount + (CPacket::HDR_SIZE * m_Samples[i].m_iPktsCount)); - m_iRateKbps = m_iRateKbps / (NUM_PERIODS * SAMPLE_DURATION_MS); + if (isFirstPeriod) + m_iRateBps = m_iRateBps * 1000 / startDelta; } -} - +} // namespace srt diff --git a/srtcore/buffer_tools.h b/srtcore/buffer_tools.h index 168b068b2..dadafdd45 100644 --- a/srtcore/buffer_tools.h +++ b/srtcore/buffer_tools.h @@ -134,7 +134,6 @@ class CSndRateEstimator public: CSndRateEstimator(const time_point& tsNow); - CSndRateEstimator() {}; /// Add sample. /// @param [in] time sample (sending) time. @@ -150,6 +149,10 @@ class CSndRateEstimator int getCurrentRate() const; protected: + int m_iCurSampleIdx; //< Index of the current sample being collected. + int m_iRateBps; //< Rate in Bytes/sec. + time_point m_tsFirstSampleTime; //< Start time of the first sample. + struct Sample { int m_iPktsCount; // number of payload packets @@ -190,23 +193,18 @@ class CSndRateEstimator 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. + Sample m_Samples[NUM_PERIODS]; + int m_iFirstSampleIdx; //< Index of the first sample. int incSampleIdx(int val, int inc = 1) const; }; -class CMobileRateEstimator:CSndRateEstimator +class CMovingRateEstimator : CSndRateEstimator { typedef sync::steady_clock::time_point time_point; public: - CMobileRateEstimator(); + CMovingRateEstimator(); /// Add sample. /// @param [in] pkts number of packets in the sample. @@ -214,26 +212,25 @@ class CMobileRateEstimator:CSndRateEstimator void addSample(int pkts = 0, double bytes = 0); /// Clean the mobile measures table to reset average value. - void resetMeasuresTable() {resetMeasuresTable(0,NUM_PERIODS);}; + void resetRate() { resetRate(0, NUM_PERIODS); }; - /// Retrieve estimated bitrate in kilobits per second - int getRateKbps() const { return m_iRateKbps; } + /// Retrieve estimated bitrate in bytes per second with 16-byte packet header. + int getRate() const { return m_iRateBps; } 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 + const int NUM_PERIODS = 100; // To get 1s of values + const int SAMPLE_DURATION_MS = 10; // 10 ms + time_point lastSlotTimestamp; // Used to compute the delta between 2 calls + srt::FixedArray m_Samples; // 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(); + /// This method will compute the average value based on all table's measures and the period + /// (NUM_PERIODS*SAMPLE_DURATION_MS) + void computeAverageValue(); /// 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); + void resetRate(int from, int to); }; } // namespace srt diff --git a/srtcore/core.cpp b/srtcore/core.cpp index 16ecd70db..24d1879d5 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -7571,11 +7571,9 @@ void srt::CUDT::bstats(CBytePerfMon *perf, bool clear, bool instantaneous) // 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(); - + perf->mbpsSendRate = Bps2Mbps(m_stats.sndr.getAverageValue()); + perf->mbpsRecvRate = Bps2Mbps(m_stats.rcvr.getAverageValue()); + // 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; diff --git a/srtcore/stats.h b/srtcore/stats.h index 4de3b9188..16043fc35 100644 --- a/srtcore/stats.h +++ b/srtcore/stats.h @@ -145,7 +145,7 @@ struct Sender Metric recvdAck; // The number of ACK packets received by the sender. Metric recvdNak; // The number of ACK packets received by the sender. - CMobileRateEstimator mobileRateEstimator; // The average Mbps over last second + CMovingRateEstimator mobileRateEstimator; // The average Mbps over last second void reset() { @@ -171,17 +171,11 @@ struct Sender sentFilterExtra.resetTrace(); } - void fulfillMeasuresTable(int pkts, double bytes) { - mobileRateEstimator.addSample(pkts, bytes); - } + void updateRate(int pkts, double bytes) { mobileRateEstimator.addSample(pkts, bytes); } - void resetMeasuresTable() { - mobileRateEstimator.resetMeasuresTable(); - } + void resetRate() { mobileRateEstimator.resetRate(); } - int getAverageValueFromTable(){ - return mobileRateEstimator.getRateKbps(); - } + int getAverageValue() { return mobileRateEstimator.getRate(); } }; /// Receiver-side statistics. @@ -202,7 +196,7 @@ struct Receiver Metric sentAck; // The number of ACK packets sent by the receiver. Metric sentNak; // The number of NACK packets sent by the receiver. - CMobileRateEstimator mobileRateEstimator; // The average Mbps over last second + CMovingRateEstimator mobileRateEstimator; // The average Mbps over last second void reset() { @@ -236,17 +230,11 @@ struct Receiver sentNak.resetTrace(); } - void fulfillMeasuresTable(int pkts, double bytes) { - mobileRateEstimator.addSample(pkts, bytes); - } + void updateRate(int pkts, double bytes) { mobileRateEstimator.addSample(pkts, bytes); } - void resetMeasuresTable() { - mobileRateEstimator.resetMeasuresTable(); - } + void resetRate() { mobileRateEstimator.resetRate(); } - int getAverageValueFromTable(){ - return mobileRateEstimator.getRateKbps(); - } + int getAverageValue() { return mobileRateEstimator.getRate(); } }; } // namespace stats From 768db18caf173dd6ee440fb596e872f873c4436e Mon Sep 17 00:00:00 2001 From: Nicolas Panhaleux Date: Thu, 22 Aug 2024 14:26:04 +0200 Subject: [PATCH 05/12] [core] Compiler warning fix --- srtcore/buffer_tools.cpp | 4 ++-- srtcore/buffer_tools.h | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/srtcore/buffer_tools.cpp b/srtcore/buffer_tools.cpp index 57e028f11..ff84cb695 100644 --- a/srtcore/buffer_tools.cpp +++ b/srtcore/buffer_tools.cpp @@ -157,9 +157,10 @@ void CRateEstimator::updateInputRate(const time_point& time, int pkts, int bytes CSndRateEstimator::CSndRateEstimator(const time_point& tsNow) : m_tsFirstSampleTime(tsNow) - , m_iFirstSampleIdx(0) , m_iCurSampleIdx(0) , m_iRateBps(0) + , m_Samples(NUM_PERIODS) + , m_iFirstSampleIdx(0) { } @@ -275,7 +276,6 @@ int CSndRateEstimator::incSampleIdx(int val, int inc) const CMovingRateEstimator::CMovingRateEstimator() : CSndRateEstimator(sync::steady_clock::now()) - , m_Samples(NUM_PERIODS) { resetRate(0, NUM_PERIODS); } diff --git a/srtcore/buffer_tools.h b/srtcore/buffer_tools.h index dadafdd45..c75fd4b77 100644 --- a/srtcore/buffer_tools.h +++ b/srtcore/buffer_tools.h @@ -149,9 +149,9 @@ class CSndRateEstimator int getCurrentRate() const; protected: + time_point m_tsFirstSampleTime; //< Start time of the first sample. int m_iCurSampleIdx; //< Index of the current sample being collected. int m_iRateBps; //< Rate in Bytes/sec. - time_point m_tsFirstSampleTime; //< Start time of the first sample. struct Sample { @@ -190,11 +190,12 @@ class CSndRateEstimator bool empty() const { return m_iPktsCount == 0; } }; + srt::FixedArray m_Samples; // Table of stored data + private: static const int NUM_PERIODS = 10; static const int SAMPLE_DURATION_MS = 100; // 100 ms - Sample m_Samples[NUM_PERIODS]; - int m_iFirstSampleIdx; //< Index of the first sample. + int m_iFirstSampleIdx; //< Index of the first sample. int incSampleIdx(int val, int inc = 1) const; }; @@ -218,10 +219,9 @@ class CMovingRateEstimator : CSndRateEstimator int getRate() const { return m_iRateBps; } private: - const int NUM_PERIODS = 100; // To get 1s of values - const int SAMPLE_DURATION_MS = 10; // 10 ms - time_point lastSlotTimestamp; // Used to compute the delta between 2 calls - srt::FixedArray m_Samples; // Table of stored data + const int NUM_PERIODS = 100; // To get 1s of values + const int SAMPLE_DURATION_MS = 10; // 10 ms + time_point lastSlotTimestamp; // Used to compute the delta between 2 calls /// This method will compute the average value based on all table's measures and the period /// (NUM_PERIODS*SAMPLE_DURATION_MS) From 1d3e6083a5eeeb56742ed04bc7db9280628039db Mon Sep 17 00:00:00 2001 From: Nicolas Panhaleux Date: Thu, 22 Aug 2024 16:28:46 +0200 Subject: [PATCH 06/12] [core] Removing inheritance and fixing issue in rate compute --- srtcore/buffer_tools.cpp | 6 ++++- srtcore/buffer_tools.h | 47 +++++++++++++++++++++++++++++++++++++++- srtcore/core.cpp | 8 ++++--- 3 files changed, 56 insertions(+), 5 deletions(-) diff --git a/srtcore/buffer_tools.cpp b/srtcore/buffer_tools.cpp index ff84cb695..194c49c09 100644 --- a/srtcore/buffer_tools.cpp +++ b/srtcore/buffer_tools.cpp @@ -275,7 +275,11 @@ int CSndRateEstimator::incSampleIdx(int val, int inc) const } CMovingRateEstimator::CMovingRateEstimator() - : CSndRateEstimator(sync::steady_clock::now()) + : m_tsFirstSampleTime(sync::steady_clock::now()) + , m_iFirstSampleIdx(0) + , m_iCurSampleIdx(0) + , m_iRateBps(0) + , m_Samples(NUM_PERIODS) { resetRate(0, NUM_PERIODS); } diff --git a/srtcore/buffer_tools.h b/srtcore/buffer_tools.h index c75fd4b77..0be738da6 100644 --- a/srtcore/buffer_tools.h +++ b/srtcore/buffer_tools.h @@ -200,7 +200,7 @@ class CSndRateEstimator int incSampleIdx(int val, int inc = 1) const; }; -class CMovingRateEstimator : CSndRateEstimator +class CMovingRateEstimator { typedef sync::steady_clock::time_point time_point; @@ -219,9 +219,54 @@ class CMovingRateEstimator : CSndRateEstimator int getRate() const { return m_iRateBps; } private: + // We would like responsiveness (accuracy) of rate estimation higher than 100 ms + // (ideally around 50 ms) for network adaptive algorithms. const int NUM_PERIODS = 100; // To get 1s of values const int SAMPLE_DURATION_MS = 10; // 10 ms + time_point m_tsFirstSampleTime; //< Start time of the first sample. time_point lastSlotTimestamp; // Used to compute the delta between 2 calls + 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. + + struct Sample + { + int m_iPktsCount; // number of payload packets + int m_iBytesCount; // number of payload bytes + + void reset() + { + m_iPktsCount = 0; + m_iBytesCount = 0; + } + + Sample() + : m_iPktsCount(0) + , m_iBytesCount(0) + { + } + + Sample(int iPkts, int iBytes) + : m_iPktsCount(iPkts) + , m_iBytesCount(iBytes) + { + } + + Sample operator+(const Sample& other) + { + return Sample(m_iPktsCount + other.m_iPktsCount, m_iBytesCount + other.m_iBytesCount); + } + + Sample& operator+=(const Sample& other) + { + *this = *this + other; + return *this; + } + + bool empty() const { return m_iPktsCount == 0; } + }; + + srt::FixedArray m_Samples; // 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) diff --git a/srtcore/core.cpp b/srtcore/core.cpp index 24d1879d5..f6d38e3a7 100644 --- a/srtcore/core.cpp +++ b/srtcore/core.cpp @@ -7571,13 +7571,13 @@ void srt::CUDT::bstats(CBytePerfMon *perf, bool clear, bool instantaneous) // Average values management + // We are updating rate with 0 Byte 0 packet to ensure an up to date compute in case we are not sending packet for a while. + m_stats.sndr.updateRate(0, 0); + m_stats.rcvr.updateRate(0, 0); perf->mbpsSendRate = Bps2Mbps(m_stats.sndr.getAverageValue()); perf->mbpsRecvRate = Bps2Mbps(m_stats.rcvr.getAverageValue()); // 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; - perf->mbpsRecvRate = double(perf->byteRecv) * 8.0 / interval; perf->usPktSndPeriod = (double) count_microseconds(m_tdSendInterval.load()); perf->pktFlowWindow = m_iFlowWindowSize.load(); perf->pktCongestionWindow = m_iCongestionWindow; @@ -9730,6 +9730,7 @@ bool srt::CUDT::packData(CPacket& w_packet, steady_clock::time_point& w_nexttime m_stats.sndr.sent.count(payload); if (new_packet_packed) m_stats.sndr.sentUnique.count(payload); + m_stats.sndr.updateRate(1, payload); leaveCS(m_StatsLock); const duration sendint = m_tdSendInterval; @@ -10406,6 +10407,7 @@ int srt::CUDT::processData(CUnit* in_unit) enterCS(m_StatsLock); m_stats.rcvr.recvd.count(pktsz); + m_stats.rcvr.updateRate(1, pktsz); leaveCS(m_StatsLock); loss_seqs_t filter_loss_seqs; From a3c8a828e5731de0f8af0ce58227c08ea0362538 Mon Sep 17 00:00:00 2001 From: Nicolas Panhaleux Date: Thu, 22 Aug 2024 17:50:34 +0200 Subject: [PATCH 07/12] [core] Changing stats var name --- srtcore/stats.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/srtcore/stats.h b/srtcore/stats.h index 16043fc35..4b67378fd 100644 --- a/srtcore/stats.h +++ b/srtcore/stats.h @@ -145,7 +145,7 @@ struct Sender Metric recvdAck; // The number of ACK packets received by the sender. Metric recvdNak; // The number of ACK packets received by the sender. - CMovingRateEstimator mobileRateEstimator; // The average Mbps over last second + CMovingRateEstimator mavgRateEstimator; // The average Mbps over last second void reset() { @@ -171,11 +171,11 @@ struct Sender sentFilterExtra.resetTrace(); } - void updateRate(int pkts, double bytes) { mobileRateEstimator.addSample(pkts, bytes); } + void updateRate(int pkts, double bytes) { mavgRateEstimator.addSample(pkts, bytes); } - void resetRate() { mobileRateEstimator.resetRate(); } + void resetRate() { mavgRateEstimator.resetRate(); } - int getAverageValue() { return mobileRateEstimator.getRate(); } + int getAverageValue() { return mavgRateEstimator.getRate(); } }; /// Receiver-side statistics. @@ -196,7 +196,7 @@ struct Receiver Metric sentAck; // The number of ACK packets sent by the receiver. Metric sentNak; // The number of NACK packets sent by the receiver. - CMovingRateEstimator mobileRateEstimator; // The average Mbps over last second + CMovingRateEstimator mavgRateEstimator; // The average Mbps over last second void reset() { @@ -230,11 +230,11 @@ struct Receiver sentNak.resetTrace(); } - void updateRate(int pkts, double bytes) { mobileRateEstimator.addSample(pkts, bytes); } + void updateRate(int pkts, double bytes) { mavgRateEstimator.addSample(pkts, bytes); } - void resetRate() { mobileRateEstimator.resetRate(); } + void resetRate() { mavgRateEstimator.resetRate(); } - int getAverageValue() { return mobileRateEstimator.getRate(); } + int getAverageValue() { return mavgRateEstimator.getRate(); } }; } // namespace stats From 0eb1cf79bbb6613d9cb023b271b5e310537dd704 Mon Sep 17 00:00:00 2001 From: Nicolas Panhaleux Date: Thu, 22 Aug 2024 17:59:30 +0200 Subject: [PATCH 08/12] [core] Restoring CSndRateEstimator --- srtcore/buffer_tools.cpp | 3 +-- srtcore/buffer_tools.h | 20 +++++++++----------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/srtcore/buffer_tools.cpp b/srtcore/buffer_tools.cpp index 194c49c09..bbe9da046 100644 --- a/srtcore/buffer_tools.cpp +++ b/srtcore/buffer_tools.cpp @@ -157,10 +157,9 @@ void CRateEstimator::updateInputRate(const time_point& time, int pkts, int bytes CSndRateEstimator::CSndRateEstimator(const time_point& tsNow) : m_tsFirstSampleTime(tsNow) + , m_iFirstSampleIdx(0) , m_iCurSampleIdx(0) , m_iRateBps(0) - , m_Samples(NUM_PERIODS) - , m_iFirstSampleIdx(0) { } diff --git a/srtcore/buffer_tools.h b/srtcore/buffer_tools.h index 0be738da6..a4d552c29 100644 --- a/srtcore/buffer_tools.h +++ b/srtcore/buffer_tools.h @@ -148,11 +148,9 @@ class CSndRateEstimator /// including the current sampling interval. int getCurrentRate() const; -protected: - time_point m_tsFirstSampleTime; //< Start time of the first sample. - int m_iCurSampleIdx; //< Index of the current sample being collected. - int m_iRateBps; //< Rate in Bytes/sec. - +private: + static const int NUM_PERIODS = 10; + static const int SAMPLE_DURATION_MS = 100; // 100 ms struct Sample { int m_iPktsCount; // number of payload packets @@ -190,14 +188,14 @@ class CSndRateEstimator bool empty() const { return m_iPktsCount == 0; } }; - srt::FixedArray m_Samples; // Table of stored data + int incSampleIdx(int val, int inc = 1) const; -private: - static const int NUM_PERIODS = 10; - static const int SAMPLE_DURATION_MS = 100; // 100 ms - int m_iFirstSampleIdx; //< Index of the first sample. + Sample m_Samples[NUM_PERIODS]; - int incSampleIdx(int val, int inc = 1) const; + time_point m_tsFirstSampleTime; //< Start time of the first sameple. + int m_iFirstSampleIdx; //< Index of the first sample. + int m_iCurSampleIdx; //< Index of the current sample being collected. + int m_iRateBps; // Input Rate in Bytes/sec }; class CMovingRateEstimator From 85161cff76efbcf120271cb202aa0aa2d62c46ac Mon Sep 17 00:00:00 2001 From: Nicolas Panhaleux Date: Mon, 26 Aug 2024 10:05:20 +0200 Subject: [PATCH 09/12] [core] Refactoring rate compute and variables name --- srtcore/buffer_tools.cpp | 18 ++++++++++-------- srtcore/buffer_tools.h | 14 +++++++------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/srtcore/buffer_tools.cpp b/srtcore/buffer_tools.cpp index bbe9da046..22a3d49cc 100644 --- a/srtcore/buffer_tools.cpp +++ b/srtcore/buffer_tools.cpp @@ -286,7 +286,7 @@ CMovingRateEstimator::CMovingRateEstimator() void CMovingRateEstimator::addSample(int pkts, double bytes) { const time_point now = steady_clock::now(); - const int iSampleDeltaIdx = (int)count_milliseconds(now - lastSlotTimestamp) / SAMPLE_DURATION_MS; + const int iSampleDeltaIdx = int(count_milliseconds(now - m_tsLastSlotTimestamp) / SAMPLE_DURATION_MS); if (iSampleDeltaIdx == 0) { @@ -308,10 +308,10 @@ void CMovingRateEstimator::addSample(int pkts, double bytes) m_Samples[m_iCurSampleIdx].m_iBytesCount = bytes; m_Samples[m_iCurSampleIdx].m_iPktsCount = pkts; - lastSlotTimestamp = now; - } + m_tsLastSlotTimestamp += milliseconds_from(SAMPLE_DURATION_MS * iSampleDeltaIdx); - computeAverageValue(); + computeAverageValue(); + } } void CMovingRateEstimator::resetRate(int from, int to) @@ -324,13 +324,15 @@ void CMovingRateEstimator::computeAverageValue() { const time_point now = steady_clock::now(); const int startDelta = count_milliseconds(now - m_tsFirstSampleTime); - const bool isFirstPeriod = startDelta < 1000; - m_iRateBps = 0; + const bool isFirstPeriod = startDelta < (SAMPLE_DURATION_MS * NUM_PERIODS); + int newRateBps = 0; for (int i = 0; i < NUM_PERIODS; i++) - m_iRateBps += (m_Samples[i].m_iBytesCount + (CPacket::HDR_SIZE * m_Samples[i].m_iPktsCount)); + newRateBps += (m_Samples[i].m_iBytesCount + (CPacket::HDR_SIZE * m_Samples[i].m_iPktsCount)); if (isFirstPeriod) - m_iRateBps = m_iRateBps * 1000 / startDelta; + newRateBps = newRateBps * 1000 / startDelta; + + m_iRateBps = newRateBps; } } // namespace srt diff --git a/srtcore/buffer_tools.h b/srtcore/buffer_tools.h index a4d552c29..e937df235 100644 --- a/srtcore/buffer_tools.h +++ b/srtcore/buffer_tools.h @@ -219,13 +219,13 @@ class CMovingRateEstimator private: // We would like responsiveness (accuracy) of rate estimation higher than 100 ms // (ideally around 50 ms) for network adaptive algorithms. - const int NUM_PERIODS = 100; // To get 1s of values - const int SAMPLE_DURATION_MS = 10; // 10 ms - time_point m_tsFirstSampleTime; //< Start time of the first sample. - time_point lastSlotTimestamp; // Used to compute the delta between 2 calls - 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. + static const int NUM_PERIODS = 100; // To get 1s of values + static const int SAMPLE_DURATION_MS = 10; // 10 ms + time_point m_tsFirstSampleTime; //< Start time of the first sample. + time_point m_tsLastSlotTimestamp; // Used to compute the delta between 2 calls + 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. struct Sample { From 1fb7fabba9a511aeb582c49ba57d3f31e3c9b7f0 Mon Sep 17 00:00:00 2001 From: Nicolas Panhaleux Date: Mon, 26 Aug 2024 14:01:25 +0200 Subject: [PATCH 10/12] [core] Fixing division by 0. --- srtcore/buffer_tools.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srtcore/buffer_tools.cpp b/srtcore/buffer_tools.cpp index 22a3d49cc..4e9e83bb6 100644 --- a/srtcore/buffer_tools.cpp +++ b/srtcore/buffer_tools.cpp @@ -331,7 +331,7 @@ void CMovingRateEstimator::computeAverageValue() newRateBps += (m_Samples[i].m_iBytesCount + (CPacket::HDR_SIZE * m_Samples[i].m_iPktsCount)); if (isFirstPeriod) - newRateBps = newRateBps * 1000 / startDelta; + newRateBps = newRateBps * SAMPLE_DURATION_MS * NUM_PERIODS / max(1, startDelta); m_iRateBps = newRateBps; } From a46819bfdd33a0a9ec08a74af2c17785363d4d79 Mon Sep 17 00:00:00 2001 From: Nicolas Panhaleux Date: Mon, 26 Aug 2024 14:23:38 +0200 Subject: [PATCH 11/12] [core] Removing unused variable (copy/paste from mother class) --- srtcore/buffer_tools.h | 1 - 1 file changed, 1 deletion(-) diff --git a/srtcore/buffer_tools.h b/srtcore/buffer_tools.h index e937df235..ebc5e6b79 100644 --- a/srtcore/buffer_tools.h +++ b/srtcore/buffer_tools.h @@ -223,7 +223,6 @@ class CMovingRateEstimator static const int SAMPLE_DURATION_MS = 10; // 10 ms time_point m_tsFirstSampleTime; //< Start time of the first sample. time_point m_tsLastSlotTimestamp; // Used to compute the delta between 2 calls - 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. From cb44223370eb05e1e3d77cadedad6157c472851d Mon Sep 17 00:00:00 2001 From: Nicolas Panhaleux Date: Mon, 26 Aug 2024 14:25:15 +0200 Subject: [PATCH 12/12] [core] Removing unused variable from c file too... --- srtcore/buffer_tools.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/srtcore/buffer_tools.cpp b/srtcore/buffer_tools.cpp index 4e9e83bb6..cd6fcf21f 100644 --- a/srtcore/buffer_tools.cpp +++ b/srtcore/buffer_tools.cpp @@ -275,7 +275,6 @@ int CSndRateEstimator::incSampleIdx(int val, int inc) const CMovingRateEstimator::CMovingRateEstimator() : m_tsFirstSampleTime(sync::steady_clock::now()) - , m_iFirstSampleIdx(0) , m_iCurSampleIdx(0) , m_iRateBps(0) , m_Samples(NUM_PERIODS)