Skip to content

Commit

Permalink
hard code pacer multiplier to 2x, moving the logic of selecting the m…
Browse files Browse the repository at this point in the history
…ultiplier into core
  • Loading branch information
kazuho committed Mar 5, 2024
1 parent f5ac5bc commit 4e9b822
Show file tree
Hide file tree
Showing 7 changed files with 16 additions and 22 deletions.
5 changes: 1 addition & 4 deletions include/quicly/cc.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ extern "C" {

#define QUICLY_MIN_CWND 2
#define QUICLY_RENO_BETA 0.7
#define QUICLY_PACER_MULTIPLIER 2

/**
* Holds pointers to concrete congestion control implementation functions.
Expand All @@ -61,10 +62,6 @@ typedef struct st_quicly_cc_t {
* Packet number indicating end of recovery period, if in recovery.
*/
uint64_t recovery_end;
/**
* multiplier to be applied for pacing, in 1/16 (e.g., 32 to send at twice CWND/RTT)
*/
uint32_t pacer_multiplier;
/**
* If the most recent loss episode was signalled by ECN only (i.e., no packet loss).
*/
Expand Down
5 changes: 1 addition & 4 deletions include/quicly/pacer.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,6 @@ typedef struct st_quicly_pacer_t {
} quicly_pacer_t;

#define QUICLY_PACER_CALC_BURST_BYTES(mtu) ((size_t)(mtu)*9 + 1)
#define QUICLY_PACER_SEND_RATE_MULTIPLIER 16
#define QUICLY_PACER_CALC_MULTIPLIER(x) ((uint32_t)((x)*QUICLY_PACER_SEND_RATE_MULTIPLIER + 0.99)) /* round-up */

/**
* resets the pacer
Expand All @@ -74,7 +72,6 @@ static uint64_t quicly_pacer_get_window(quicly_pacer_t *pacer, int64_t now, uint
static void quicly_pacer_consume_window(quicly_pacer_t *pacer, size_t delta);
/**
* Calculates the flow rate as `bytes_per_msec`. The returned value is no less than 1.
* @param multiplier multiplier applied to `cwnd / rtt` in permil
*/
static uint32_t quicly_pacer_calc_send_rate(uint32_t multiplier, uint32_t cwnd, uint32_t rtt);

Expand Down Expand Up @@ -139,7 +136,7 @@ inline void quicly_pacer_consume_window(quicly_pacer_t *pacer, size_t delta)

inline uint32_t quicly_pacer_calc_send_rate(uint32_t multiplier, uint32_t cwnd, uint32_t rtt)
{
return ((cwnd + QUICLY_PACER_SEND_RATE_MULTIPLIER - 1) / QUICLY_PACER_SEND_RATE_MULTIPLIER * multiplier + rtt - 1) / rtt;
return (cwnd * multiplier + rtt - 1) / rtt;
}

#ifdef __cplusplus
Expand Down
2 changes: 0 additions & 2 deletions lib/cc-cubic.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ static void cubic_on_acked(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t
}

/* Congestion avoidance. */
cc->pacer_multiplier = QUICLY_PACER_CALC_MULTIPLIER(1.2);
cubic_float_t t_sec = calc_cubic_t(cc, now);
cubic_float_t rtt_sec = loss->rtt.smoothed / (cubic_float_t)1000; /* ms -> s */

Expand Down Expand Up @@ -169,7 +168,6 @@ static void cubic_reset(quicly_cc_t *cc, uint32_t initcwnd)
cc->type = &quicly_cc_type_cubic;
cc->cwnd = cc->cwnd_initial = cc->cwnd_maximum = initcwnd;
cc->ssthresh = cc->cwnd_minimum = UINT32_MAX;
cc->pacer_multiplier = QUICLY_PACER_CALC_MULTIPLIER(2);
}

static int cubic_on_switch(quicly_cc_t *cc)
Expand Down
4 changes: 0 additions & 4 deletions lib/cc-pico.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,6 @@ static void pico_on_lost(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t by
return;
cc->recovery_end = next_pn;

/* switch pacer to congestion avoidance mode the moment loss is observed */
cc->pacer_multiplier = QUICLY_PACER_CALC_MULTIPLIER(1.2);

++cc->num_loss_episodes;
if (cc->cwnd_exiting_slow_start == 0)
cc->cwnd_exiting_slow_start = cc->cwnd;
Expand Down Expand Up @@ -149,7 +146,6 @@ static void pico_reset(quicly_cc_t *cc, uint32_t initcwnd)
.cwnd_maximum = initcwnd,
.cwnd_minimum = UINT32_MAX,
.ssthresh = UINT32_MAX,
.pacer_multiplier = QUICLY_PACER_CALC_MULTIPLIER(2),
};
pico_init_pico_state(cc, 0);
}
Expand Down
2 changes: 0 additions & 2 deletions lib/cc-reno.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ static void reno_on_acked(quicly_cc_t *cc, const quicly_loss_t *loss, uint32_t b
return;
}
/* Congestion avoidance. */
cc->pacer_multiplier = QUICLY_PACER_CALC_MULTIPLIER(1.2);
if (!cc_limited)
return;
cc->state.reno.stash += bytes;
Expand Down Expand Up @@ -96,7 +95,6 @@ static void reno_reset(quicly_cc_t *cc, uint32_t initcwnd)
cc->type = &quicly_cc_type_reno;
cc->cwnd = cc->cwnd_initial = cc->cwnd_maximum = initcwnd;
cc->ssthresh = cc->cwnd_minimum = UINT32_MAX;
cc->pacer_multiplier = QUICLY_PACER_CALC_MULTIPLIER(2);
}

static int reno_on_switch(quicly_cc_t *cc)
Expand Down
8 changes: 7 additions & 1 deletion lib/quicly.c
Original file line number Diff line number Diff line change
Expand Up @@ -3036,7 +3036,13 @@ static int on_ack_retire_connection_id(quicly_sentmap_t *map, const quicly_sent_

static uint32_t calc_pacer_send_rate(quicly_conn_t *conn)
{
return quicly_pacer_calc_send_rate(conn->egress.cc.pacer_multiplier, conn->egress.cc.cwnd, conn->egress.loss.rtt.smoothed);
/* The multiplier uses a hard-coded value of 2x in both the slow start and the congestion avoidance phases. This differs from
* Linux, which uses 1.25x for the latter. The rationale behind this choice is that 1.25x is not sufficiently aggressive
* immediately after a loss event. Following a loss event, the congestion window (CWND) is halved (i.e., beta), but the Smoothed
* Round Trip Time (SRTT) can remain high for a couple of round-trips since it is a moving average adjusted with each ACK
* received. Consequently, if the multiplier is set to 1.25x, the calculated send rate could drop to as low as 1.25 * 1/2 =
* 0.625. By using a 2x multiplier, the send rate is guaranteed to be no less than 1x. */
return quicly_pacer_calc_send_rate(2, conn->egress.cc.cwnd, conn->egress.loss.rtt.smoothed);
}

static int should_send_datagram_frame(quicly_conn_t *conn)
Expand Down
12 changes: 7 additions & 5 deletions t/pacer.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,22 @@
#include "quicly/pacer.h"
#include "test.h"

static const uint32_t multiplier = QUICLY_PACER_CALC_MULTIPLIER(2);

static void test_calc_rate(void)
{
uint64_t bytes_per_msec;

bytes_per_msec = quicly_pacer_calc_send_rate(multiplier, 50 * 1200, 10);
bytes_per_msec = quicly_pacer_calc_send_rate(2, 50 * 1200, 10);
ok(bytes_per_msec == 12000); /* send 60KB packets in 5ms */

bytes_per_msec = quicly_pacer_calc_send_rate(multiplier, 100 * 1200, 10);
bytes_per_msec = quicly_pacer_calc_send_rate(2, 100 * 1200, 10);
ok(bytes_per_msec == 24000); /* 2x CWND, 2x flow rate */

bytes_per_msec = quicly_pacer_calc_send_rate(multiplier, 50 * 1200, 100);
bytes_per_msec = quicly_pacer_calc_send_rate(2, 50 * 1200, 100);
ok(bytes_per_msec == 1200); /* 10x RTT, 1/10 flow rate */

/* half the rate as above, due to multiplier being 1x */
bytes_per_msec = quicly_pacer_calc_send_rate(1, 50 * 1200, 100);
ok(bytes_per_msec == 600);
}

static const uint16_t mtu = 1200;
Expand Down

0 comments on commit 4e9b822

Please sign in to comment.