Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ SET(QUICLY_LIBRARY_FILES
lib/remote_cid.c
lib/retire_cid.c
lib/sendstate.c
lib/ss-rfc2001.c
lib/ss-hybla.c
lib/ss-hystart.c
lib/ss-search.c
lib/sentmap.c
lib/streambuf.c
${CMAKE_CURRENT_BINARY_DIR}/quicly-tracer.h)
Expand Down
5 changes: 5 additions & 0 deletions include/quicly.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ extern "C" {
#include "quicly/local_cid.h"
#include "quicly/linklist.h"
#include "quicly/loss.h"
#include "quicly/ss.h"
#include "quicly/cc.h"
#include "quicly/rate.h"
#include "quicly/recvstate.h"
Expand Down Expand Up @@ -392,6 +393,10 @@ struct st_quicly_context_t {
* initializes a congestion controller for given connection.
*/
quicly_init_cc_t *init_cc;
/**
* set the slowstart function for the connection
*/
quicly_ss_type_t *cc_slowstart;
/**
* optional refcount callback
*/
Expand Down
49 changes: 49 additions & 0 deletions include/quicly/cc.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ extern "C" {
#define QUICLY_MIN_CWND 2
#define QUICLY_RENO_BETA 0.7

#define SEARCH20_DELV_BIN_COUNT 10
Comment thread
parvit marked this conversation as resolved.
Outdated
#define SEARCH20_SENT_BIN_COUNT 25 // 10 + 15 extra bins
#define SEARCH20_WINDOW_MULTIPLIER (3.5)
#define SEARCH20_THRESH (0.35)

#define QUICLY_HYBLA_RTT0 (25)
Comment thread
parvit marked this conversation as resolved.
Outdated
#define QUICLY_HYBLA_RHO_LIM (16)

// #define SEARCH_EXIT

/**
* Holds pointers to concrete congestion control implementation functions.
*/
Expand All @@ -58,6 +68,41 @@ typedef struct st_quicly_cc_t {
* Current slow start threshold.
*/
uint32_t ssthresh;
/**
* Slow-start specific data storage
*/
union {
struct {
double rho;
} hybla;
struct {
uint8_t found;
Comment thread
parvit marked this conversation as resolved.
Outdated
int64_t round_start;
int64_t last_ack;
int64_t end_seq;
uint32_t min_round_rtt;
uint8_t samples;
} hystart;
struct {
/**
* Bins for the byte count sent and the byte count delivered (instantiated on init)
*/
uint64_t delv_bins[SEARCH20_SENT_BIN_COUNT];
/**
* Maintains the end time of the current bin
*/
int64_t bin_end;
/**
* Holds the size of each bin (based on the handshake RTT)
*/
uint32_t bin_time;
/**
* Counts the number of times that the bin has been incremented, so we know when to
* start trying to watch for congestion
*/
uint32_t bin_rounds;
} search;
} ss_state;
/**
* Packet number indicating end of recovery period, if in recovery.
*/
Expand Down Expand Up @@ -202,6 +247,10 @@ struct st_quicly_cc_type_t {
* Switches the underlying algorithm of `cc` to that of `cc_switch`, returning a boolean if the operation was successful.
*/
int (*cc_switch)(quicly_cc_t *cc);
/*
* Defines a variable slowstart callback
*/
struct st_quicly_variable_ss *cc_slowstart;
/**
*
*/
Expand Down
1 change: 1 addition & 0 deletions include/quicly/defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ extern quicly_crypto_engine_t quicly_default_crypto_engine;

#define quicly_default_cc quicly_cc_type_reno
#define quicly_default_init_cc quicly_cc_reno_init
#define quicly_default_ss quicly_ss_type_rfc2001

#ifdef __cplusplus
}
Expand Down
46 changes: 46 additions & 0 deletions include/quicly/ss.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#ifndef quicly_ss_h
#define quicly_ss_h

#ifdef __cplusplus
extern "C" {
#endif

#include "quicly/cc.h"
#include "quicly/constants.h"
#include <stdint.h>
#include <stdbool.h>

extern bool search_exit;

#define MIN(x,y) ((x > y) ? (y) : (x))
#define MAX(x,y) ((x < y) ? (y) : (x))
Comment thread
parvit marked this conversation as resolved.
Outdated

/**
* Holds pointers to concrete congestion control implementation functions.
*/
typedef const struct st_quicly_ss_type_t quicly_ss_type_t;

struct st_quicly_ss_type_t {
const char* name;
void (*ss)(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, uint64_t largest_acked, uint32_t inflight,
uint64_t next_pn, int64_t now, uint32_t max_udp_payload_size);
};

extern quicly_ss_type_t quicly_ss_type_rfc2001, quicly_ss_type_hybla, quicly_ss_type_hystart, quicly_ss_type_search;

extern quicly_ss_type_t* quicly_ss_all_types[];

void ss_rfc2001(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, uint64_t largest_acked, uint32_t inflight,
uint64_t next_pn, int64_t now, uint32_t max_udp_payload_size);

struct st_quicly_variable_ss {
Comment thread
parvit marked this conversation as resolved.
Outdated
quicly_ss_type_t* slowstart;
};

extern struct st_quicly_variable_ss active_slowstart;

#ifdef __cplusplus
}
#endif

#endif
14 changes: 8 additions & 6 deletions lib/cc-cubic.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@
*/
#include <math.h>
#include "quicly/cc.h"
#include "quicly/defaults.h"
#include "quicly.h"
#include "quicly/pacer.h"
#include "quicly/ss.h"

#define QUICLY_MIN_CWND 2

Expand Down Expand Up @@ -73,13 +75,11 @@ static void cubic_on_acked(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t

quicly_cc_jumpstart_on_acked(cc, 0, bytes, largest_acked, inflight, next_pn);

/* TODO: respect cc_limited */

/* Slow start. */
if (cc->cwnd < cc->ssthresh) {
cc->cwnd += bytes;
if (cc->cwnd_maximum < cc->cwnd)
cc->cwnd_maximum = cc->cwnd;
if (cc_limited) {
cc->type->cc_slowstart->slowstart->ss(cc, loss, bytes, largest_acked, inflight, next_pn, now, max_udp_payload_size);
}
return;
}

Expand Down Expand Up @@ -206,7 +206,9 @@ static void cubic_init(quicly_init_cc_t *self, quicly_cc_t *cc, uint32_t initcwn
cubic_reset(cc, initcwnd);
}

struct st_quicly_variable_ss cubic_active_slowstart = {&quicly_default_ss};

quicly_cc_type_t quicly_cc_type_cubic = {"cubic", &quicly_cc_cubic_init, cubic_on_acked,
cubic_on_lost, cubic_on_persistent_congestion, cubic_on_sent,
cubic_on_switch, quicly_cc_jumpstart_enter};
cubic_on_switch, &cubic_active_slowstart, quicly_cc_jumpstart_enter};
quicly_init_cc_t quicly_cc_cubic_init = {cubic_init};
3 changes: 2 additions & 1 deletion lib/cc-pico.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,5 +194,6 @@ static void pico_init(quicly_init_cc_t *self, quicly_cc_t *cc, uint32_t initcwnd

quicly_cc_type_t quicly_cc_type_pico = {"pico", &quicly_cc_pico_init, pico_on_acked,
pico_on_lost, pico_on_persistent_congestion, pico_on_sent,
pico_on_switch, quicly_cc_jumpstart_enter};
pico_on_switch, NULL /* no slow start exists for this CCA*/,
Comment thread
parvit marked this conversation as resolved.
Outdated
quicly_cc_jumpstart_enter};
quicly_init_cc_t quicly_cc_pico_init = {pico_init};
8 changes: 5 additions & 3 deletions lib/cc-reno.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
* IN THE SOFTWARE.
*/
#include "quicly/cc.h"
#include "quicly/defaults.h"
#include "quicly.h"

/* TODO: Avoid increase if sender was application limited. */
Expand All @@ -39,9 +40,7 @@ static void reno_on_acked(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t b
/* Slow start. */
if (cc->cwnd < cc->ssthresh) {
if (cc_limited) {
cc->cwnd += bytes;
if (cc->cwnd_maximum < cc->cwnd)
cc->cwnd_maximum = cc->cwnd;
cc->type->cc_slowstart->slowstart->ss(cc, loss, bytes, largest_acked, inflight, next_pn, now, max_udp_payload_size);
}
return;
}
Expand Down Expand Up @@ -136,13 +135,16 @@ static void reno_init(quicly_init_cc_t *self, quicly_cc_t *cc, uint32_t initcwnd
reno_reset(cc, initcwnd);
}

struct st_quicly_variable_ss reno_active_slowstart = {&quicly_default_ss};

quicly_cc_type_t quicly_cc_type_reno = {"reno",
&quicly_cc_reno_init,
reno_on_acked,
quicly_cc_reno_on_lost,
quicly_cc_reno_on_persistent_congestion,
quicly_cc_reno_on_sent,
reno_on_switch,
&reno_active_slowstart,
quicly_cc_jumpstart_enter};
quicly_init_cc_t quicly_cc_reno_init = {reno_init};

Expand Down
6 changes: 4 additions & 2 deletions lib/defaults.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ const quicly_context_t quicly_spec_context = {NULL,
NULL,
NULL,
&quicly_default_crypto_engine,
&quicly_default_init_cc};
&quicly_default_init_cc,
&quicly_default_ss};
Comment thread
parvit marked this conversation as resolved.

/* profile with a focus on reducing latency for the HTTP use case */
const quicly_context_t quicly_performant_context = {NULL, /* tls */
Expand Down Expand Up @@ -99,7 +100,8 @@ const quicly_context_t quicly_performant_context = {NULL,
NULL,
NULL,
&quicly_default_crypto_engine,
&quicly_default_init_cc};
&quicly_default_init_cc,
&quicly_default_ss};

/**
* The context of the default CID encryptor. All the contexts being used here are ECB ciphers and therefore stateless - they can be
Expand Down
4 changes: 4 additions & 0 deletions lib/quicly.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "quicly/sentmap.h"
#include "quicly/pacer.h"
#include "quicly/frame.h"
#include "quicly/ss.h"
#include "quicly/streambuf.h"
#include "quicly/cc.h"
#if QUICLY_USE_DTRACE
Expand Down Expand Up @@ -2259,6 +2260,9 @@ static quicly_conn_t *create_connection(quicly_context_t *ctx, uint32_t protocol
conn->egress.ack_frequency.update_at = INT64_MAX;
conn->egress.send_ack_at = INT64_MAX;
conn->super.ctx->init_cc->cb(conn->super.ctx->init_cc, &conn->egress.cc, initcwnd, conn->stash.now);
if (conn->egress.cc.type->cc_slowstart != NULL) {
Comment thread
parvit marked this conversation as resolved.
Outdated
conn->egress.cc.type->cc_slowstart->slowstart = conn->super.ctx->cc_slowstart;
}
if (pacer != NULL) {
conn->egress.pacer = pacer;
quicly_pacer_reset(conn->egress.pacer);
Expand Down
27 changes: 27 additions & 0 deletions lib/ss-hybla.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include "quicly/ss.h"
#include <stdint.h>
#include <math.h>

static void recalc_rho(quicly_cc_t *cc, const quicly_loss_t *loss) {
// RTT in msec
// Linux here uses us instead of ms for their rho calculations, which gives them more accurate information about
// the bandwidth of the connection. Here, we only have ms level measurements from loss, and so all of our
// measurements are only up to that level of precision. It cleans the code up a little bit though from the kernel.
// we have changed this to use doubles for more accuracy and ease of writing code.
double rho = (double) loss->rtt.minimum / QUICLY_HYBLA_RTT0;
// don't allow the ratio to be less than one for faster connections than reference.
cc->ss_state.hybla.rho = MAX(rho, 1);
}

void ss_hybla(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, uint64_t largest_acked, uint32_t inflight,
Comment thread
parvit marked this conversation as resolved.
Outdated
uint64_t next_pn, int64_t now, uint32_t max_udp_payload_size)
{
recalc_rho(cc, loss);

cc->cwnd += (uint32_t)round(pow(2, MIN(cc->ss_state.hybla.rho, QUICLY_HYBLA_RHO_LIM)));

if (cc->cwnd_maximum < cc->cwnd)
cc->cwnd_maximum = cc->cwnd;
}

quicly_ss_type_t quicly_ss_type_hybla = { "hybla", ss_hybla };
72 changes: 72 additions & 0 deletions lib/ss-hystart.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#include "quicly/ss.h"
#include <stdint.h>

#define QUICLY_HYSTART_MIN_SAMPLES (8)
#define QUICLY_HYSTART_MIN_SSTHRESH (16)
#define QUICLY_HYSTART_ACK_DELTA_MS (2)
#define QUICLY_HYSTART_DELAY_MIN (4)
#define QUICLY_HYSTART_DELAY_MAX (16)
#define QUICLY_HYSTART_LOW_WINDOW (16)


static void ss_hystart_reset(quicly_cc_t *cc, int64_t now, uint64_t next_pn) {
cc->ss_state.hystart.round_start = cc->ss_state.hystart.last_ack = now; // we only have ms resolution
cc->ss_state.hystart.end_seq = next_pn; // next packet we will send
cc->ss_state.hystart.min_round_rtt = ~0U; // max uint32_t
cc->ss_state.hystart.samples = 0;
}

// This code is heavily based on Linux's CUBIC/HyStart implementation with several functional differences to make it
// work with the constraints we've been given by Quicly.
Comment thread
parvit marked this conversation as resolved.
Outdated
void ss_hystart(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t bytes, uint64_t largest_acked, uint32_t inflight,
uint64_t next_pn, int64_t now, uint32_t max_udp_payload_size)
{
// RTT available at loss->rtt.latest
// dMin (min observed RTT) available at loss->rtt.minimum
// this isn't exactly sequence number comparison, but it also ain't exactly NOT sequence number comparison...
if (largest_acked > cc->ss_state.hystart.end_seq) {
ss_hystart_reset(cc, now, next_pn);
}


// check for ACK train
// Linux does this in usec, but we aren't so lucky
if (now - cc->ss_state.hystart.last_ack <= QUICLY_HYSTART_ACK_DELTA_MS) {
cc->ss_state.hystart.last_ack = now;

// Kernel defines threshold as `ca->delay_min + hystart_ack_delay(sk);`
// hystart_ack_delay(sk) maxes at 1ms if there is packet spacing happening
// but we don't have usec so i dont know how much it matters
uint32_t threshold = loss->rtt.minimum >> 1;

if (now - cc->ss_state.hystart.round_start > threshold) {
cc->ss_state.hystart.found = 1;
cc->ssthresh = cc->cwnd;
}
}

// HyStart Delay exit point
if (cc->ss_state.hystart.min_round_rtt > loss->rtt.latest) {
cc->ss_state.hystart.min_round_rtt = loss->rtt.latest;
}
if (cc->ss_state.hystart.samples < QUICLY_HYSTART_MIN_SAMPLES) {
cc->ss_state.hystart.samples += 1;
}
else {
uint32_t threshold = loss->rtt.minimum + MIN(QUICLY_HYSTART_DELAY_MAX, MAX(QUICLY_HYSTART_DELAY_MIN, loss->rtt.minimum >> 3));

if (cc->ss_state.hystart.min_round_rtt > threshold) {
cc->ss_state.hystart.found = 1;
cc->ssthresh = cc->cwnd;
}
}

if (cc->ss_state.hystart.found == 0) {
cc->cwnd += bytes;
if (cc->cwnd_maximum < cc->cwnd)
cc->cwnd_maximum = cc->cwnd;
}
}

quicly_ss_type_t quicly_ss_type_hystart = { "hystart", ss_hystart };

Loading