mirror of
https://github.com/irungentoo/toxcore.git
synced 2024-03-22 13:30:51 +08:00
New congestion control algorithm.
This new congestion control algorithm uses the increase in size of the send queue to regulate how fast it sends data. When tweaked it should work better than the old one.
This commit is contained in:
parent
bb1bb58352
commit
162a900660
|
@ -2300,95 +2300,42 @@ static void send_crypto_packets(Net_Crypto *c)
|
||||||
conn->packet_counter = 0;
|
conn->packet_counter = 0;
|
||||||
conn->packet_counter_set = temp_time;
|
conn->packet_counter_set = temp_time;
|
||||||
|
|
||||||
|
double real_send_rate = (double)(conn->packets_sent + conn->packets_resent) / (dt / 1000.0);
|
||||||
|
uint32_t packets_sent = conn->packets_sent;
|
||||||
|
conn->packets_sent = conn->packets_resent = 0;
|
||||||
|
|
||||||
/* conjestion control
|
/* conjestion control
|
||||||
calculate a new value of conn->packet_send_rate based on some data
|
calculate a new value of conn->packet_send_rate based on some data
|
||||||
notes: needs improvement but seems to work fine for packet loss <1%
|
notes: needs improvement but seems to work fine for packet loss <1%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* additional step: adjust the send rate based on the size change of the send queue */
|
unsigned int pos = conn->last_sendqueue_counter % CONGESTION_QUEUE_ARRAY_SIZE;
|
||||||
uint32_t queue_size = num_packets_array(&conn->send_array);
|
conn->last_sendqueue_size[pos] = num_packets_array(&conn->send_array);
|
||||||
|
++conn->last_sendqueue_counter;
|
||||||
|
|
||||||
if (queue_size > conn->packet_send_rate && queue_size > conn->last_queue_size) {
|
unsigned int j;
|
||||||
conn->rate_increase = 0;
|
long signed int sum = 0;
|
||||||
conn->packets_resent = conn->packets_sent;
|
sum = (long signed int)conn->last_sendqueue_size[(pos) % CONGESTION_QUEUE_ARRAY_SIZE] -
|
||||||
|
(long signed int)conn->last_sendqueue_size[(pos - (CONGESTION_QUEUE_ARRAY_SIZE - 1)) % CONGESTION_QUEUE_ARRAY_SIZE];
|
||||||
|
|
||||||
|
conn->last_num_packets_sent[pos] = packets_sent;
|
||||||
|
long signed int total_sent = 0;
|
||||||
|
|
||||||
|
for (j = 0; j < CONGESTION_QUEUE_ARRAY_SIZE; ++j) {
|
||||||
|
total_sent += conn->last_num_packets_sent[j];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
total_sent -= sum;
|
||||||
|
|
||||||
//hack to prevent 1 packet lost from affecting calculations at low send rates
|
double min_speed = 1000.0 * (((double)(total_sent)) / ((double)(CONGESTION_QUEUE_ARRAY_SIZE) *
|
||||||
if (conn->packets_resent == 1) {
|
PACKET_COUNTER_AVERAGE_INTERVAL));
|
||||||
conn->packets_resent = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//new "dropped" value: weighted average of previous value and packet drop rate measured by the number of packets which were resends of previous packets
|
conn->packet_send_rate = min_speed * 1.3;
|
||||||
double dropped = (conn->dropped) * 0.30 + ((double)conn->packets_resent / dt) * 0.70;
|
|
||||||
|
|
||||||
//since the "dropped" packets measure is delayed in time from the actual # of dropped packets,
|
|
||||||
// ignore dropped packet measure for 2 seconds after it becomes high and the send rate is lowered as a result
|
|
||||||
double drop_ignore_new;
|
|
||||||
|
|
||||||
if (conn->drop_ignore_start + 2000 < temp_time) {
|
|
||||||
drop_ignore_new = 0.0;
|
|
||||||
|
|
||||||
if ((dropped * 1000.0) / conn->packet_send_rate >= 0.10) {
|
|
||||||
conn->drop_ignore_start = temp_time;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
drop_ignore_new = (dropped > conn->drop_ignore) ? dropped : conn->drop_ignore;
|
|
||||||
}
|
|
||||||
|
|
||||||
//calculate the "real" send rate (send rate - drop rate)
|
|
||||||
double r = conn->packet_send_rate;
|
|
||||||
double realrate = (r - (dropped - drop_ignore_new) * 1000.0);
|
|
||||||
|
|
||||||
if (dropped < drop_ignore_new) {
|
|
||||||
realrate = r;
|
|
||||||
}
|
|
||||||
|
|
||||||
//calculate exponential increase in rate, triggered when drop rate is below 5% for 5 seconds
|
|
||||||
if ((dropped * 1000.0) / conn->packet_send_rate >= 0.05) {
|
|
||||||
conn->rate_increase_stop_start = temp_time;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (conn->rate_increase_stop_start + 5000 < temp_time) {
|
|
||||||
if (conn->rate_increase < 1.0) {
|
|
||||||
conn->rate_increase = 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
conn->rate_increase *= pow(1.1, pow(realrate / r, 10.0));;
|
|
||||||
} else {
|
|
||||||
conn->rate_increase = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//"constant" linear increase in rate
|
|
||||||
double linear_increase = realrate * 0.0025 + 1.0;
|
|
||||||
|
|
||||||
//final send rate: average of "real" and previous send rates + increases
|
|
||||||
double newrate = (realrate + conn->packet_send_rate) / 2.0 + conn->rate_increase + linear_increase;
|
|
||||||
conn->last_send_rate = conn->packet_send_rate;
|
|
||||||
conn->packet_send_rate = newrate;
|
|
||||||
|
|
||||||
|
|
||||||
conn->dropped = dropped;
|
|
||||||
conn->drop_ignore = drop_ignore_new;
|
|
||||||
conn->packets_resent = 0;
|
|
||||||
conn->last_queue_size = queue_size;
|
|
||||||
|
|
||||||
if (!conn->sending || !conn->packets_sent) {
|
|
||||||
conn->rate_increase = 0;
|
|
||||||
conn->packet_send_rate /= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (conn->packet_send_rate < CRYPTO_PACKET_MIN_RATE) {
|
if (conn->packet_send_rate < CRYPTO_PACKET_MIN_RATE) {
|
||||||
conn->packet_send_rate = CRYPTO_PACKET_MIN_RATE;
|
conn->packet_send_rate = CRYPTO_PACKET_MIN_RATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
conn->packets_sent = 0;
|
|
||||||
|
|
||||||
if (conn->sending != 0 && num_packets_array(&conn->send_array) < CRYPTO_MIN_QUEUE_LENGTH / 2) {
|
|
||||||
--conn->sending;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conn->last_packets_left_set == 0) {
|
if (conn->last_packets_left_set == 0) {
|
||||||
|
@ -2409,13 +2356,8 @@ static void send_crypto_packets(Net_Crypto *c)
|
||||||
int ret = send_requested_packets(c, i, conn->packets_left);
|
int ret = send_requested_packets(c, i, conn->packets_left);
|
||||||
|
|
||||||
if (ret != -1) {
|
if (ret != -1) {
|
||||||
if (ret != 0) {
|
|
||||||
conn->sending = CONN_SENDING_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
conn->packets_resent += ret;
|
|
||||||
conn->packets_left -= ret;
|
conn->packets_left -= ret;
|
||||||
conn->packets_sent += ret;
|
conn->packets_resent += ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conn->packet_send_rate > CRYPTO_PACKET_MIN_RATE * 1.5) {
|
if (conn->packet_send_rate > CRYPTO_PACKET_MIN_RATE * 1.5) {
|
||||||
|
@ -2496,7 +2438,6 @@ int64_t write_cryptpacket(const Net_Crypto *c, int crypt_connection_id, const ui
|
||||||
|
|
||||||
--conn->packets_left;
|
--conn->packets_left;
|
||||||
conn->packets_sent++;
|
conn->packets_sent++;
|
||||||
conn->sending = CONN_SENDING_VALUE;
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,6 +79,9 @@
|
||||||
|
|
||||||
#define CRYPTO_MAX_PADDING 8 /* All packets will be padded a number of bytes based on this number. */
|
#define CRYPTO_MAX_PADDING 8 /* All packets will be padded a number of bytes based on this number. */
|
||||||
|
|
||||||
|
|
||||||
|
#define CONGESTION_QUEUE_ARRAY_SIZE 8
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint64_t time;
|
uint64_t time;
|
||||||
uint16_t length;
|
uint16_t length;
|
||||||
|
@ -143,11 +146,9 @@ typedef struct {
|
||||||
uint32_t packets_left;
|
uint32_t packets_left;
|
||||||
uint64_t last_packets_left_set;
|
uint64_t last_packets_left_set;
|
||||||
|
|
||||||
double dropped, drop_ignore, rate_increase, last_send_rate;
|
uint32_t last_sendqueue_size[CONGESTION_QUEUE_ARRAY_SIZE], last_sendqueue_counter;
|
||||||
uint64_t drop_ignore_start, rate_increase_stop_start;
|
long signed int last_num_packets_sent[CONGESTION_QUEUE_ARRAY_SIZE];
|
||||||
uint32_t packets_resent, last_queue_size, packets_sent, last_packets_sent;
|
uint32_t packets_sent, packets_resent;
|
||||||
|
|
||||||
uint8_t sending; /* indicates if data is being sent or not. */
|
|
||||||
|
|
||||||
uint8_t killed; /* set to 1 to kill the connection. */
|
uint8_t killed; /* set to 1 to kill the connection. */
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user