From: James Jones Date: Thu, 26 Aug 2021 16:02:56 +0000 (-0500) Subject: Add init parameter to LST creation closes #4210 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c8cb7c04205b5344527dcb62aa02821c38762131;p=thirdparty%2Ffreeradius-server.git Add init parameter to LST creation closes #4210 The parameter determines the initial capacity choice: 0 will get the default initial capacity, while any other value will be rounded up to a power of 2 and used as the initial capacity. --- diff --git a/src/lib/util/event.c b/src/lib/util/event.c index 7c7a31f307a..3c86488535f 100644 --- a/src/lib/util/event.c +++ b/src/lib/util/event.c @@ -2277,7 +2277,7 @@ fr_event_list_t *fr_event_list_alloc(TALLOC_CTX *ctx, fr_event_status_cb_t statu el->kq = -1; /* So destructor can be used before kqueue() provides us with fd */ talloc_set_destructor(el, _event_list_free); - el->times = fr_lst_talloc_alloc(el, fr_event_timer_cmp, fr_event_timer_t, lst_id); + el->times = fr_lst_talloc_alloc(el, fr_event_timer_cmp, fr_event_timer_t, lst_id, 0); if (!el->times) { fr_strerror_const("Failed allocating event lst"); error: @@ -2292,7 +2292,7 @@ fr_event_list_t *fr_event_list_alloc(TALLOC_CTX *ctx, fr_event_status_cb_t statu } #ifdef LOCAL_PID - el->pids = fr_lst_talloc_alloc(el, fr_event_pid_cmp, fr_event_pid_t, lst_id); + el->pids = fr_lst_talloc_alloc(el, fr_event_pid_cmp, fr_event_pid_t, lst_id, 0); if (!el->pids) { fr_strerror_const("Failed allocating PID lst"); goto error; diff --git a/src/lib/util/lst.c b/src/lib/util/lst.c index 36b5ee50a5f..e36190fe2ab 100644 --- a/src/lib/util/lst.c +++ b/src/lib/util/lst.c @@ -23,6 +23,7 @@ RCSID("$Id$") #include +#include #include #include @@ -47,6 +48,8 @@ RCSID("$Id$") #define INITIAL_CAPACITY 2048 #define INITIAL_STACK_CAPACITY 32 +#define is_power_of_2(_n) ((_n) && (((_n) & ((_n) - 1)) == 0)) + typedef unsigned int stack_index_t; typedef struct { @@ -147,8 +150,7 @@ static inline CC_HINT(always_inline, nonnull) void *pivot_item(fr_lst_t *lst, st * The index is visible for the size and length functions, since they need * to know the subtree they're working on. */ -static inline CC_HINT(always_inline, nonnull) -bool is_bucket(fr_lst_t *lst, stack_index_t idx) +static inline CC_HINT(always_inline, nonnull) bool is_bucket(fr_lst_t *lst, stack_index_t idx) { return lst_length(lst, idx) == 1; } @@ -218,11 +220,17 @@ void stack_set(pivot_stack_t *s, stack_index_t idx, fr_lst_index_t new_value) s->data[idx] = new_value; } -fr_lst_t *_fr_lst_alloc(TALLOC_CTX *ctx, fr_lst_cmp_t cmp, char const *type, size_t offset) +fr_lst_t *_fr_lst_alloc(TALLOC_CTX *ctx, fr_lst_cmp_t cmp, char const *type, size_t offset, fr_lst_index_t init) { fr_lst_t *lst; pivot_stack_t *s; + if (!init) { + init = INITIAL_CAPACITY; + } else if (!is_power_of_2(init)) { + init = 1 << fr_high_bit_pos(init); + } + /* * Pre-allocate stack memory as it is * unlikely to need to grow in practice. @@ -238,7 +246,7 @@ fr_lst_t *_fr_lst_alloc(TALLOC_CTX *ctx, fr_lst_cmp_t cmp, char const *type, siz lst = talloc_zero_pooled_object(ctx, fr_lst_t, 3, (INITIAL_STACK_CAPACITY * sizeof(fr_lst_index_t))); if (unlikely(!lst)) return NULL; - lst->capacity = INITIAL_CAPACITY; + lst->capacity = init; lst->p = talloc_array(lst, void *, lst->capacity); if (unlikely(!lst->p)) { cleanup: diff --git a/src/lib/util/lst.h b/src/lib/util/lst.h index 053aa7b872c..465bf838c79 100644 --- a/src/lib/util/lst.h +++ b/src/lib/util/lst.h @@ -56,9 +56,14 @@ typedef int8_t (*fr_lst_cmp_t)(void const *a, void const *b); * @param[in] _cmp Comparator used to compare elements. * @param[in] _type Of elements. * @param[in] _field to store LST indexes in. + * @param[in] _init initial capacity (0 for default initial size); + * the capacity will be rounded up to a power of two. + * @return + * - A pointer to the new LST. + * - NULL on error */ -#define fr_lst_alloc(_ctx, _cmp, _type, _field) \ - _fr_lst_alloc(_ctx, _cmp, NULL, (size_t)offsetof(_type, _field)) +#define fr_lst_alloc(_ctx, _cmp, _type, _field, _init) \ + _fr_lst_alloc(_ctx, _cmp, NULL, (size_t)offsetof(_type, _field), _init) /** Creates an LST that verifies elements are of a specific talloc type * @@ -66,14 +71,16 @@ typedef int8_t (*fr_lst_cmp_t)(void const *a, void const *b); * @param[in] _cmp Comparator used to compare elements. * @param[in] _talloc_type of elements. * @param[in] _field to store heap indexes in. + * @param[in] _init initial capacity (0 for default initial size); + * the capacity will be rounded up to a power of two. * @return * - A pointer to the new LST. * - NULL on error. */ -#define fr_lst_talloc_alloc(_ctx, _cmp, _talloc_type, _field) \ - _fr_lst_alloc(_ctx, _cmp, #_talloc_type, (size_t)offsetof(_talloc_type, _field)) +#define fr_lst_talloc_alloc(_ctx, _cmp, _talloc_type, _field, _init) \ + _fr_lst_alloc(_ctx, _cmp, #_talloc_type, (size_t)offsetof(_talloc_type, _field), _init) -fr_lst_t *_fr_lst_alloc(TALLOC_CTX *ctx, fr_lst_cmp_t cmp, char const *type, size_t offset) CC_HINT(nonnull(2)); +fr_lst_t *_fr_lst_alloc(TALLOC_CTX *ctx, fr_lst_cmp_t cmp, char const *type, size_t offset, fr_lst_index_t init) CC_HINT(nonnull(2)); /** Check if an entry is inserted into an LST. * diff --git a/src/lib/util/lst_tests.c b/src/lib/util/lst_tests.c index 4b660c32b47..d49577432d2 100644 --- a/src/lib/util/lst_tests.c +++ b/src/lib/util/lst_tests.c @@ -67,7 +67,7 @@ static void lst_test_basic(void) fr_lst_t *lst; lst_thing values[NVALUES]; - lst = fr_lst_alloc(NULL, lst_cmp, lst_thing, idx); + lst = fr_lst_alloc(NULL, lst_cmp, lst_thing, idx, NVALUES); TEST_CHECK(lst != NULL); populate_values(values, NUM_ELEMENTS(values)); @@ -83,6 +83,7 @@ static void lst_test_basic(void) TEST_CHECK(value != NULL); TEST_CHECK(!fr_lst_entry_inserted(value->idx)); TEST_CHECK(value->data == i); + TEST_MSG("iteration %u, popped %u", i, value->data); } talloc_free(lst); } @@ -104,7 +105,7 @@ static void lst_test(int skip) done_init = true; } - lst = fr_lst_alloc(NULL, lst_cmp, lst_thing, idx); + lst = fr_lst_alloc(NULL, lst_cmp, lst_thing, idx, 0); TEST_CHECK(lst != NULL); values = calloc(LST_TEST_SIZE, sizeof(lst_thing)); @@ -182,7 +183,7 @@ static void lst_stress_realloc(void) done_init = true; } - lst = fr_lst_alloc(NULL, lst_cmp, lst_thing, idx); + lst = fr_lst_alloc(NULL, lst_cmp, lst_thing, idx, 0); TEST_CHECK(lst != NULL); hp = fr_heap_alloc(NULL, lst_cmp, lst_thing, idx, 0); @@ -259,7 +260,7 @@ static void lst_burn_in(void) array = calloc(BURN_IN_OPS, sizeof(lst_thing)); for (unsigned int i = 0; i < BURN_IN_OPS; i++) array[i].data = rand() % 65537; - lst = fr_lst_alloc(NULL, lst_cmp, lst_thing, idx); + lst = fr_lst_alloc(NULL, lst_cmp, lst_thing, idx, 0); for (unsigned int i = 0; i < BURN_IN_OPS; i++) { lst_thing *ret_thing = NULL; @@ -311,7 +312,7 @@ static void lst_cycle(void) done_init = true; } - lst = fr_lst_alloc(NULL, lst_cmp, lst_thing, idx); + lst = fr_lst_alloc(NULL, lst_cmp, lst_thing, idx, 0); TEST_CHECK(lst != NULL); values = calloc(LST_CYCLE_SIZE, sizeof(lst_thing)); @@ -388,7 +389,7 @@ static void lst_iter(void) lst_thing values[NVALUES], *data; - lst = fr_lst_alloc(NULL, lst_cmp, lst_thing, idx); + lst = fr_lst_alloc(NULL, lst_cmp, lst_thing, idx, 0); TEST_CHECK(lst != NULL); populate_values(values, NUM_ELEMENTS(values)); @@ -449,7 +450,7 @@ static void queue_cmp(unsigned int count) populate_values(values, count); start_alloc = fr_time(); - lst = fr_lst_alloc(NULL, lst_cmp, lst_thing, idx); + lst = fr_lst_alloc(NULL, lst_cmp, lst_thing, idx, 0); end_alloc = fr_time(); TEST_CHECK(lst != NULL);