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);
+}

Reply via email to