Default value: cubic
It is possible to enable pacing if the algorithm is compatible. This is done
- by specifying an optional burst argument as described in the next paragraph.
+ by setting an optional integer argument as described in the next paragraph.
The purpose of pacing is to smooth emission of data to reduce network losses.
In most scenario, it can significantly improve network throughput by avoiding
retransmissions. Pacing support is still experimental, as such it requires
mandatory order of each parameters :
- maximum window size in bytes. It must be greater than 10k and smaller than
4g. By default "tune.quic.frontend.default-max-window-size" value is used.
- - burst size in datagrams. By default, it is set to 0, which means unlimited.
- A positive value up to 1024 can be specified to smooth emission using
- pacing. Lower values provide a smoother traffic (hence less losses) at the
- expense of a higher CPU usage, while higher values will reduce CPU usage
- and provide a slightly more bursty traffic. Note that a datagram is usually
- around 1252 bytes, and that a typical receive buffer is 208kB or 170
- datagrams, so in order to keep the traffic smooth, bursts should only
- represent a small fraction of this value (between a few units to a few tens
- at most). See above paragraph for more explanation. This parameter is
- ignored by BBR.
+ - pacing activation. By default, it is set to 0, which means pacing is not
+ used. To activate it, specify a positive value. Burst size will be
+ dynamically adjusted to adapt to the network conditions. This parameter is
+ ignored by BBR as pacing is automatically activated for this algorithm.
Example:
# newreno congestion control algorithm
quic-cc-algo newreno
# cubic congestion control algorithm with one megabytes as window
quic-cc-algo cubic(1m)
- # cubic with pacing on top of it, with burst limited to 12 datagrams
- quic-cc-algo cubic(,12)
+ # cubic with pacing activated on top of it
+ quic-cc-algo cubic(,1)
A special value "nocc" may be used to force a fixed congestion window always
set at the maximum size. It is reserved for debugging scenarios to remove any
{
const uint64_t task_now_ns = task_mono_time();
const uint64_t inter = pacer->cc->algo->pacing_inter(pacer->cc);
- uint64_t inc;
+ uint64_t inc, wakeup_delay;
uint credit_max;
if (task_now_ns > pacer->cur) {
/* Calculate number of packets which could have been emitted since last emission sequence. Result is rounded up. */
inc = (task_now_ns - pacer->cur + inter - 1) / inter;
- credit_max = pacer->cc->algo->pacing_burst(pacer->cc);
+ /* Credit must not exceed a maximal value to guarantee a
+ * smooth emission. This max value represents the number of
+ * packet based on congestion window and RTT which can be sent
+ * to cover the sleep until the next wakeup. This delay is
+ * roughly the max between the scheduler delay or 1ms.
+ */
+
+ /* Calculate wakeup_delay to determine max credit value. */
+ wakeup_delay = MAX(swrate_avg(activity[tid].avg_loop_us, TIME_STATS_SAMPLES), 1000);
+ /* Convert it to nanoseconds. Use 1.5 factor tolerance to try to cover the imponderable extra system delay until the next wakeup. */
+ wakeup_delay *= 1500;
+ /* Determine max credit from wakeup_delay and packet rate emission. */
+ credit_max = wakeup_delay / inter;
+ /* Ensure max credit will never be smaller than 2. */
+ credit_max = MAX(credit_max, 2);
+ /* Apply max credit on the new value. */
pacer->credit = MIN(pacer->credit + inc, credit_max);
/* Refresh pacing reload timer. */