2023-08-24 18:04:25 +02:00
|
|
|
#include "./cubic.hpp"
|
|
|
|
|
|
|
|
#include <cmath>
|
|
|
|
#include <iostream>
|
|
|
|
|
2024-05-27 11:59:32 +02:00
|
|
|
void CUBIC::updateReductionTimer(float time_delta) {
|
|
|
|
const auto now {getTimeNow()};
|
|
|
|
|
|
|
|
// only keep updating while the cca interaction is not too long ago
|
2024-05-27 18:07:19 +02:00
|
|
|
if (now - _time_point_last_update <= getCurrentDelay()*4.f) {
|
2024-05-27 11:59:32 +02:00
|
|
|
_time_since_reduction += time_delta;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CUBIC::resetReductionTimer(void) {
|
|
|
|
_time_since_reduction = 0.f;
|
|
|
|
}
|
|
|
|
|
2023-08-24 18:04:25 +02:00
|
|
|
float CUBIC::getCWnD(void) const {
|
|
|
|
const double K = cbrt(
|
|
|
|
(_window_max * (1. - BETA)) / SCALING_CONSTANT
|
|
|
|
);
|
|
|
|
|
2024-05-27 11:59:32 +02:00
|
|
|
const double TK = _time_since_reduction - K;
|
2023-08-24 18:04:25 +02:00
|
|
|
|
|
|
|
const double cwnd =
|
|
|
|
SCALING_CONSTANT
|
|
|
|
* TK * TK * TK // TK^3
|
|
|
|
+ _window_max
|
|
|
|
;
|
|
|
|
|
2023-08-30 13:45:09 +02:00
|
|
|
#if 0
|
2023-08-30 03:03:43 +02:00
|
|
|
std::cout
|
|
|
|
<< "K:" << K
|
|
|
|
<< " ts:" << time_since_reduction
|
|
|
|
<< " TK:" << TK
|
|
|
|
<< " cwnd:" << cwnd
|
|
|
|
<< " rtt:" << getCurrentDelay()
|
|
|
|
<< "\n"
|
|
|
|
;
|
2023-08-30 13:45:09 +02:00
|
|
|
#endif
|
2023-08-24 18:04:25 +02:00
|
|
|
|
2023-08-30 03:03:43 +02:00
|
|
|
return std::max<float>(cwnd, 2.f * MAXIMUM_SEGMENT_SIZE);
|
2023-08-24 18:04:25 +02:00
|
|
|
}
|
|
|
|
|
2023-08-30 03:03:43 +02:00
|
|
|
void CUBIC::onCongestion(void) {
|
2023-10-16 19:51:56 +02:00
|
|
|
// 8 is probably too much (800ms for 100ms rtt)
|
2024-05-27 11:59:32 +02:00
|
|
|
if (_time_since_reduction >= getCurrentDelay()*4.f) {
|
|
|
|
const auto tmp_old_tp = _time_since_reduction;
|
2023-09-02 02:28:22 +02:00
|
|
|
|
2023-10-16 19:51:56 +02:00
|
|
|
const auto current_cwnd = getCWnD(); // TODO: remove, only used by logging?
|
2023-09-08 00:41:25 +02:00
|
|
|
const auto current_wnd = getWindow(); // respects cwnd and fwnd
|
|
|
|
|
2024-05-27 20:51:42 +02:00
|
|
|
_bytes_leftover = 0;
|
2024-05-27 11:59:32 +02:00
|
|
|
resetReductionTimer();
|
2023-10-16 19:51:56 +02:00
|
|
|
|
|
|
|
if (current_cwnd < _window_max) {
|
|
|
|
// congestion before reaching the inflection point (prev window_max).
|
|
|
|
// reduce to wnd*beta to be fair
|
|
|
|
_window_max = current_wnd * BETA;
|
|
|
|
} else {
|
|
|
|
_window_max = current_wnd;
|
|
|
|
}
|
|
|
|
|
|
|
|
_window_max = std::max(_window_max, 2.0*MAXIMUM_SEGMENT_SIZE);
|
2023-08-24 18:04:25 +02:00
|
|
|
|
2023-09-01 17:34:05 +02:00
|
|
|
#if 1
|
2023-09-02 02:28:22 +02:00
|
|
|
std::cout << "----CONGESTION!"
|
2023-09-08 00:41:25 +02:00
|
|
|
<< " cwnd:" << current_cwnd
|
|
|
|
<< " wnd:" << current_wnd
|
2023-09-01 17:34:05 +02:00
|
|
|
<< " cwnd_max:" << _window_max
|
|
|
|
<< " pts:" << tmp_old_tp
|
|
|
|
<< " rtt:" << getCurrentDelay()
|
|
|
|
<< "\n"
|
|
|
|
;
|
|
|
|
#endif
|
2023-08-30 13:45:09 +02:00
|
|
|
}
|
2023-08-24 18:04:25 +02:00
|
|
|
}
|
|
|
|
|
2023-09-08 00:41:25 +02:00
|
|
|
float CUBIC::getWindow(void) {
|
|
|
|
return std::min<float>(getCWnD(), FlowOnly::getWindow());
|
|
|
|
}
|
|
|
|
|
2024-01-07 17:23:06 +01:00
|
|
|
int64_t CUBIC::canSend(float time_delta) {
|
|
|
|
const auto fspace_pkgs = FlowOnly::canSend(time_delta);
|
2023-08-24 18:04:25 +02:00
|
|
|
|
2024-05-27 11:59:32 +02:00
|
|
|
updateReductionTimer(time_delta);
|
|
|
|
|
2023-08-30 13:45:09 +02:00
|
|
|
if (fspace_pkgs == 0u) {
|
|
|
|
return 0u;
|
2023-08-30 03:03:43 +02:00
|
|
|
}
|
2023-08-24 18:04:25 +02:00
|
|
|
|
2023-12-13 17:56:56 +01:00
|
|
|
const auto window = getCWnD();
|
2024-05-27 20:51:42 +02:00
|
|
|
int64_t cspace_bytes = (window - _in_flight_bytes) + _bytes_leftover;
|
2023-08-30 13:45:09 +02:00
|
|
|
if (cspace_bytes < MAXIMUM_SEGMENT_DATA_SIZE) {
|
2023-08-30 03:03:43 +02:00
|
|
|
return 0u;
|
|
|
|
}
|
2023-08-24 18:04:25 +02:00
|
|
|
|
2023-12-13 17:56:56 +01:00
|
|
|
// also limit to max sendrate per tick, which is usually smaller than window
|
|
|
|
// this is mostly to prevent spikes on empty windows
|
2023-12-15 15:31:32 +01:00
|
|
|
const auto rate = window / getCurrentDelay();
|
|
|
|
|
2023-12-13 17:56:56 +01:00
|
|
|
// we dont want this limit to fall below atleast 1 segment
|
2023-12-15 15:31:32 +01:00
|
|
|
const int64_t max_bytes_per_tick = std::max<int64_t>(rate * time_delta + 0.5f, MAXIMUM_SEGMENT_SIZE);
|
2023-12-13 17:56:56 +01:00
|
|
|
cspace_bytes = std::min<int64_t>(cspace_bytes, max_bytes_per_tick);
|
|
|
|
|
2023-08-30 03:03:43 +02:00
|
|
|
// limit to whole packets
|
2023-09-01 17:34:05 +02:00
|
|
|
int64_t cspace_pkgs = (cspace_bytes / MAXIMUM_SEGMENT_DATA_SIZE) * MAXIMUM_SEGMENT_DATA_SIZE;
|
2023-08-24 18:04:25 +02:00
|
|
|
|
2024-05-27 20:51:42 +02:00
|
|
|
_bytes_leftover = cspace_bytes - cspace_pkgs;
|
|
|
|
|
2023-08-30 13:45:09 +02:00
|
|
|
return std::min(cspace_pkgs, fspace_pkgs);
|
2023-08-24 18:04:25 +02:00
|
|
|
}
|
|
|
|
|