1a74702c6SGeorge Wang/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */ 250aadb33SDmitri Tikhonov/* 350aadb33SDmitri Tikhonov * lsquic_mm.c -- Memory manager. 450aadb33SDmitri Tikhonov */ 550aadb33SDmitri Tikhonov 650aadb33SDmitri Tikhonov#include <assert.h> 750aadb33SDmitri Tikhonov#include <errno.h> 850aadb33SDmitri Tikhonov#include <stddef.h> 950aadb33SDmitri Tikhonov#include <stdlib.h> 1050aadb33SDmitri Tikhonov#include <string.h> 1150aadb33SDmitri Tikhonov#include <sys/queue.h> 1250aadb33SDmitri Tikhonov 1350aadb33SDmitri Tikhonov#include "fiu-local.h" 1450aadb33SDmitri Tikhonov 1550aadb33SDmitri Tikhonov#include "lsquic.h" 1650aadb33SDmitri Tikhonov#include "lsquic_int_types.h" 175392f7a3SLiteSpeed Tech#include "lsquic_sizes.h" 1850aadb33SDmitri Tikhonov#include "lsquic_malo.h" 195392f7a3SLiteSpeed Tech#include "lsquic_hash.h" 2050aadb33SDmitri Tikhonov#include "lsquic_conn.h" 2150aadb33SDmitri Tikhonov#include "lsquic_rtt.h" 2250aadb33SDmitri Tikhonov#include "lsquic_packet_common.h" 235392f7a3SLiteSpeed Tech#include "lsquic_mini_conn.h" 245392f7a3SLiteSpeed Tech#include "lsquic_enc_sess.h" 25fbc6cc04SDmitri Tikhonov#include "lsquic_trechist.h" 265392f7a3SLiteSpeed Tech#include "lsquic_mini_conn_ietf.h" 275392f7a3SLiteSpeed Tech#include "lsquic_packet_gquic.h" 2850aadb33SDmitri Tikhonov#include "lsquic_packet_in.h" 2950aadb33SDmitri Tikhonov#include "lsquic_packet_out.h" 3050aadb33SDmitri Tikhonov#include "lsquic_parse.h" 3150aadb33SDmitri Tikhonov#include "lsquic_mm.h" 3250aadb33SDmitri Tikhonov#include "lsquic_engine_public.h" 335392f7a3SLiteSpeed Tech#include "lsquic_full_conn.h" 345392f7a3SLiteSpeed Tech#include "lsquic_varint.h" 355392f7a3SLiteSpeed Tech#include "lsquic_hq.h" 365392f7a3SLiteSpeed Tech#include "lsquic_sfcw.h" 375392f7a3SLiteSpeed Tech#include "lsquic_stream.h" 385392f7a3SLiteSpeed Tech 395392f7a3SLiteSpeed Tech#ifndef LSQUIC_LOG_POOL_STATS 405392f7a3SLiteSpeed Tech#define LSQUIC_LOG_POOL_STATS 0 415392f7a3SLiteSpeed Tech#endif 425392f7a3SLiteSpeed Tech 435392f7a3SLiteSpeed Tech#if LSQUIC_LOG_POOL_STATS 445392f7a3SLiteSpeed Tech#include "lsquic_logger.h" 455392f7a3SLiteSpeed Tech#endif 465392f7a3SLiteSpeed Tech 475392f7a3SLiteSpeed Tech#ifndef LSQUIC_USE_POOLS 485392f7a3SLiteSpeed Tech#define LSQUIC_USE_POOLS 1 495392f7a3SLiteSpeed Tech#endif 5050aadb33SDmitri Tikhonov 5150aadb33SDmitri Tikhonov#define FAIL_NOMEM do { errno = ENOMEM; return NULL; } while (0) 5250aadb33SDmitri Tikhonov 5350aadb33SDmitri Tikhonov 545392f7a3SLiteSpeed Techstruct packet_in_buf 5550aadb33SDmitri Tikhonov{ 565392f7a3SLiteSpeed Tech SLIST_ENTRY(packet_in_buf) next_pib; 5750aadb33SDmitri Tikhonov}; 5850aadb33SDmitri Tikhonov 5950aadb33SDmitri Tikhonovstruct packet_out_buf 6050aadb33SDmitri Tikhonov{ 6150aadb33SDmitri Tikhonov SLIST_ENTRY(packet_out_buf) next_pob; 6250aadb33SDmitri Tikhonov}; 6350aadb33SDmitri Tikhonov 6450aadb33SDmitri Tikhonovstruct four_k_page 6550aadb33SDmitri Tikhonov{ 6650aadb33SDmitri Tikhonov SLIST_ENTRY(four_k_page) next_fkp; 6750aadb33SDmitri Tikhonov}; 6850aadb33SDmitri Tikhonov 6950aadb33SDmitri Tikhonovstruct sixteen_k_page 7050aadb33SDmitri Tikhonov{ 7150aadb33SDmitri Tikhonov SLIST_ENTRY(sixteen_k_page) next_skp; 7250aadb33SDmitri Tikhonov}; 7350aadb33SDmitri Tikhonov 7450aadb33SDmitri Tikhonov 7550aadb33SDmitri Tikhonovint 7650aadb33SDmitri Tikhonovlsquic_mm_init (struct lsquic_mm *mm) 7750aadb33SDmitri Tikhonov{ 785392f7a3SLiteSpeed Tech#if LSQUIC_USE_POOLS 7950aadb33SDmitri Tikhonov int i; 805392f7a3SLiteSpeed Tech#endif 8150aadb33SDmitri Tikhonov 8250aadb33SDmitri Tikhonov mm->acki = malloc(sizeof(*mm->acki)); 8350aadb33SDmitri Tikhonov mm->malo.stream_frame = lsquic_malo_create(sizeof(struct stream_frame)); 84b8fa6195SDmitri Tikhonov mm->malo.frame_rec_arr = lsquic_malo_create(sizeof(struct frame_rec_arr)); 855392f7a3SLiteSpeed Tech mm->malo.mini_conn = lsquic_malo_create(sizeof(struct mini_conn)); 865392f7a3SLiteSpeed Tech mm->malo.mini_conn_ietf = lsquic_malo_create(sizeof(struct ietf_mini_conn)); 8750aadb33SDmitri Tikhonov mm->malo.packet_in = lsquic_malo_create(sizeof(struct lsquic_packet_in)); 8850aadb33SDmitri Tikhonov mm->malo.packet_out = lsquic_malo_create(sizeof(struct lsquic_packet_out)); 895392f7a3SLiteSpeed Tech mm->malo.dcid_elem = lsquic_malo_create(sizeof(struct dcid_elem)); 905392f7a3SLiteSpeed Tech mm->malo.stream_hq_frame 915392f7a3SLiteSpeed Tech = lsquic_malo_create(sizeof(struct stream_hq_frame)); 92de46bf2fSDmitri Tikhonov mm->ack_str = malloc(MAX_ACKI_STR_SZ); 935392f7a3SLiteSpeed Tech#if LSQUIC_USE_POOLS 9450aadb33SDmitri Tikhonov TAILQ_INIT(&mm->free_packets_in); 9550aadb33SDmitri Tikhonov for (i = 0; i < MM_N_OUT_BUCKETS; ++i) 9650aadb33SDmitri Tikhonov SLIST_INIT(&mm->packet_out_bufs[i]); 975392f7a3SLiteSpeed Tech for (i = 0; i < MM_N_IN_BUCKETS; ++i) 985392f7a3SLiteSpeed Tech SLIST_INIT(&mm->packet_in_bufs[i]); 9950aadb33SDmitri Tikhonov SLIST_INIT(&mm->four_k_pages); 10050aadb33SDmitri Tikhonov SLIST_INIT(&mm->sixteen_k_pages); 1015392f7a3SLiteSpeed Tech#endif 102b8fa6195SDmitri Tikhonov if (mm->acki && mm->malo.stream_frame && mm->malo.frame_rec_arr 1035392f7a3SLiteSpeed Tech && mm->malo.mini_conn && mm->malo.mini_conn_ietf && mm->malo.packet_in 104de46bf2fSDmitri Tikhonov && mm->malo.packet_out && mm->malo.dcid_elem 105de46bf2fSDmitri Tikhonov && mm->malo.stream_hq_frame && mm->ack_str) 10650aadb33SDmitri Tikhonov { 10750aadb33SDmitri Tikhonov return 0; 10850aadb33SDmitri Tikhonov } 10950aadb33SDmitri Tikhonov else 11050aadb33SDmitri Tikhonov return -1; 11150aadb33SDmitri Tikhonov} 11250aadb33SDmitri Tikhonov 11350aadb33SDmitri Tikhonov 11450aadb33SDmitri Tikhonovvoid 11550aadb33SDmitri Tikhonovlsquic_mm_cleanup (struct lsquic_mm *mm) 11650aadb33SDmitri Tikhonov{ 1175392f7a3SLiteSpeed Tech#if LSQUIC_USE_POOLS 11850aadb33SDmitri Tikhonov int i; 11950aadb33SDmitri Tikhonov struct packet_out_buf *pob; 1205392f7a3SLiteSpeed Tech struct packet_in_buf *pib; 12150aadb33SDmitri Tikhonov struct four_k_page *fkp; 12250aadb33SDmitri Tikhonov struct sixteen_k_page *skp; 1235392f7a3SLiteSpeed Tech#endif 12450aadb33SDmitri Tikhonov 12550aadb33SDmitri Tikhonov free(mm->acki); 1265392f7a3SLiteSpeed Tech lsquic_malo_destroy(mm->malo.stream_hq_frame); 1275392f7a3SLiteSpeed Tech lsquic_malo_destroy(mm->malo.dcid_elem); 12850aadb33SDmitri Tikhonov lsquic_malo_destroy(mm->malo.packet_in); 12950aadb33SDmitri Tikhonov lsquic_malo_destroy(mm->malo.packet_out); 13050aadb33SDmitri Tikhonov lsquic_malo_destroy(mm->malo.stream_frame); 131b8fa6195SDmitri Tikhonov lsquic_malo_destroy(mm->malo.frame_rec_arr); 1325392f7a3SLiteSpeed Tech lsquic_malo_destroy(mm->malo.mini_conn); 1335392f7a3SLiteSpeed Tech lsquic_malo_destroy(mm->malo.mini_conn_ietf); 134de46bf2fSDmitri Tikhonov free(mm->ack_str); 13550aadb33SDmitri Tikhonov 1365392f7a3SLiteSpeed Tech#if LSQUIC_USE_POOLS 13750aadb33SDmitri Tikhonov for (i = 0; i < MM_N_OUT_BUCKETS; ++i) 13850aadb33SDmitri Tikhonov while ((pob = SLIST_FIRST(&mm->packet_out_bufs[i]))) 13950aadb33SDmitri Tikhonov { 14050aadb33SDmitri Tikhonov SLIST_REMOVE_HEAD(&mm->packet_out_bufs[i], next_pob); 14150aadb33SDmitri Tikhonov free(pob); 14250aadb33SDmitri Tikhonov } 14350aadb33SDmitri Tikhonov 1445392f7a3SLiteSpeed Tech for (i = 0; i < MM_N_IN_BUCKETS; ++i) 1455392f7a3SLiteSpeed Tech while ((pib = SLIST_FIRST(&mm->packet_in_bufs[i]))) 1465392f7a3SLiteSpeed Tech { 1475392f7a3SLiteSpeed Tech SLIST_REMOVE_HEAD(&mm->packet_in_bufs[i], next_pib); 1485392f7a3SLiteSpeed Tech free(pib); 1495392f7a3SLiteSpeed Tech } 15050aadb33SDmitri Tikhonov 15150aadb33SDmitri Tikhonov while ((fkp = SLIST_FIRST(&mm->four_k_pages))) 15250aadb33SDmitri Tikhonov { 15350aadb33SDmitri Tikhonov SLIST_REMOVE_HEAD(&mm->four_k_pages, next_fkp); 15450aadb33SDmitri Tikhonov free(fkp); 15550aadb33SDmitri Tikhonov } 15650aadb33SDmitri Tikhonov 15750aadb33SDmitri Tikhonov while ((skp = SLIST_FIRST(&mm->sixteen_k_pages))) 15850aadb33SDmitri Tikhonov { 15950aadb33SDmitri Tikhonov SLIST_REMOVE_HEAD(&mm->sixteen_k_pages, next_skp); 16050aadb33SDmitri Tikhonov free(skp); 16150aadb33SDmitri Tikhonov } 1625392f7a3SLiteSpeed Tech#endif 1635392f7a3SLiteSpeed Tech} 1645392f7a3SLiteSpeed Tech 1655392f7a3SLiteSpeed Tech 1665392f7a3SLiteSpeed Tech#if LSQUIC_USE_POOLS 1675392f7a3SLiteSpeed Techenum { 1685392f7a3SLiteSpeed Tech PACKET_IN_PAYLOAD_0 = 1370, /* common QUIC payload size upperbound */ 1695392f7a3SLiteSpeed Tech PACKET_IN_PAYLOAD_1 = 4096, /* payload size middleground guess */ 1705392f7a3SLiteSpeed Tech PACKET_IN_PAYLOAD_2 = 0xffff, /* UDP payload size upperbound */ 1715392f7a3SLiteSpeed Tech}; 1725392f7a3SLiteSpeed Tech 1735392f7a3SLiteSpeed Tech 1745392f7a3SLiteSpeed Techstatic const unsigned packet_in_sizes[] = { 1755392f7a3SLiteSpeed Tech PACKET_IN_PAYLOAD_0, 1765392f7a3SLiteSpeed Tech PACKET_IN_PAYLOAD_1, 1775392f7a3SLiteSpeed Tech PACKET_IN_PAYLOAD_2, 1785392f7a3SLiteSpeed Tech}; 1795392f7a3SLiteSpeed Tech 1805392f7a3SLiteSpeed Tech 1815392f7a3SLiteSpeed Techstatic unsigned 1825392f7a3SLiteSpeed Techpacket_in_index (unsigned size) 1835392f7a3SLiteSpeed Tech{ 1845392f7a3SLiteSpeed Tech unsigned idx = (size > PACKET_IN_PAYLOAD_0) 1855392f7a3SLiteSpeed Tech + (size > PACKET_IN_PAYLOAD_1); 1865392f7a3SLiteSpeed Tech return idx; 1875392f7a3SLiteSpeed Tech} 1885392f7a3SLiteSpeed Tech#endif 1895392f7a3SLiteSpeed Tech 1905392f7a3SLiteSpeed Tech 1915392f7a3SLiteSpeed Techvoid 1925392f7a3SLiteSpeed Techlsquic_mm_put_packet_in (struct lsquic_mm *mm, 1935392f7a3SLiteSpeed Tech struct lsquic_packet_in *packet_in) 1945392f7a3SLiteSpeed Tech{ 1955392f7a3SLiteSpeed Tech#if LSQUIC_USE_POOLS 1965392f7a3SLiteSpeed Tech unsigned idx; 1975392f7a3SLiteSpeed Tech struct packet_in_buf *pib; 1985392f7a3SLiteSpeed Tech 1995392f7a3SLiteSpeed Tech assert(0 == packet_in->pi_refcnt); 2005392f7a3SLiteSpeed Tech if (packet_in->pi_flags & PI_OWN_DATA) 2015392f7a3SLiteSpeed Tech { 2025392f7a3SLiteSpeed Tech pib = (struct packet_in_buf *) packet_in->pi_data; 2035392f7a3SLiteSpeed Tech idx = packet_in_index(packet_in->pi_data_sz); 2045392f7a3SLiteSpeed Tech SLIST_INSERT_HEAD(&mm->packet_in_bufs[idx], pib, next_pib); 2055392f7a3SLiteSpeed Tech } 2065392f7a3SLiteSpeed Tech TAILQ_INSERT_HEAD(&mm->free_packets_in, packet_in, pi_next); 2075392f7a3SLiteSpeed Tech#else 2085392f7a3SLiteSpeed Tech if (packet_in->pi_flags & PI_OWN_DATA) 2095392f7a3SLiteSpeed Tech free(packet_in->pi_data); 2105392f7a3SLiteSpeed Tech lsquic_malo_put(packet_in); 2115392f7a3SLiteSpeed Tech#endif 21250aadb33SDmitri Tikhonov} 21350aadb33SDmitri Tikhonov 21450aadb33SDmitri Tikhonov 21550aadb33SDmitri Tikhonovstruct lsquic_packet_in * 21650aadb33SDmitri Tikhonovlsquic_mm_get_packet_in (struct lsquic_mm *mm) 21750aadb33SDmitri Tikhonov{ 21850aadb33SDmitri Tikhonov struct lsquic_packet_in *packet_in; 21950aadb33SDmitri Tikhonov 22050aadb33SDmitri Tikhonov fiu_do_on("mm/packet_in", FAIL_NOMEM); 22150aadb33SDmitri Tikhonov 2225392f7a3SLiteSpeed Tech#if LSQUIC_USE_POOLS 22350aadb33SDmitri Tikhonov packet_in = TAILQ_FIRST(&mm->free_packets_in); 22450aadb33SDmitri Tikhonov if (packet_in) 22550aadb33SDmitri Tikhonov { 22650aadb33SDmitri Tikhonov assert(0 == packet_in->pi_refcnt); 22750aadb33SDmitri Tikhonov TAILQ_REMOVE(&mm->free_packets_in, packet_in, pi_next); 22850aadb33SDmitri Tikhonov } 22950aadb33SDmitri Tikhonov else 2305392f7a3SLiteSpeed Tech#endif 23150aadb33SDmitri Tikhonov packet_in = lsquic_malo_get(mm->malo.packet_in); 23250aadb33SDmitri Tikhonov 23350aadb33SDmitri Tikhonov if (packet_in) 23450aadb33SDmitri Tikhonov memset(packet_in, 0, sizeof(*packet_in)); 23550aadb33SDmitri Tikhonov 23650aadb33SDmitri Tikhonov return packet_in; 23750aadb33SDmitri Tikhonov} 23850aadb33SDmitri Tikhonov 23950aadb33SDmitri Tikhonov 2405392f7a3SLiteSpeed Tech#if LSQUIC_USE_POOLS 24150aadb33SDmitri Tikhonov/* Based on commonly used MTUs, ordered from small to large: */ 24250aadb33SDmitri Tikhonovenum { 2435392f7a3SLiteSpeed Tech PACKET_OUT_PAYLOAD_0 = 1280 - GQUIC_MIN_PACKET_OVERHEAD, 2445392f7a3SLiteSpeed Tech PACKET_OUT_PAYLOAD_1 = GQUIC_MAX_IPv6_PACKET_SZ - GQUIC_MIN_PACKET_OVERHEAD, 2455392f7a3SLiteSpeed Tech PACKET_OUT_PAYLOAD_2 = GQUIC_MAX_IPv4_PACKET_SZ - GQUIC_MIN_PACKET_OVERHEAD, 2465392f7a3SLiteSpeed Tech PACKET_OUT_PAYLOAD_3 = 4096, 2475392f7a3SLiteSpeed Tech PACKET_OUT_PAYLOAD_4 = 0xffff, 24850aadb33SDmitri Tikhonov}; 24950aadb33SDmitri Tikhonov 25050aadb33SDmitri Tikhonov 25150aadb33SDmitri Tikhonovstatic const unsigned packet_out_sizes[] = { 25250aadb33SDmitri Tikhonov PACKET_OUT_PAYLOAD_0, 25350aadb33SDmitri Tikhonov PACKET_OUT_PAYLOAD_1, 25450aadb33SDmitri Tikhonov PACKET_OUT_PAYLOAD_2, 2555392f7a3SLiteSpeed Tech PACKET_OUT_PAYLOAD_3, 2565392f7a3SLiteSpeed Tech PACKET_OUT_PAYLOAD_4, 25750aadb33SDmitri Tikhonov}; 25850aadb33SDmitri Tikhonov 25950aadb33SDmitri Tikhonov 26050aadb33SDmitri Tikhonovstatic unsigned 26150aadb33SDmitri Tikhonovpacket_out_index (unsigned size) 26250aadb33SDmitri Tikhonov{ 26350aadb33SDmitri Tikhonov unsigned idx = (size > PACKET_OUT_PAYLOAD_0) 2645392f7a3SLiteSpeed Tech + (size > PACKET_OUT_PAYLOAD_1) 2655392f7a3SLiteSpeed Tech + (size > PACKET_OUT_PAYLOAD_2) 2665392f7a3SLiteSpeed Tech + (size > PACKET_OUT_PAYLOAD_3); 26750aadb33SDmitri Tikhonov return idx; 26850aadb33SDmitri Tikhonov} 2695392f7a3SLiteSpeed Tech#endif 2705392f7a3SLiteSpeed Tech 2715392f7a3SLiteSpeed Tech#if LSQUIC_USE_POOLS 2725392f7a3SLiteSpeed Tech#define POOL_SAMPLE_PERIOD 1024 2735392f7a3SLiteSpeed Tech 2745392f7a3SLiteSpeed Techstatic void 2755392f7a3SLiteSpeed Techpoolst_sample_max (struct pool_stats *poolst) 2765392f7a3SLiteSpeed Tech{ 2775392f7a3SLiteSpeed Tech#define ALPHA_SHIFT 3 2785392f7a3SLiteSpeed Tech#define BETA_SHIFT 2 2795392f7a3SLiteSpeed Tech unsigned diff; 2805392f7a3SLiteSpeed Tech 2815392f7a3SLiteSpeed Tech if (poolst->ps_max_avg) 2825392f7a3SLiteSpeed Tech { 2835392f7a3SLiteSpeed Tech poolst->ps_max_var -= poolst->ps_max_var >> BETA_SHIFT; 2845392f7a3SLiteSpeed Tech if (poolst->ps_max_avg > poolst->ps_max) 2855392f7a3SLiteSpeed Tech diff = poolst->ps_max_avg - poolst->ps_max; 2865392f7a3SLiteSpeed Tech else 2875392f7a3SLiteSpeed Tech diff = poolst->ps_max - poolst->ps_max_avg; 2885392f7a3SLiteSpeed Tech poolst->ps_max_var += diff >> BETA_SHIFT; 2895392f7a3SLiteSpeed Tech poolst->ps_max_avg -= poolst->ps_max_avg >> ALPHA_SHIFT; 2905392f7a3SLiteSpeed Tech poolst->ps_max_avg += poolst->ps_max >> ALPHA_SHIFT; 2915392f7a3SLiteSpeed Tech } 2925392f7a3SLiteSpeed Tech else 2935392f7a3SLiteSpeed Tech { 2945392f7a3SLiteSpeed Tech /* First measurement */ 2955392f7a3SLiteSpeed Tech poolst->ps_max_avg = poolst->ps_max; 2965392f7a3SLiteSpeed Tech poolst->ps_max_var = poolst->ps_max / 2; 2975392f7a3SLiteSpeed Tech } 2985392f7a3SLiteSpeed Tech 2995392f7a3SLiteSpeed Tech poolst->ps_calls = 0; 3005392f7a3SLiteSpeed Tech poolst->ps_max = poolst->ps_objs_out; 3015392f7a3SLiteSpeed Tech#if LSQUIC_LOG_POOL_STATS 3025392f7a3SLiteSpeed Tech LSQ_DEBUG("new sample: max avg: %u; var: %u", poolst->ps_max_avg, 3035392f7a3SLiteSpeed Tech poolst->ps_max_var); 3045392f7a3SLiteSpeed Tech#endif 3055392f7a3SLiteSpeed Tech} 3065392f7a3SLiteSpeed Tech 3075392f7a3SLiteSpeed Tech 3085392f7a3SLiteSpeed Techstatic void 3095392f7a3SLiteSpeed Techpoolst_allocated (struct pool_stats *poolst, unsigned new) 3105392f7a3SLiteSpeed Tech{ 3115392f7a3SLiteSpeed Tech poolst->ps_objs_out += 1; 3125392f7a3SLiteSpeed Tech poolst->ps_objs_all += new; 3135392f7a3SLiteSpeed Tech if (poolst->ps_objs_out > poolst->ps_max) 3145392f7a3SLiteSpeed Tech poolst->ps_max = poolst->ps_objs_out; 3155392f7a3SLiteSpeed Tech ++poolst->ps_calls; 3165392f7a3SLiteSpeed Tech if (0 == poolst->ps_calls % POOL_SAMPLE_PERIOD) 3175392f7a3SLiteSpeed Tech poolst_sample_max(poolst); 3185392f7a3SLiteSpeed Tech} 3195392f7a3SLiteSpeed Tech 3205392f7a3SLiteSpeed Tech 3215392f7a3SLiteSpeed Techstatic void 3225392f7a3SLiteSpeed Techpoolst_freed (struct pool_stats *poolst) 3235392f7a3SLiteSpeed Tech{ 3245392f7a3SLiteSpeed Tech --poolst->ps_objs_out; 3255392f7a3SLiteSpeed Tech ++poolst->ps_calls; 3265392f7a3SLiteSpeed Tech if (0 == poolst->ps_calls % POOL_SAMPLE_PERIOD) 3275392f7a3SLiteSpeed Tech poolst_sample_max(poolst); 3285392f7a3SLiteSpeed Tech} 3295392f7a3SLiteSpeed Tech 3305392f7a3SLiteSpeed Tech 3315392f7a3SLiteSpeed Techstatic int 3325392f7a3SLiteSpeed Techpoolst_has_new_sample (const struct pool_stats *poolst) 3335392f7a3SLiteSpeed Tech{ 3345392f7a3SLiteSpeed Tech return poolst->ps_calls == 0; 3355392f7a3SLiteSpeed Tech} 3365392f7a3SLiteSpeed Tech 3375392f7a3SLiteSpeed Tech 3385392f7a3SLiteSpeed Tech/* If average maximum falls under 1/4 of all objects allocated, release 3395392f7a3SLiteSpeed Tech * half of the objects allocated. 3405392f7a3SLiteSpeed Tech */ 3415392f7a3SLiteSpeed Techstatic void 3425392f7a3SLiteSpeed Techmaybe_shrink_packet_out_bufs (struct lsquic_mm *mm, unsigned idx) 3435392f7a3SLiteSpeed Tech{ 3445392f7a3SLiteSpeed Tech struct pool_stats *poolst; 3455392f7a3SLiteSpeed Tech struct packet_out_buf *pob; 3465392f7a3SLiteSpeed Tech unsigned n_to_leave; 3475392f7a3SLiteSpeed Tech 3485392f7a3SLiteSpeed Tech poolst = &mm->packet_out_bstats[idx]; 3495392f7a3SLiteSpeed Tech if (poolst->ps_max_avg * 4 < poolst->ps_objs_all) 3505392f7a3SLiteSpeed Tech { 3515392f7a3SLiteSpeed Tech n_to_leave = poolst->ps_objs_all / 2; 3525392f7a3SLiteSpeed Tech while (poolst->ps_objs_all > n_to_leave 3535392f7a3SLiteSpeed Tech && (pob = SLIST_FIRST(&mm->packet_out_bufs[idx]))) 3545392f7a3SLiteSpeed Tech { 3555392f7a3SLiteSpeed Tech SLIST_REMOVE_HEAD(&mm->packet_out_bufs[idx], next_pob); 3565392f7a3SLiteSpeed Tech free(pob); 3575392f7a3SLiteSpeed Tech --poolst->ps_objs_all; 3585392f7a3SLiteSpeed Tech } 3595392f7a3SLiteSpeed Tech#if LSQUIC_LOG_POOL_STATS 3605392f7a3SLiteSpeed Tech LSQ_DEBUG("pool #%u; max avg %u; shrank from %u to %u objs", 3615392f7a3SLiteSpeed Tech idx, poolst->ps_max_avg, n_to_leave * 2, poolst->ps_objs_all); 3625392f7a3SLiteSpeed Tech#endif 3635392f7a3SLiteSpeed Tech } 3645392f7a3SLiteSpeed Tech#if LSQUIC_LOG_POOL_STATS 3655392f7a3SLiteSpeed Tech else 3665392f7a3SLiteSpeed Tech LSQ_DEBUG("pool #%u; max avg %u; objs: %u; won't shrink", 3675392f7a3SLiteSpeed Tech idx, poolst->ps_max_avg, poolst->ps_objs_all); 3685392f7a3SLiteSpeed Tech#endif 3695392f7a3SLiteSpeed Tech} 3705392f7a3SLiteSpeed Tech#endif 37150aadb33SDmitri Tikhonov 37250aadb33SDmitri Tikhonov 37350aadb33SDmitri Tikhonovvoid 37450aadb33SDmitri Tikhonovlsquic_mm_put_packet_out (struct lsquic_mm *mm, 37550aadb33SDmitri Tikhonov struct lsquic_packet_out *packet_out) 37650aadb33SDmitri Tikhonov{ 3775392f7a3SLiteSpeed Tech#if LSQUIC_USE_POOLS 37850aadb33SDmitri Tikhonov struct packet_out_buf *pob; 37950aadb33SDmitri Tikhonov unsigned idx; 38050aadb33SDmitri Tikhonov 38150aadb33SDmitri Tikhonov assert(packet_out->po_data); 38250aadb33SDmitri Tikhonov pob = (struct packet_out_buf *) packet_out->po_data; 38350aadb33SDmitri Tikhonov idx = packet_out_index(packet_out->po_n_alloc); 38450aadb33SDmitri Tikhonov SLIST_INSERT_HEAD(&mm->packet_out_bufs[idx], pob, next_pob); 3855392f7a3SLiteSpeed Tech poolst_freed(&mm->packet_out_bstats[idx]); 3865392f7a3SLiteSpeed Tech if (poolst_has_new_sample(&mm->packet_out_bstats[idx])) 3875392f7a3SLiteSpeed Tech maybe_shrink_packet_out_bufs(mm, idx); 3885392f7a3SLiteSpeed Tech#else 3895392f7a3SLiteSpeed Tech free(packet_out->po_data); 3905392f7a3SLiteSpeed Tech#endif 39150aadb33SDmitri Tikhonov lsquic_malo_put(packet_out); 39250aadb33SDmitri Tikhonov} 39350aadb33SDmitri Tikhonov 39450aadb33SDmitri Tikhonov 39550aadb33SDmitri Tikhonovstruct lsquic_packet_out * 39650aadb33SDmitri Tikhonovlsquic_mm_get_packet_out (struct lsquic_mm *mm, struct malo *malo, 39750aadb33SDmitri Tikhonov unsigned short size) 39850aadb33SDmitri Tikhonov{ 39950aadb33SDmitri Tikhonov struct lsquic_packet_out *packet_out; 40050aadb33SDmitri Tikhonov struct packet_out_buf *pob; 4015392f7a3SLiteSpeed Tech#if LSQUIC_USE_POOLS 40250aadb33SDmitri Tikhonov unsigned idx; 4035392f7a3SLiteSpeed Tech#endif 40450aadb33SDmitri Tikhonov 40550aadb33SDmitri Tikhonov fiu_do_on("mm/packet_out", FAIL_NOMEM); 40650aadb33SDmitri Tikhonov 40750aadb33SDmitri Tikhonov packet_out = lsquic_malo_get(malo ? malo : mm->malo.packet_out); 40850aadb33SDmitri Tikhonov if (!packet_out) 40950aadb33SDmitri Tikhonov return NULL; 41050aadb33SDmitri Tikhonov 4115392f7a3SLiteSpeed Tech#if LSQUIC_USE_POOLS 41250aadb33SDmitri Tikhonov idx = packet_out_index(size); 41350aadb33SDmitri Tikhonov pob = SLIST_FIRST(&mm->packet_out_bufs[idx]); 41450aadb33SDmitri Tikhonov if (pob) 4155392f7a3SLiteSpeed Tech { 41650aadb33SDmitri Tikhonov SLIST_REMOVE_HEAD(&mm->packet_out_bufs[idx], next_pob); 4175392f7a3SLiteSpeed Tech poolst_allocated(&mm->packet_out_bstats[idx], 0); 4185392f7a3SLiteSpeed Tech } 41950aadb33SDmitri Tikhonov else 42050aadb33SDmitri Tikhonov { 42150aadb33SDmitri Tikhonov pob = malloc(packet_out_sizes[idx]); 42250aadb33SDmitri Tikhonov if (!pob) 42350aadb33SDmitri Tikhonov { 42450aadb33SDmitri Tikhonov lsquic_malo_put(packet_out); 42550aadb33SDmitri Tikhonov return NULL; 42650aadb33SDmitri Tikhonov } 4275392f7a3SLiteSpeed Tech poolst_allocated(&mm->packet_out_bstats[idx], 1); 42850aadb33SDmitri Tikhonov } 4295392f7a3SLiteSpeed Tech if (poolst_has_new_sample(&mm->packet_out_bstats[idx])) 4305392f7a3SLiteSpeed Tech maybe_shrink_packet_out_bufs(mm, idx); 4315392f7a3SLiteSpeed Tech#else 4325392f7a3SLiteSpeed Tech pob = malloc(size); 4335392f7a3SLiteSpeed Tech if (!pob) 4345392f7a3SLiteSpeed Tech { 4355392f7a3SLiteSpeed Tech lsquic_malo_put(packet_out); 4365392f7a3SLiteSpeed Tech return NULL; 4375392f7a3SLiteSpeed Tech } 4385392f7a3SLiteSpeed Tech#endif 43950aadb33SDmitri Tikhonov 44050aadb33SDmitri Tikhonov memset(packet_out, 0, sizeof(*packet_out)); 44150aadb33SDmitri Tikhonov packet_out->po_n_alloc = size; 44250aadb33SDmitri Tikhonov packet_out->po_data = (unsigned char *) pob; 44350aadb33SDmitri Tikhonov 44450aadb33SDmitri Tikhonov return packet_out; 44550aadb33SDmitri Tikhonov} 44650aadb33SDmitri Tikhonov 44750aadb33SDmitri Tikhonov 44850aadb33SDmitri Tikhonovvoid * 4495392f7a3SLiteSpeed Techlsquic_mm_get_packet_in_buf (struct lsquic_mm *mm, size_t size) 45050aadb33SDmitri Tikhonov{ 4515392f7a3SLiteSpeed Tech struct packet_in_buf *pib; 4525392f7a3SLiteSpeed Tech#if LSQUIC_USE_POOLS 4535392f7a3SLiteSpeed Tech unsigned idx; 4545392f7a3SLiteSpeed Tech 4555392f7a3SLiteSpeed Tech idx = packet_in_index(size); 4565392f7a3SLiteSpeed Tech pib = SLIST_FIRST(&mm->packet_in_bufs[idx]); 4575392f7a3SLiteSpeed Tech fiu_do_on("mm/packet_in_buf", FAIL_NOMEM); 4585392f7a3SLiteSpeed Tech if (pib) 4595392f7a3SLiteSpeed Tech SLIST_REMOVE_HEAD(&mm->packet_in_bufs[idx], next_pib); 46050aadb33SDmitri Tikhonov else 4615392f7a3SLiteSpeed Tech pib = malloc(packet_in_sizes[idx]); 4625392f7a3SLiteSpeed Tech#else 4635392f7a3SLiteSpeed Tech pib = malloc(size); 4645392f7a3SLiteSpeed Tech#endif 4655392f7a3SLiteSpeed Tech return pib; 46650aadb33SDmitri Tikhonov} 46750aadb33SDmitri Tikhonov 46850aadb33SDmitri Tikhonov 46950aadb33SDmitri Tikhonovvoid 4705392f7a3SLiteSpeed Techlsquic_mm_put_packet_in_buf (struct lsquic_mm *mm, void *mem, size_t size) 47150aadb33SDmitri Tikhonov{ 4725392f7a3SLiteSpeed Tech#if LSQUIC_USE_POOLS 4735392f7a3SLiteSpeed Tech unsigned idx; 4745392f7a3SLiteSpeed Tech struct packet_in_buf *pib; 4755392f7a3SLiteSpeed Tech 4765392f7a3SLiteSpeed Tech pib = (struct packet_in_buf *) mem; 4775392f7a3SLiteSpeed Tech idx = packet_in_index(size); 4785392f7a3SLiteSpeed Tech SLIST_INSERT_HEAD(&mm->packet_in_bufs[idx], pib, next_pib); 4795392f7a3SLiteSpeed Tech#else 4805392f7a3SLiteSpeed Tech free(mem); 4815392f7a3SLiteSpeed Tech#endif 48250aadb33SDmitri Tikhonov} 48350aadb33SDmitri Tikhonov 48450aadb33SDmitri Tikhonov 48550aadb33SDmitri Tikhonovvoid * 48650aadb33SDmitri Tikhonovlsquic_mm_get_4k (struct lsquic_mm *mm) 48750aadb33SDmitri Tikhonov{ 4885392f7a3SLiteSpeed Tech#if LSQUIC_USE_POOLS 48950aadb33SDmitri Tikhonov struct four_k_page *fkp = SLIST_FIRST(&mm->four_k_pages); 49050aadb33SDmitri Tikhonov fiu_do_on("mm/4k", FAIL_NOMEM); 49150aadb33SDmitri Tikhonov if (fkp) 49250aadb33SDmitri Tikhonov SLIST_REMOVE_HEAD(&mm->four_k_pages, next_fkp); 49350aadb33SDmitri Tikhonov else 49450aadb33SDmitri Tikhonov fkp = malloc(0x1000); 49550aadb33SDmitri Tikhonov return fkp; 4965392f7a3SLiteSpeed Tech#else 4975392f7a3SLiteSpeed Tech return malloc(0x1000); 4985392f7a3SLiteSpeed Tech#endif 49950aadb33SDmitri Tikhonov} 50050aadb33SDmitri Tikhonov 50150aadb33SDmitri Tikhonov 50250aadb33SDmitri Tikhonovvoid 50350aadb33SDmitri Tikhonovlsquic_mm_put_4k (struct lsquic_mm *mm, void *mem) 50450aadb33SDmitri Tikhonov{ 5055392f7a3SLiteSpeed Tech#if LSQUIC_USE_POOLS 50650aadb33SDmitri Tikhonov struct four_k_page *fkp = mem; 50750aadb33SDmitri Tikhonov SLIST_INSERT_HEAD(&mm->four_k_pages, fkp, next_fkp); 5085392f7a3SLiteSpeed Tech#else 5095392f7a3SLiteSpeed Tech free(mem); 5105392f7a3SLiteSpeed Tech#endif 51150aadb33SDmitri Tikhonov} 51250aadb33SDmitri Tikhonov 51350aadb33SDmitri Tikhonov 51450aadb33SDmitri Tikhonovvoid * 51550aadb33SDmitri Tikhonovlsquic_mm_get_16k (struct lsquic_mm *mm) 51650aadb33SDmitri Tikhonov{ 5175392f7a3SLiteSpeed Tech#if LSQUIC_USE_POOLS 51850aadb33SDmitri Tikhonov struct sixteen_k_page *skp = SLIST_FIRST(&mm->sixteen_k_pages); 51950aadb33SDmitri Tikhonov fiu_do_on("mm/16k", FAIL_NOMEM); 52050aadb33SDmitri Tikhonov if (skp) 52150aadb33SDmitri Tikhonov SLIST_REMOVE_HEAD(&mm->sixteen_k_pages, next_skp); 52250aadb33SDmitri Tikhonov else 52350aadb33SDmitri Tikhonov skp = malloc(16 * 1024); 52450aadb33SDmitri Tikhonov return skp; 5255392f7a3SLiteSpeed Tech#else 5265392f7a3SLiteSpeed Tech return malloc(16 * 1024); 5275392f7a3SLiteSpeed Tech#endif 52850aadb33SDmitri Tikhonov} 52950aadb33SDmitri Tikhonov 53050aadb33SDmitri Tikhonov 53150aadb33SDmitri Tikhonovvoid 53250aadb33SDmitri Tikhonovlsquic_mm_put_16k (struct lsquic_mm *mm, void *mem) 53350aadb33SDmitri Tikhonov{ 5345392f7a3SLiteSpeed Tech#if LSQUIC_USE_POOLS 53550aadb33SDmitri Tikhonov struct sixteen_k_page *skp = mem; 53650aadb33SDmitri Tikhonov SLIST_INSERT_HEAD(&mm->sixteen_k_pages, skp, next_skp); 5375392f7a3SLiteSpeed Tech#else 5385392f7a3SLiteSpeed Tech free(mem); 5395392f7a3SLiteSpeed Tech#endif 54050aadb33SDmitri Tikhonov} 54150aadb33SDmitri Tikhonov 54250aadb33SDmitri Tikhonov 543c51ce338SDmitri Tikhonovsize_t 544c51ce338SDmitri Tikhonovlsquic_mm_mem_used (const struct lsquic_mm *mm) 545c51ce338SDmitri Tikhonov{ 5465392f7a3SLiteSpeed Tech#if LSQUIC_USE_POOLS 547c51ce338SDmitri Tikhonov const struct packet_out_buf *pob; 5485392f7a3SLiteSpeed Tech const struct packet_in_buf *pib; 549c51ce338SDmitri Tikhonov const struct four_k_page *fkp; 550c51ce338SDmitri Tikhonov const struct sixteen_k_page *skp; 551c51ce338SDmitri Tikhonov unsigned i; 552c51ce338SDmitri Tikhonov size_t size; 553c51ce338SDmitri Tikhonov 554c51ce338SDmitri Tikhonov size = sizeof(*mm); 555c51ce338SDmitri Tikhonov size += sizeof(*mm->acki); 556c51ce338SDmitri Tikhonov size += lsquic_malo_mem_used(mm->malo.stream_frame); 557b8fa6195SDmitri Tikhonov size += lsquic_malo_mem_used(mm->malo.frame_rec_arr); 5585392f7a3SLiteSpeed Tech size += lsquic_malo_mem_used(mm->malo.mini_conn); 5595392f7a3SLiteSpeed Tech size += lsquic_malo_mem_used(mm->malo.mini_conn_ietf); 560c51ce338SDmitri Tikhonov size += lsquic_malo_mem_used(mm->malo.packet_in); 561c51ce338SDmitri Tikhonov size += lsquic_malo_mem_used(mm->malo.packet_out); 562c51ce338SDmitri Tikhonov 563c51ce338SDmitri Tikhonov for (i = 0; i < MM_N_OUT_BUCKETS; ++i) 564c51ce338SDmitri Tikhonov SLIST_FOREACH(pob, &mm->packet_out_bufs[i], next_pob) 565c51ce338SDmitri Tikhonov size += packet_out_sizes[i]; 566c51ce338SDmitri Tikhonov 5675392f7a3SLiteSpeed Tech for (i = 0; i < MM_N_IN_BUCKETS; ++i) 5685392f7a3SLiteSpeed Tech SLIST_FOREACH(pib, &mm->packet_in_bufs[i], next_pib) 5695392f7a3SLiteSpeed Tech size += packet_in_sizes[i]; 570c51ce338SDmitri Tikhonov 571c51ce338SDmitri Tikhonov SLIST_FOREACH(fkp, &mm->four_k_pages, next_fkp) 572c51ce338SDmitri Tikhonov size += 0x1000; 573c51ce338SDmitri Tikhonov 574c51ce338SDmitri Tikhonov SLIST_FOREACH(skp, &mm->sixteen_k_pages, next_skp) 575c51ce338SDmitri Tikhonov size += 0x4000; 576c51ce338SDmitri Tikhonov 577c51ce338SDmitri Tikhonov return size; 5785392f7a3SLiteSpeed Tech#else 5795392f7a3SLiteSpeed Tech return sizeof(*mm); 5805392f7a3SLiteSpeed Tech#endif 581c51ce338SDmitri Tikhonov} 582