util: Avoid waste space when linear alloc'ing large sizes
In the linear allocator, when a size larger than the minimum buffer size is allocated, we currently create the new buffer to fit exactly the requested size. In that case, don't bother updating the `latest` pointer, since this newly created buffer is already full. In the worst case, the current `latest` is full and it would be the same; in the best case, there's still room for small allocations, so we avoid wasting space if the next allocations would fit. Reviewed-by: Emma Anholt <emma@anholt.net> Reviewed-by: Marek Olšák <marek.olsak@amd.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/25517>
This commit is contained in:
+18
-4
@@ -1032,14 +1032,28 @@ linear_alloc_child(linear_ctx *ctx, unsigned size)
|
||||
if (unlikely(!ptr))
|
||||
return NULL;
|
||||
|
||||
ctx->offset = 0;
|
||||
ctx->size = node_size;
|
||||
ctx->latest = ptr + canary_size;
|
||||
#ifndef NDEBUG
|
||||
linear_node_canary *canary = get_node_canary(ctx->latest);
|
||||
linear_node_canary *canary = (void *) ptr;
|
||||
canary->magic = LMAGIC_NODE;
|
||||
canary->offset = 0;
|
||||
#endif
|
||||
|
||||
/* If the new buffer is going to be full, don't update `latest`
|
||||
* pointer. Either the current one is also full, so doesn't
|
||||
* matter, or the current one is not full, so there's still chance
|
||||
* to use that space.
|
||||
*/
|
||||
if (unlikely(size == node_size)) {
|
||||
#ifndef NDEBUG
|
||||
canary->offset = size;
|
||||
#endif
|
||||
assert((uintptr_t)(ptr + canary_size) % SUBALLOC_ALIGNMENT == 0);
|
||||
return ptr + canary_size;
|
||||
}
|
||||
|
||||
ctx->offset = 0;
|
||||
ctx->size = node_size;
|
||||
ctx->latest = ptr + canary_size;
|
||||
}
|
||||
|
||||
void *ptr = (char *)ctx->latest + ctx->offset;
|
||||
|
||||
@@ -53,3 +53,20 @@ TEST(LinearAlloc, RewriteTail)
|
||||
|
||||
ralloc_free(ctx);
|
||||
}
|
||||
|
||||
TEST(LinearAlloc, AvoidWasteAfterLargeAlloc)
|
||||
{
|
||||
void *ctx = ralloc_context(NULL);
|
||||
linear_ctx *lin_ctx = linear_context(ctx);
|
||||
|
||||
char *first = (char *) linear_alloc_child(lin_ctx, 32);
|
||||
|
||||
/* Large allocation that would force a larger buffer. */
|
||||
linear_alloc_child(lin_ctx, 1024 * 16);
|
||||
|
||||
char *second = (char *) linear_alloc_child(lin_ctx, 32);
|
||||
|
||||
EXPECT_EQ(second - first, 32);
|
||||
|
||||
ralloc_free(ctx);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user