Module: Mesa Branch: main Commit: c005b5a16f5a0e38840d03d419137d6c98090788 URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=c005b5a16f5a0e38840d03d419137d6c98090788
Author: Caio Oliveira <[email protected]> Date: Mon Oct 2 23:24:51 2023 -0700 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 <[email protected]> Reviewed-by: Marek Olšák <[email protected]> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/25517> --- src/util/ralloc.c | 22 ++++++++++++++++++---- src/util/tests/linear_test.cpp | 17 +++++++++++++++++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/util/ralloc.c b/src/util/ralloc.c index 4dfc6f27b3d..c85c61e3d8a 100644 --- a/src/util/ralloc.c +++ b/src/util/ralloc.c @@ -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; diff --git a/src/util/tests/linear_test.cpp b/src/util/tests/linear_test.cpp index 8fd95a38c6a..2b573184515 100644 --- a/src/util/tests/linear_test.cpp +++ b/src/util/tests/linear_test.cpp @@ -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); +}
