copy srt estimated link capacity algorithm

This commit is contained in:
xiongguangjie
2022-09-22 00:34:42 +08:00
parent ea35002be8
commit 533f35dac4
4 changed files with 148 additions and 40 deletions

View File

@@ -1,5 +1,5 @@
#include <algorithm>
#include <math.h>
#include "Statistic.hpp"
namespace SRT {
@@ -47,47 +47,121 @@ uint32_t PacketRecvRateContext::getPacketRecvRate(uint32_t &bytesps) {
++bp; // advance bytes pointer
}
if(count>(SIZE>>1)){
bytesps = (unsigned long)ceil(1000000.0 / (double(sum) / double(bytes)));
auto ret = (uint32_t)ceil(1000000.0 / (sum / count));
return ret;
}
bytesps = 0;
return 0;
// claculate speed, or return 0 if not enough valid value
bytesps = (unsigned long)ceil(1000000.0 / (double(sum) / double(bytes)));
auto ret = (uint32_t)ceil(1000000.0 / (sum / count));
if(_cur_idx == 0)
TraceL << bytesps << " byte/sec " << ret << " pkt/sec";
return ret;
}
EstimatedLinkCapacityContext::EstimatedLinkCapacityContext(TimePoint start) : _start(start) {
for (size_t i = 0; i < SIZE; i++) {
_dur_probe_arr[i] = 1000;
}
_cur_idx = 0;
};
void EstimatedLinkCapacityContext::inputPacket(TimePoint &ts,DataPacket::Ptr& pkt) {
uint32_t seq = pkt->packet_seq_number;
auto diff = seqCmp(seq,_last_seq);
const bool retransmitted = pkt->R == 1;
const bool unordered = diff<=0;
uint32_t one = seq&0xf;
if(one == 0){
probe1Arrival(ts,pkt,unordered || retransmitted);
}
if(diff>0){
_last_seq = seq;
}
if(unordered || retransmitted){
return;
}
if(one == 1){
probe2Arrival(ts,pkt);
}
}
void EstimatedLinkCapacityContext::inputPacket(TimePoint &ts) {
if (_pkt_map.size() > 16) {
_pkt_map.erase(_pkt_map.begin());
/// Record the arrival time of the first probing packet.
void EstimatedLinkCapacityContext::probe1Arrival(TimePoint &ts, const DataPacket::Ptr &pkt, bool unordered) {
if (unordered && pkt->packet_seq_number == _probe1_seq) {
// Reset the starting probe into "undefined", when
// a packet has come as retransmitted before the
// measurement at arrival of 17th could be taken.
_probe1_seq = SEQ_NONE;
return;
}
auto tmp = DurationCountMicroseconds(ts - _start);
_pkt_map.emplace(tmp, tmp);
_ts_probe_time = ts;
_probe1_seq = pkt->packet_seq_number; // Record the sequence where 16th packet probe was taken
}
/// Record the arrival time of the second probing packet and the interval between packet pairs.
void EstimatedLinkCapacityContext::probe2Arrival(TimePoint &ts, const DataPacket::Ptr &pkt) {
// Reject probes that don't refer to the very next packet
// towards the one that was lately notified by probe1Arrival.
// Otherwise the result can be stupid.
// Simply, in case when this wasn't called exactly for the
// expected packet pair, behave as if the 17th packet was lost.
// no start point yet (or was reset) OR not very next packet
if (_probe1_seq == SEQ_NONE || incSeq(_probe1_seq) != pkt->packet_seq_number)
return;
// Reset the starting probe to prevent checking if the
// measurement was already taken.
_probe1_seq = SEQ_NONE;
// record the probing packets interval
// Adjust the time for what a complete packet would have take
const int64_t timediff = DurationCountMicroseconds(ts - _ts_probe_time);
const int64_t timediff_times_pl_size = timediff * SRT_MAX_PAYLOAD_SIZE;
// Let's take it simpler than it is coded here:
// (stating that a packet has never zero size)
//
// probe_case = (now - previous_packet_time) * SRT_MAX_PAYLOAD_SIZE / pktsz;
//
// Meaning: if the packet is fully packed, probe_case = timediff.
// Otherwise the timediff will be "converted" to a time that a fully packed packet "would take",
// provided the arrival time is proportional to the payload size and skipping
// the ETH+IP+UDP+SRT header part elliminates the constant packet delivery time influence.
//
const size_t pktsz = pkt->payloadSize();
_dur_probe_arr[_cur_idx] = pktsz ? int64_t(timediff_times_pl_size / pktsz) : int64_t(timediff);
// the window is logically circular
_cur_idx = (_cur_idx + 1) % SIZE;
}
uint32_t EstimatedLinkCapacityContext::getEstimatedLinkCapacity() {
decltype(_pkt_map.begin()) next;
std::vector<int64_t> tmp;
int64_t tmp[SIZE];
std::copy(_dur_probe_arr, _dur_probe_arr + SIZE , tmp);
std::nth_element(tmp, tmp + (SIZE / 2), tmp + SIZE);
int64_t median = tmp[SIZE / 2];
for (auto it = _pkt_map.begin(); it != _pkt_map.end(); ++it) {
next = it;
++next;
if (next != _pkt_map.end()) {
tmp.push_back(next->first - it->first);
} else {
break;
}
}
std::sort(tmp.begin(), tmp.end());
if (tmp.empty()) {
return 1000;
}
int64_t count = 1;
int64_t sum = median;
int64_t upper = median << 3; // median*8
int64_t lower = median >> 3; // median/8
if (tmp.size() < 16) {
return 1000;
}
// median filtering
const int64_t* p = _dur_probe_arr;
for (int i = 0, n = SIZE; i < n; ++ i)
{
if ((*p < upper) && (*p > lower))
{
++ count;
sum += *p;
}
++ p;
}
double dur = tmp[0] / 1e6;
return (uint32_t)(1.0 / dur);
return (uint32_t)ceil(1000000.0 / (double(sum) / double(count)));
}
/*