lsquic_pacer.c revision 90fe3b25
1/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */ 2#include <assert.h> 3#include <inttypes.h> 4#include <stdint.h> 5#include <string.h> 6#ifdef WIN32 7#include <vc_compat.h> 8#endif 9 10#include "lsquic_types.h" 11#include "lsquic_int_types.h" 12#include "lsquic_pacer.h" 13#include "lsquic_packet_common.h" 14#include "lsquic_packet_out.h" 15#include "lsquic_util.h" 16 17#define LSQUIC_LOGGER_MODULE LSQLM_PACER 18#define LSQUIC_LOG_CONN_ID pacer->pa_cid 19#include "lsquic_logger.h" 20 21#ifndef MAX 22# define MAX(a, b) ((a) > (b) ? (a) : (b)) 23#endif 24 25 26void 27pacer_init (struct pacer *pacer, lsquic_cid_t cid, unsigned clock_granularity) 28{ 29 memset(pacer, 0, sizeof(*pacer)); 30 pacer->pa_burst_tokens = 10; 31 pacer->pa_cid = cid; 32 pacer->pa_clock_granularity = clock_granularity; 33} 34 35 36void 37pacer_cleanup (struct pacer *pacer) 38{ 39#ifndef NDEBUG 40 LSQ_DEBUG("scheduled calls: %u", pacer->pa_stats.n_scheduled); 41#endif 42} 43 44 45void 46pacer_packet_scheduled (struct pacer *pacer, unsigned n_in_flight, 47 int in_recovery, tx_time_f tx_time, void *tx_ctx) 48{ 49 lsquic_time_t delay, sched_time; 50 int app_limited, making_up; 51 52#ifndef NDEBUG 53 ++pacer->pa_stats.n_scheduled; 54#endif 55 56 if (n_in_flight == 0 && !in_recovery) 57 { 58 pacer->pa_burst_tokens = 10; 59 LSQ_DEBUG("%s: replenish tokens: %u", __func__, pacer->pa_burst_tokens); 60 } 61 62 if (pacer->pa_burst_tokens > 0) 63 { 64 --pacer->pa_burst_tokens; 65 pacer->pa_flags &= ~PA_LAST_SCHED_DELAYED; 66 pacer->pa_next_sched = 0; 67 pacer->pa_last_delayed = 0; 68 LSQ_DEBUG("%s: tokens: %u", __func__, pacer->pa_burst_tokens); 69 return; 70 } 71 72 sched_time = pacer->pa_now; 73 delay = tx_time(tx_ctx); 74 if (pacer->pa_flags & PA_LAST_SCHED_DELAYED) 75 { 76 pacer->pa_next_sched += delay; 77 app_limited = pacer->pa_last_delayed != 0 78 && pacer->pa_last_delayed + delay <= sched_time; 79 making_up = pacer->pa_next_sched <= sched_time; 80 LSQ_DEBUG("making up: %d; app limited; %d", making_up, app_limited); 81 if (making_up && !app_limited) 82 pacer->pa_last_delayed = sched_time; 83 else 84 { 85 pacer->pa_flags &= ~PA_LAST_SCHED_DELAYED; 86 pacer->pa_last_delayed = 0; 87 } 88 } 89 else 90 pacer->pa_next_sched = MAX(pacer->pa_next_sched + delay, 91 sched_time + delay); 92 LSQ_DEBUG("next_sched is set to %"PRIu64" usec from now", 93 pacer->pa_next_sched - lsquic_time_now()); 94} 95 96 97void 98pacer_loss_event (struct pacer *pacer) 99{ 100 pacer->pa_burst_tokens = 0; 101 LSQ_DEBUG("%s: tokens: %u", __func__, pacer->pa_burst_tokens); 102} 103 104 105int 106pacer_can_schedule (struct pacer *pacer, unsigned n_in_flight) 107{ 108 int can; 109 110 if (pacer->pa_burst_tokens > 0 || n_in_flight == 0) 111 can = 1; 112 else if (pacer->pa_next_sched > pacer->pa_now + pacer->pa_clock_granularity) 113 { 114 pacer->pa_flags |= PA_LAST_SCHED_DELAYED; 115 can = 0; 116 } 117 else 118 can = 1; 119 120 LSQ_DEBUG("%s: %d", __func__, can); 121 return can; 122} 123 124 125void 126pacer_tick (struct pacer *pacer, lsquic_time_t now) 127{ 128 assert(now >= pacer->pa_now); 129 pacer->pa_now = now; 130} 131