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:
irungentoo 2014-08-16 18:14:47 -04:00
parent bb1bb58352
commit 162a900660
No known key found for this signature in database
GPG Key ID: 10349DC9BED89E98
2 changed files with 28 additions and 86 deletions

View File

@ -2300,95 +2300,42 @@ static void send_crypto_packets(Net_Crypto *c)
conn->packet_counter = 0;
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
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%
*/
/* additional step: adjust the send rate based on the size change of the send queue */
uint32_t queue_size = num_packets_array(&conn->send_array);
unsigned int pos = conn->last_sendqueue_counter % CONGESTION_QUEUE_ARRAY_SIZE;
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) {
conn->rate_increase = 0;
conn->packets_resent = conn->packets_sent;
unsigned int j;
long signed int sum = 0;
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
if (conn->packets_resent == 1) {
conn->packets_resent = 0;
}
double min_speed = 1000.0 * (((double)(total_sent)) / ((double)(CONGESTION_QUEUE_ARRAY_SIZE) *
PACKET_COUNTER_AVERAGE_INTERVAL));
//new "dropped" value: weighted average of previous value and packet drop rate measured by the number of packets which were resends of previous packets
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;
}
conn->packet_send_rate = min_speed * 1.3;
if (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) {
@ -2409,13 +2356,8 @@ static void send_crypto_packets(Net_Crypto *c)
int ret = send_requested_packets(c, i, conn->packets_left);
if (ret != -1) {
if (ret != 0) {
conn->sending = CONN_SENDING_VALUE;
}
conn->packets_resent += ret;
conn->packets_left -= ret;
conn->packets_sent += ret;
conn->packets_resent += ret;
}
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_sent++;
conn->sending = CONN_SENDING_VALUE;
return ret;
}

View File

@ -79,6 +79,9 @@
#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 {
uint64_t time;
uint16_t length;
@ -143,11 +146,9 @@ typedef struct {
uint32_t packets_left;
uint64_t last_packets_left_set;
double dropped, drop_ignore, rate_increase, last_send_rate;
uint64_t drop_ignore_start, rate_increase_stop_start;
uint32_t packets_resent, last_queue_size, packets_sent, last_packets_sent;
uint8_t sending; /* indicates if data is being sent or not. */
uint32_t last_sendqueue_size[CONGESTION_QUEUE_ARRAY_SIZE], last_sendqueue_counter;
long signed int last_num_packets_sent[CONGESTION_QUEUE_ARRAY_SIZE];
uint32_t packets_sent, packets_resent;
uint8_t killed; /* set to 1 to kill the connection. */