0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2025-01-23 17:31:55 +00:00

Allocate the normalization buckets on stack

Even though allocating from tmp_linpool is quite cheap,
it isn't cheap when the block is larger than a page, which is the case here.
Instead, we now allocate just the result which typically fits in a page,
avoiding a necessity of a malloc().
This commit is contained in:
Maria Matejka 2024-12-24 16:16:55 +01:00
parent 4f7899e3cb
commit ffa57a4303

View File

@ -967,8 +967,8 @@ ea_list_size(ea_list *o)
* and creates the final structure useful for storage or fast searching. * and creates the final structure useful for storage or fast searching.
* The method is a bucket sort. * The method is a bucket sort.
* *
* Returns the final ea_list with some excess memory at the end, * Returns the final ea_list allocated from the tmp_linpool.
* allocated from the tmp_linpool. The adata is linked from the original places. * The adata is linked from the original places.
*/ */
ea_list * ea_list *
ea_normalize(ea_list *e, u32 upto) ea_normalize(ea_list *e, u32 upto)
@ -976,21 +976,17 @@ ea_normalize(ea_list *e, u32 upto)
/* We expect some work to be actually needed. */ /* We expect some work to be actually needed. */
ASSERT_DIE(!BIT32_TEST(&upto, e->stored)); ASSERT_DIE(!BIT32_TEST(&upto, e->stored));
/* Allocate the output */ /* Allocate the buckets locally */
ea_list *out = tmp_allocz(ea_class_max * sizeof(eattr) + sizeof(ea_list)); eattr *buckets = allocz(ea_class_max * sizeof(eattr));
*out = (ea_list) {
.flags = EALF_SORTED,
};
uint min_id = ~0, max_id = 0; uint min_id = ~0, max_id = 0;
eattr *buckets = out->attrs; ea_list *next = NULL;
/* Walk the attribute lists, one after another. */ /* Walk the attribute lists, one after another. */
for (; e; e = e->next) for (; e; e = e->next)
{ {
if (!out->next && BIT32_TEST(&upto, e->stored)) if (!next && BIT32_TEST(&upto, e->stored))
out->next = e; next = e;
for (int i = 0; i < e->count; i++) for (int i = 0; i < e->count; i++)
{ {
@ -1000,7 +996,7 @@ ea_normalize(ea_list *e, u32 upto)
if (id < min_id) if (id < min_id)
min_id = id; min_id = id;
if (out->next) if (next)
{ {
/* Underlay: check whether the value is duplicate */ /* Underlay: check whether the value is duplicate */
if (buckets[id].id && buckets[id].fresh) if (buckets[id].id && buckets[id].fresh)
@ -1026,6 +1022,18 @@ ea_normalize(ea_list *e, u32 upto)
} }
} }
/* Find out how big the output actually is. */
uint len = 0;
for (uint id = min_id; id <= max_id; id++)
if (buckets[id].id && !(buckets[id].undef && buckets[id].fresh))
len++;
ea_list *out = tmp_alloc(sizeof(ea_list) + len * sizeof(eattr));
*out = (ea_list) {
.flags = EALF_SORTED,
.next = next,
};
/* And now we just walk the list from beginning to end and collect /* And now we just walk the list from beginning to end and collect
* everything to the beginning of the list. * everything to the beginning of the list.
* Walking just that part which is inhabited for sure. */ * Walking just that part which is inhabited for sure. */
@ -1044,9 +1052,12 @@ ea_normalize(ea_list *e, u32 upto)
/* Move the attribute to the beginning */ /* Move the attribute to the beginning */
ASSERT_DIE(out->count < id); ASSERT_DIE(out->count < id);
buckets[out->count++] = buckets[id]; ASSERT_DIE(out->count < len);
out->attrs[out->count++] = buckets[id];
} }
ASSERT_DIE(out->count == len);
/* We want to bisect only if the list is long enough */ /* We want to bisect only if the list is long enough */
if (out->count > 5) if (out->count > 5)
out->flags |= EALF_BISECT; out->flags |= EALF_BISECT;