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