lsquic_pacer.c revision 229fce07
1229fce07SDmitri Tikhonov/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */ 250aadb33SDmitri Tikhonov#include <assert.h> 350aadb33SDmitri Tikhonov#include <inttypes.h> 450aadb33SDmitri Tikhonov#include <stdint.h> 550aadb33SDmitri Tikhonov#ifndef NDEBUG 650aadb33SDmitri Tikhonov#include <stdlib.h> /* getenv */ 750aadb33SDmitri Tikhonov#endif 850aadb33SDmitri Tikhonov#include <string.h> 9461e84d8SAmol Deshpande#ifdef WIN32 10461e84d8SAmol Deshpande#include <vc_compat.h> 11461e84d8SAmol Deshpande#endif 1250aadb33SDmitri Tikhonov 1350aadb33SDmitri Tikhonov#include "lsquic_types.h" 1450aadb33SDmitri Tikhonov#include "lsquic_int_types.h" 1550aadb33SDmitri Tikhonov#include "lsquic_pacer.h" 1650aadb33SDmitri Tikhonov#include "lsquic_packet_common.h" 1750aadb33SDmitri Tikhonov#include "lsquic_packet_out.h" 1850aadb33SDmitri Tikhonov#include "lsquic_util.h" 1950aadb33SDmitri Tikhonov 2050aadb33SDmitri Tikhonov#define LSQUIC_LOGGER_MODULE LSQLM_PACER 2150aadb33SDmitri Tikhonov#define LSQUIC_LOG_CONN_ID pacer->pa_cid 2250aadb33SDmitri Tikhonov#include "lsquic_logger.h" 2350aadb33SDmitri Tikhonov 2450aadb33SDmitri Tikhonov#ifndef MAX 2550aadb33SDmitri Tikhonov# define MAX(a, b) ((a) > (b) ? (a) : (b)) 2650aadb33SDmitri Tikhonov#endif 2750aadb33SDmitri Tikhonov 2850aadb33SDmitri Tikhonov 2950aadb33SDmitri Tikhonovvoid 3050aadb33SDmitri Tikhonovpacer_init (struct pacer *pacer, lsquic_cid_t cid, unsigned max_intertick) 3150aadb33SDmitri Tikhonov{ 3250aadb33SDmitri Tikhonov memset(pacer, 0, sizeof(*pacer)); 3350aadb33SDmitri Tikhonov pacer->pa_burst_tokens = 10; 3450aadb33SDmitri Tikhonov pacer->pa_cid = cid; 3550aadb33SDmitri Tikhonov pacer->pa_max_intertick = max_intertick; 3650aadb33SDmitri Tikhonov#ifndef NDEBUG 3750aadb33SDmitri Tikhonov const char *val; 3850aadb33SDmitri Tikhonov if ((val = getenv("LSQUIC_PACER_INTERTICK"))) 3950aadb33SDmitri Tikhonov { 4050aadb33SDmitri Tikhonov pacer->pa_flags |= PA_CONSTANT_INTERTICK; 4150aadb33SDmitri Tikhonov pacer->pa_intertick_avg = atoi(val); 4250aadb33SDmitri Tikhonov } 4350aadb33SDmitri Tikhonov#endif 4450aadb33SDmitri Tikhonov} 4550aadb33SDmitri Tikhonov 4650aadb33SDmitri Tikhonov 4750aadb33SDmitri Tikhonovvoid 48bfc7bfd8SDmitri Tikhonovpacer_cleanup (struct pacer *pacer) 49bfc7bfd8SDmitri Tikhonov{ 50bfc7bfd8SDmitri Tikhonov#ifndef NDEBUG 51bfc7bfd8SDmitri Tikhonov LSQ_NOTICE("scheduled calls: %u", pacer->pa_stats.n_scheduled); 52bfc7bfd8SDmitri Tikhonov#endif 53bfc7bfd8SDmitri Tikhonov} 54bfc7bfd8SDmitri Tikhonov 55bfc7bfd8SDmitri Tikhonov 56bfc7bfd8SDmitri Tikhonovvoid 5750aadb33SDmitri Tikhonovpacer_packet_scheduled (struct pacer *pacer, unsigned n_in_flight, 5850aadb33SDmitri Tikhonov int in_recovery, tx_time_f tx_time, void *tx_ctx) 5950aadb33SDmitri Tikhonov{ 6050aadb33SDmitri Tikhonov lsquic_time_t delay, sched_time; 6150aadb33SDmitri Tikhonov int app_limited, making_up; 6250aadb33SDmitri Tikhonov 63bfc7bfd8SDmitri Tikhonov#ifndef NDEBUG 64bfc7bfd8SDmitri Tikhonov ++pacer->pa_stats.n_scheduled; 65bfc7bfd8SDmitri Tikhonov#endif 66bfc7bfd8SDmitri Tikhonov 6750aadb33SDmitri Tikhonov if (n_in_flight == 0 && !in_recovery) 6850aadb33SDmitri Tikhonov { 6950aadb33SDmitri Tikhonov pacer->pa_burst_tokens = 10; 7050aadb33SDmitri Tikhonov LSQ_DEBUG("%s: replenish tokens: %u", __func__, pacer->pa_burst_tokens); 7150aadb33SDmitri Tikhonov } 7250aadb33SDmitri Tikhonov 7350aadb33SDmitri Tikhonov if (pacer->pa_burst_tokens > 0) 7450aadb33SDmitri Tikhonov { 7550aadb33SDmitri Tikhonov --pacer->pa_burst_tokens; 7650aadb33SDmitri Tikhonov pacer->pa_flags &= ~PA_LAST_SCHED_DELAYED; 7750aadb33SDmitri Tikhonov pacer->pa_next_sched = 0; 7850aadb33SDmitri Tikhonov pacer->pa_last_delayed = 0; 7950aadb33SDmitri Tikhonov LSQ_DEBUG("%s: tokens: %u", __func__, pacer->pa_burst_tokens); 8050aadb33SDmitri Tikhonov return; 8150aadb33SDmitri Tikhonov } 8250aadb33SDmitri Tikhonov 8350aadb33SDmitri Tikhonov sched_time = pacer->pa_now; 8450aadb33SDmitri Tikhonov delay = tx_time(tx_ctx); 8550aadb33SDmitri Tikhonov if (pacer->pa_flags & PA_LAST_SCHED_DELAYED) 8650aadb33SDmitri Tikhonov { 8750aadb33SDmitri Tikhonov pacer->pa_next_sched += delay; 8850aadb33SDmitri Tikhonov app_limited = pacer->pa_last_delayed != 0 8950aadb33SDmitri Tikhonov && pacer->pa_last_delayed + delay <= sched_time; 9050aadb33SDmitri Tikhonov making_up = pacer->pa_next_sched <= sched_time; 9150aadb33SDmitri Tikhonov LSQ_DEBUG("making up: %d; app limited; %d", making_up, app_limited); 9250aadb33SDmitri Tikhonov if (making_up && !app_limited) 9350aadb33SDmitri Tikhonov pacer->pa_last_delayed = sched_time; 9450aadb33SDmitri Tikhonov else 9550aadb33SDmitri Tikhonov { 9650aadb33SDmitri Tikhonov pacer->pa_flags &= ~PA_LAST_SCHED_DELAYED; 9750aadb33SDmitri Tikhonov pacer->pa_last_delayed = 0; 9850aadb33SDmitri Tikhonov } 9950aadb33SDmitri Tikhonov } 10050aadb33SDmitri Tikhonov else 10150aadb33SDmitri Tikhonov pacer->pa_next_sched = MAX(pacer->pa_next_sched + delay, 10250aadb33SDmitri Tikhonov sched_time + delay); 10350aadb33SDmitri Tikhonov LSQ_DEBUG("next_sched is set to %"PRIu64" usec from now", 10450aadb33SDmitri Tikhonov pacer->pa_next_sched - lsquic_time_now()); 10550aadb33SDmitri Tikhonov} 10650aadb33SDmitri Tikhonov 10750aadb33SDmitri Tikhonov 10850aadb33SDmitri Tikhonovvoid 10950aadb33SDmitri Tikhonovpacer_loss_event (struct pacer *pacer) 11050aadb33SDmitri Tikhonov{ 11150aadb33SDmitri Tikhonov pacer->pa_burst_tokens = 0; 11250aadb33SDmitri Tikhonov LSQ_DEBUG("%s: tokens: %u", __func__, pacer->pa_burst_tokens); 11350aadb33SDmitri Tikhonov} 11450aadb33SDmitri Tikhonov 11550aadb33SDmitri Tikhonov 11650aadb33SDmitri Tikhonovstatic unsigned 11750aadb33SDmitri Tikhonovclock_granularity (const struct pacer *pacer) 11850aadb33SDmitri Tikhonov{ 119bfc7bfd8SDmitri Tikhonov return pacer->pa_intertick_avg; 12050aadb33SDmitri Tikhonov} 12150aadb33SDmitri Tikhonov 12250aadb33SDmitri Tikhonov 12350aadb33SDmitri Tikhonovint 12450aadb33SDmitri Tikhonovpacer_can_schedule (struct pacer *pacer, unsigned n_in_flight) 12550aadb33SDmitri Tikhonov{ 12650aadb33SDmitri Tikhonov int can; 12750aadb33SDmitri Tikhonov 12850aadb33SDmitri Tikhonov if (pacer->pa_burst_tokens > 0 || n_in_flight == 0) 12950aadb33SDmitri Tikhonov can = 1; 13050aadb33SDmitri Tikhonov else if (pacer->pa_next_sched > pacer->pa_now + clock_granularity(pacer)) 13150aadb33SDmitri Tikhonov { 13250aadb33SDmitri Tikhonov pacer->pa_flags |= PA_LAST_SCHED_DELAYED; 13350aadb33SDmitri Tikhonov can = 0; 13450aadb33SDmitri Tikhonov } 13550aadb33SDmitri Tikhonov else 13650aadb33SDmitri Tikhonov can = 1; 13750aadb33SDmitri Tikhonov 13850aadb33SDmitri Tikhonov LSQ_DEBUG("%s: %d", __func__, can); 13950aadb33SDmitri Tikhonov return can; 14050aadb33SDmitri Tikhonov} 14150aadb33SDmitri Tikhonov 14250aadb33SDmitri Tikhonov 14350aadb33SDmitri Tikhonov#define ALPHA_SHIFT 3 14450aadb33SDmitri Tikhonov#define BETA_SHIFT 2 14550aadb33SDmitri Tikhonov 14650aadb33SDmitri Tikhonovstatic void 14750aadb33SDmitri Tikhonovupdate_avg_intertick (struct pacer *pacer, unsigned intertick) 14850aadb33SDmitri Tikhonov{ 14950aadb33SDmitri Tikhonov unsigned diff; 15050aadb33SDmitri Tikhonov 15150aadb33SDmitri Tikhonov#ifndef NDEBUG 15250aadb33SDmitri Tikhonov if (pacer->pa_flags & PA_CONSTANT_INTERTICK) 15350aadb33SDmitri Tikhonov return; 15450aadb33SDmitri Tikhonov#endif 15550aadb33SDmitri Tikhonov 15650aadb33SDmitri Tikhonov if (pacer->pa_intertick_avg) 15750aadb33SDmitri Tikhonov { 15850aadb33SDmitri Tikhonov if (intertick > pacer->pa_intertick_avg) 15950aadb33SDmitri Tikhonov diff = intertick - pacer->pa_intertick_avg; 16050aadb33SDmitri Tikhonov else 16150aadb33SDmitri Tikhonov diff = pacer->pa_intertick_avg - intertick; 16250aadb33SDmitri Tikhonov pacer->pa_intertick_var -= pacer->pa_intertick_var >> BETA_SHIFT; 16350aadb33SDmitri Tikhonov pacer->pa_intertick_var += diff >> BETA_SHIFT; 16450aadb33SDmitri Tikhonov pacer->pa_intertick_avg -= pacer->pa_intertick_avg >> ALPHA_SHIFT; 16550aadb33SDmitri Tikhonov pacer->pa_intertick_avg += intertick >> ALPHA_SHIFT; 16650aadb33SDmitri Tikhonov } 16750aadb33SDmitri Tikhonov else 16850aadb33SDmitri Tikhonov { 16950aadb33SDmitri Tikhonov pacer->pa_intertick_avg = intertick; 17050aadb33SDmitri Tikhonov pacer->pa_intertick_var = intertick >> 1; 17150aadb33SDmitri Tikhonov } 17250aadb33SDmitri Tikhonov} 17350aadb33SDmitri Tikhonov 17450aadb33SDmitri Tikhonov 17550aadb33SDmitri Tikhonovvoid 17650aadb33SDmitri Tikhonovpacer_tick (struct pacer *pacer, lsquic_time_t now) 17750aadb33SDmitri Tikhonov{ 17850aadb33SDmitri Tikhonov unsigned intertick; 17950aadb33SDmitri Tikhonov 180bdba46fdSDmitri Tikhonov assert(now >= pacer->pa_now); 18150aadb33SDmitri Tikhonov if (pacer->pa_now) 18250aadb33SDmitri Tikhonov { 18350aadb33SDmitri Tikhonov assert(now - pacer->pa_now < (1ULL << sizeof(unsigned) * 8)); 18450aadb33SDmitri Tikhonov intertick = now - pacer->pa_now; 18550aadb33SDmitri Tikhonov LSQ_DEBUG("intertick estimate: %u; real value: %u; error: %d", 18650aadb33SDmitri Tikhonov clock_granularity(pacer), intertick, 18750aadb33SDmitri Tikhonov (int) clock_granularity(pacer) - (int) intertick); 18850aadb33SDmitri Tikhonov update_avg_intertick(pacer, intertick); 18950aadb33SDmitri Tikhonov } 19050aadb33SDmitri Tikhonov pacer->pa_now = now; 19150aadb33SDmitri Tikhonov} 192