1a74702c6SGeorge Wang/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */ 250aadb33SDmitri Tikhonov#include <assert.h> 350aadb33SDmitri Tikhonov#include <inttypes.h> 450aadb33SDmitri Tikhonov#include <stdint.h> 550aadb33SDmitri Tikhonov#include <string.h> 6461e84d8SAmol Deshpande#ifdef WIN32 7461e84d8SAmol Deshpande#include <vc_compat.h> 8461e84d8SAmol Deshpande#endif 950aadb33SDmitri Tikhonov 1050aadb33SDmitri Tikhonov#include "lsquic_types.h" 1150aadb33SDmitri Tikhonov#include "lsquic_int_types.h" 1250aadb33SDmitri Tikhonov#include "lsquic_pacer.h" 1350aadb33SDmitri Tikhonov#include "lsquic_packet_common.h" 145392f7a3SLiteSpeed Tech#include "lsquic_packet_gquic.h" 1550aadb33SDmitri Tikhonov#include "lsquic_packet_out.h" 1650aadb33SDmitri Tikhonov#include "lsquic_util.h" 1750aadb33SDmitri Tikhonov 1850aadb33SDmitri Tikhonov#define LSQUIC_LOGGER_MODULE LSQLM_PACER 195392f7a3SLiteSpeed Tech#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(pacer->pa_conn) 2050aadb33SDmitri Tikhonov#include "lsquic_logger.h" 2150aadb33SDmitri Tikhonov 2250aadb33SDmitri Tikhonov#ifndef MAX 2350aadb33SDmitri Tikhonov# define MAX(a, b) ((a) > (b) ? (a) : (b)) 2450aadb33SDmitri Tikhonov#endif 2550aadb33SDmitri Tikhonov 2650aadb33SDmitri Tikhonov 2750aadb33SDmitri Tikhonovvoid 28a5fa05f9SDmitri Tikhonovlsquic_pacer_init (struct pacer *pacer, const struct lsquic_conn *conn, 295392f7a3SLiteSpeed Tech unsigned clock_granularity) 3050aadb33SDmitri Tikhonov{ 3150aadb33SDmitri Tikhonov memset(pacer, 0, sizeof(*pacer)); 3250aadb33SDmitri Tikhonov pacer->pa_burst_tokens = 10; 335392f7a3SLiteSpeed Tech pacer->pa_conn = conn; 346aba801dSDmitri Tikhonov pacer->pa_clock_granularity = clock_granularity; 3550aadb33SDmitri Tikhonov} 3650aadb33SDmitri Tikhonov 3750aadb33SDmitri Tikhonov 3850aadb33SDmitri Tikhonovvoid 39a5fa05f9SDmitri Tikhonovlsquic_pacer_cleanup (struct pacer *pacer) 40bfc7bfd8SDmitri Tikhonov{ 41bfc7bfd8SDmitri Tikhonov#ifndef NDEBUG 4290fe3b25SDmitri Tikhonov LSQ_DEBUG("scheduled calls: %u", pacer->pa_stats.n_scheduled); 43bfc7bfd8SDmitri Tikhonov#endif 44bfc7bfd8SDmitri Tikhonov} 45bfc7bfd8SDmitri Tikhonov 46bfc7bfd8SDmitri Tikhonov 47bfc7bfd8SDmitri Tikhonovvoid 48a5fa05f9SDmitri Tikhonovlsquic_pacer_packet_scheduled (struct pacer *pacer, unsigned n_in_flight, 4950aadb33SDmitri Tikhonov int in_recovery, tx_time_f tx_time, void *tx_ctx) 5050aadb33SDmitri Tikhonov{ 5150aadb33SDmitri Tikhonov lsquic_time_t delay, sched_time; 5250aadb33SDmitri Tikhonov int app_limited, making_up; 5350aadb33SDmitri Tikhonov 54bfc7bfd8SDmitri Tikhonov#ifndef NDEBUG 55bfc7bfd8SDmitri Tikhonov ++pacer->pa_stats.n_scheduled; 56bfc7bfd8SDmitri Tikhonov#endif 575392f7a3SLiteSpeed Tech ++pacer->pa_n_scheduled; 58bfc7bfd8SDmitri Tikhonov 5950aadb33SDmitri Tikhonov if (n_in_flight == 0 && !in_recovery) 6050aadb33SDmitri Tikhonov { 6150aadb33SDmitri Tikhonov pacer->pa_burst_tokens = 10; 6250aadb33SDmitri Tikhonov LSQ_DEBUG("%s: replenish tokens: %u", __func__, pacer->pa_burst_tokens); 6350aadb33SDmitri Tikhonov } 6450aadb33SDmitri Tikhonov 6550aadb33SDmitri Tikhonov if (pacer->pa_burst_tokens > 0) 6650aadb33SDmitri Tikhonov { 6750aadb33SDmitri Tikhonov --pacer->pa_burst_tokens; 6850aadb33SDmitri Tikhonov pacer->pa_flags &= ~PA_LAST_SCHED_DELAYED; 6950aadb33SDmitri Tikhonov pacer->pa_next_sched = 0; 7050aadb33SDmitri Tikhonov pacer->pa_last_delayed = 0; 7150aadb33SDmitri Tikhonov LSQ_DEBUG("%s: tokens: %u", __func__, pacer->pa_burst_tokens); 7250aadb33SDmitri Tikhonov return; 7350aadb33SDmitri Tikhonov } 7450aadb33SDmitri Tikhonov 7550aadb33SDmitri Tikhonov sched_time = pacer->pa_now; 7650aadb33SDmitri Tikhonov delay = tx_time(tx_ctx); 7750aadb33SDmitri Tikhonov if (pacer->pa_flags & PA_LAST_SCHED_DELAYED) 7850aadb33SDmitri Tikhonov { 7950aadb33SDmitri Tikhonov pacer->pa_next_sched += delay; 8050aadb33SDmitri Tikhonov app_limited = pacer->pa_last_delayed != 0 8150aadb33SDmitri Tikhonov && pacer->pa_last_delayed + delay <= sched_time; 8250aadb33SDmitri Tikhonov making_up = pacer->pa_next_sched <= sched_time; 8350aadb33SDmitri Tikhonov LSQ_DEBUG("making up: %d; app limited; %d", making_up, app_limited); 8450aadb33SDmitri Tikhonov if (making_up && !app_limited) 8550aadb33SDmitri Tikhonov pacer->pa_last_delayed = sched_time; 8650aadb33SDmitri Tikhonov else 8750aadb33SDmitri Tikhonov { 8850aadb33SDmitri Tikhonov pacer->pa_flags &= ~PA_LAST_SCHED_DELAYED; 8950aadb33SDmitri Tikhonov pacer->pa_last_delayed = 0; 9050aadb33SDmitri Tikhonov } 9150aadb33SDmitri Tikhonov } 9250aadb33SDmitri Tikhonov else 9350aadb33SDmitri Tikhonov pacer->pa_next_sched = MAX(pacer->pa_next_sched + delay, 9450aadb33SDmitri Tikhonov sched_time + delay); 9550aadb33SDmitri Tikhonov LSQ_DEBUG("next_sched is set to %"PRIu64" usec from now", 965392f7a3SLiteSpeed Tech pacer->pa_next_sched - pacer->pa_now); 9750aadb33SDmitri Tikhonov} 9850aadb33SDmitri Tikhonov 9950aadb33SDmitri Tikhonov 10050aadb33SDmitri Tikhonovvoid 101a5fa05f9SDmitri Tikhonovlsquic_pacer_loss_event (struct pacer *pacer) 10250aadb33SDmitri Tikhonov{ 10350aadb33SDmitri Tikhonov pacer->pa_burst_tokens = 0; 10450aadb33SDmitri Tikhonov LSQ_DEBUG("%s: tokens: %u", __func__, pacer->pa_burst_tokens); 10550aadb33SDmitri Tikhonov} 10650aadb33SDmitri Tikhonov 10750aadb33SDmitri Tikhonov 10850aadb33SDmitri Tikhonovint 109a5fa05f9SDmitri Tikhonovlsquic_pacer_can_schedule (struct pacer *pacer, unsigned n_in_flight) 11050aadb33SDmitri Tikhonov{ 11150aadb33SDmitri Tikhonov int can; 11250aadb33SDmitri Tikhonov 11350aadb33SDmitri Tikhonov if (pacer->pa_burst_tokens > 0 || n_in_flight == 0) 11450aadb33SDmitri Tikhonov can = 1; 1156aba801dSDmitri Tikhonov else if (pacer->pa_next_sched > pacer->pa_now + pacer->pa_clock_granularity) 11650aadb33SDmitri Tikhonov { 11750aadb33SDmitri Tikhonov pacer->pa_flags |= PA_LAST_SCHED_DELAYED; 11850aadb33SDmitri Tikhonov can = 0; 11950aadb33SDmitri Tikhonov } 12050aadb33SDmitri Tikhonov else 12150aadb33SDmitri Tikhonov can = 1; 12250aadb33SDmitri Tikhonov 12350aadb33SDmitri Tikhonov LSQ_DEBUG("%s: %d", __func__, can); 12450aadb33SDmitri Tikhonov return can; 12550aadb33SDmitri Tikhonov} 12650aadb33SDmitri Tikhonov 12750aadb33SDmitri Tikhonov 128b8fa6195SDmitri Tikhonovint 129b8fa6195SDmitri Tikhonovlsquic_pacer_can_schedule_probe (const struct pacer *pacer, 130b8fa6195SDmitri Tikhonov unsigned n_in_flight, lsquic_time_t tx_time) 131b8fa6195SDmitri Tikhonov{ 132b8fa6195SDmitri Tikhonov return pacer->pa_burst_tokens > 1 /* Double packet size, want two tokens */ 133b8fa6195SDmitri Tikhonov || n_in_flight == 0 134b8fa6195SDmitri Tikhonov || pacer->pa_next_sched > pacer->pa_now + tx_time / 2; 135b8fa6195SDmitri Tikhonov} 136b8fa6195SDmitri Tikhonov 137b8fa6195SDmitri Tikhonov 13850aadb33SDmitri Tikhonovvoid 139a5fa05f9SDmitri Tikhonovlsquic_pacer_tick_in (struct pacer *pacer, lsquic_time_t now) 14050aadb33SDmitri Tikhonov{ 141bdba46fdSDmitri Tikhonov assert(now >= pacer->pa_now); 14250aadb33SDmitri Tikhonov pacer->pa_now = now; 1435392f7a3SLiteSpeed Tech if (pacer->pa_flags & PA_LAST_SCHED_DELAYED) 1445392f7a3SLiteSpeed Tech pacer->pa_flags |= PA_DELAYED_ON_TICK_IN; 1455392f7a3SLiteSpeed Tech pacer->pa_n_scheduled = 0; 1465392f7a3SLiteSpeed Tech} 1475392f7a3SLiteSpeed Tech 1485392f7a3SLiteSpeed Tech 1495392f7a3SLiteSpeed Techvoid 150a5fa05f9SDmitri Tikhonovlsquic_pacer_tick_out (struct pacer *pacer) 1515392f7a3SLiteSpeed Tech{ 1525392f7a3SLiteSpeed Tech if ((pacer->pa_flags & PA_DELAYED_ON_TICK_IN) 1535392f7a3SLiteSpeed Tech && pacer->pa_n_scheduled == 0 1545392f7a3SLiteSpeed Tech && pacer->pa_now > pacer->pa_next_sched) 1555392f7a3SLiteSpeed Tech { 1565392f7a3SLiteSpeed Tech LSQ_DEBUG("tick passed without scheduled packets: reset delayed flag"); 1575392f7a3SLiteSpeed Tech pacer->pa_flags &= ~PA_LAST_SCHED_DELAYED; 1585392f7a3SLiteSpeed Tech } 1595392f7a3SLiteSpeed Tech pacer->pa_flags &= ~PA_DELAYED_ON_TICK_IN; 16050aadb33SDmitri Tikhonov} 161