Compare commits
2 Commits
fe751b77b3
...
f460d7b4a5
Author | SHA1 | Date | |
---|---|---|---|
f460d7b4a5 | |||
475a99054f |
@ -25,6 +25,8 @@ add_library(solanaceae_ngcft1
|
||||
./solanaceae/ngc_ft1/cca.hpp
|
||||
./solanaceae/ngc_ft1/ledbat.hpp
|
||||
./solanaceae/ngc_ft1/ledbat.cpp
|
||||
./solanaceae/ngc_ft1/cubic.hpp
|
||||
./solanaceae/ngc_ft1/cubic.cpp
|
||||
|
||||
./solanaceae/ngc_ft1/rcv_buf.hpp
|
||||
./solanaceae/ngc_ft1/rcv_buf.cpp
|
||||
|
@ -2,6 +2,17 @@
|
||||
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
// TODO: refactor, more state tracking in ccai and seperate into flow and congestion algos
|
||||
inline bool isSkipSeqID(const std::pair<uint8_t, uint16_t>& a, const std::pair<uint8_t, uint16_t>& b) {
|
||||
// this is not perfect, would need more ft id based history
|
||||
if (a.first != b.first) {
|
||||
return false; // we dont know
|
||||
} else {
|
||||
return a.second+1 != b.second;
|
||||
}
|
||||
}
|
||||
|
||||
struct CCAI {
|
||||
public: // config
|
||||
|
49
solanaceae/ngc_ft1/cubic.cpp
Normal file
49
solanaceae/ngc_ft1/cubic.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
#include "./cubic.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
|
||||
float CUBIC::getCWnD(void) const {
|
||||
const double K = cbrt(
|
||||
(_window_max * (1. - BETA)) / SCALING_CONSTANT
|
||||
);
|
||||
|
||||
const double TK = _time_since_reduction - K;
|
||||
|
||||
const double cwnd =
|
||||
SCALING_CONSTANT
|
||||
* TK * TK * TK // TK^3
|
||||
+ _window_max
|
||||
;
|
||||
|
||||
std::cout << "K:" << K << " TK:" << TK << " cwnd:" << cwnd << " rtt:" << getCurrentDelay() << "\n";
|
||||
|
||||
return cwnd;
|
||||
}
|
||||
|
||||
float CUBIC::getCurrentDelay(void) const {
|
||||
return _rtt_ema;
|
||||
}
|
||||
|
||||
void CUBIC::addRTT(float new_delay) {
|
||||
// lerp(new_delay, rtt_ema, 0.1)
|
||||
_rtt_ema = RTT_EMA_ALPHA * new_delay + (1.f - RTT_EMA_ALPHA) * _rtt_ema;
|
||||
}
|
||||
|
||||
size_t CUBIC::canSend(void) const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<CUBIC::SeqIDType> CUBIC::getTimeouts(void) const {
|
||||
return {};
|
||||
}
|
||||
|
||||
void CUBIC::onSent(SeqIDType seq, size_t data_size) {
|
||||
}
|
||||
|
||||
void CUBIC::onAck(std::vector<SeqIDType> seqs) {
|
||||
}
|
||||
|
||||
void CUBIC::onLoss(SeqIDType seq, bool discard) {
|
||||
}
|
||||
|
64
solanaceae/ngc_ft1/cubic.hpp
Normal file
64
solanaceae/ngc_ft1/cubic.hpp
Normal file
@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
|
||||
#include "./cca.hpp"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
struct CUBIC : public CCAI {
|
||||
using clock = std::chrono::steady_clock;
|
||||
|
||||
public: // config
|
||||
static constexpr float BETA {0.7f};
|
||||
static constexpr float SCALING_CONSTANT {0.4f};
|
||||
static constexpr float RTT_EMA_ALPHA = 0.1f; // 0.1 is very smooth, might need more
|
||||
|
||||
private:
|
||||
// window size before last reduciton
|
||||
double _window_max {2.f * MAXIMUM_SEGMENT_SIZE}; // start with mss*2
|
||||
double _window_last_max {2.f * MAXIMUM_SEGMENT_SIZE};
|
||||
double _time_since_reduction {0.};
|
||||
|
||||
// initialize to low value, will get corrected very fast
|
||||
float _fwnd {0.01f * max_byterate_allowed}; // in bytes
|
||||
|
||||
// rtt exponental moving average
|
||||
float _rtt_ema {0.5f};
|
||||
|
||||
clock::time_point _time_start_offset;
|
||||
|
||||
private:
|
||||
float getCWnD(void) const;
|
||||
|
||||
// make values relative to algo start for readability (and precision)
|
||||
// get timestamp in seconds
|
||||
float getTimeNow(void) const {
|
||||
return std::chrono::duration<float>{clock::now() - _time_start_offset}.count();
|
||||
}
|
||||
|
||||
// moving avg over the last few delay samples
|
||||
// VERY sensitive to bundling acks
|
||||
float getCurrentDelay(void) const;
|
||||
|
||||
void addRTT(float new_delay);
|
||||
|
||||
public: // api
|
||||
CUBIC(size_t maximum_segment_data_size) : CCAI(maximum_segment_data_size) {}
|
||||
|
||||
// TODO: api for how much data we should send
|
||||
// take time since last sent into account
|
||||
// respect max_byterate_allowed
|
||||
size_t canSend(void) const override;
|
||||
|
||||
// get the list of timed out seq_ids
|
||||
std::vector<SeqIDType> getTimeouts(void) const override;
|
||||
|
||||
public: // callbacks
|
||||
// data size is without overhead
|
||||
void onSent(SeqIDType seq, size_t data_size) override;
|
||||
|
||||
void onAck(std::vector<SeqIDType> seqs) override;
|
||||
|
||||
// if discard, not resent, not inflight
|
||||
void onLoss(SeqIDType seq, bool discard) override;
|
||||
};
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "./ledbat.hpp"
|
||||
#include "solanaceae/ngc_ft1/cca.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
@ -68,6 +69,11 @@ void LEDBAT::onSent(SeqIDType seq, size_t data_size) {
|
||||
}
|
||||
|
||||
void LEDBAT::onAck(std::vector<SeqIDType> seqs) {
|
||||
if (seqs.empty()) {
|
||||
assert(false && "got empty list of acks???");
|
||||
return;
|
||||
}
|
||||
|
||||
// only take the smallest value
|
||||
float most_recent {-std::numeric_limits<float>::infinity()};
|
||||
|
||||
@ -75,6 +81,23 @@ void LEDBAT::onAck(std::vector<SeqIDType> seqs) {
|
||||
|
||||
const auto now {getTimeNow()};
|
||||
|
||||
{ // skip in ack is congestion event
|
||||
// 1. look at primary ack of packet
|
||||
auto it = std::find_if(_in_flight.begin(), _in_flight.end(), [seq = seqs.front()](const auto& v) -> bool {
|
||||
return std::get<0>(v) == seq;
|
||||
});
|
||||
if (it != _in_flight.end()) {
|
||||
if (isSkipSeqID(_last_ack_got, std::get<0>(*it))) {
|
||||
if (getTimeNow() >= _last_congestion_event + _last_congestion_rtt) {
|
||||
_recently_lost_data = true;
|
||||
_last_congestion_event = getTimeNow();
|
||||
_last_congestion_rtt = getCurrentDelay();
|
||||
}
|
||||
}
|
||||
// TODO: only if newer, triggers double event otherwise (without a timer)
|
||||
_last_ack_got = std::get<0>(*it);
|
||||
}
|
||||
}
|
||||
for (const auto& seq : seqs) {
|
||||
auto it = std::find_if(_in_flight.begin(), _in_flight.end(), [seq](const auto& v) -> bool {
|
||||
return std::get<0>(v) == seq;
|
||||
@ -124,16 +147,18 @@ void LEDBAT::onLoss(SeqIDType seq, bool discard) {
|
||||
}
|
||||
// TODO: reset timestamp?
|
||||
|
||||
#if 0 // temporarily disable ce for timeout
|
||||
// at most once per rtt?
|
||||
// TODO: use delay at event instead
|
||||
if (getTimeNow() >= _last_congestion_event + _last_congestion_rtt) {
|
||||
_recently_lost_data = true;
|
||||
_last_congestion_event = getTimeNow();
|
||||
_last_congestion_rtt = getCurrentDelay();
|
||||
}
|
||||
#endif
|
||||
|
||||
updateWindows();
|
||||
}
|
||||
}
|
||||
|
||||
float LEDBAT::getCurrentDelay(void) const {
|
||||
float sum {0.f};
|
||||
@ -205,7 +230,7 @@ void LEDBAT::updateWindows(void) {
|
||||
|
||||
if (_recently_lost_data) {
|
||||
_cwnd = std::clamp(
|
||||
_cwnd / 2.f,
|
||||
_cwnd * 0.7f,
|
||||
//_cwnd / 1.6f,
|
||||
2.f * MAXIMUM_SEGMENT_SIZE,
|
||||
_cwnd
|
||||
@ -213,7 +238,7 @@ void LEDBAT::updateWindows(void) {
|
||||
} else {
|
||||
// LEDBAT++ (the Rethinking the LEDBAT Protocol paper)
|
||||
// "Multiplicative decrease"
|
||||
const float constant {2.f}; // spec recs 1
|
||||
const float constant {1.f}; // spec recs 1
|
||||
if (queuing_delay < target_delay) {
|
||||
_cwnd = std::min(
|
||||
_cwnd + gain,
|
||||
|
@ -123,6 +123,8 @@ struct LEDBAT : public CCAI{
|
||||
|
||||
int64_t _in_flight_bytes {0};
|
||||
|
||||
SeqIDType _last_ack_got {0xff, 0xffff}; // some default
|
||||
|
||||
private: // helper
|
||||
clock::time_point _time_start_offset;
|
||||
};
|
||||
|
@ -826,6 +826,7 @@ bool SHA1_NGCFT1::onEvent(const Events::NGCFT1_send_data& e) {
|
||||
}
|
||||
|
||||
auto& transfer = peer.at(e.transfer_id);
|
||||
transfer.time_since_activity = 0.f;
|
||||
if (std::holds_alternative<SendingTransfer::Info>(transfer.v)) {
|
||||
auto& info_transfer = std::get<SendingTransfer::Info>(transfer.v);
|
||||
for (size_t i = 0; i < e.data_size && (i + e.data_offset) < info_transfer.info_data.size(); i++) {
|
||||
@ -859,8 +860,6 @@ bool SHA1_NGCFT1::onEvent(const Events::NGCFT1_send_data& e) {
|
||||
assert(false && "not implemented?");
|
||||
}
|
||||
|
||||
transfer.time_since_activity = 0.f;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user