util/vma: Add an option to configure high/low preference
authorJason Ekstrand <jason@jlekstrand.net>
Thu, 29 Aug 2019 18:04:25 +0000 (13:04 -0500)
committerMarge Bot <eric+marge@anholt.net>
Wed, 13 May 2020 23:36:44 +0000 (23:36 +0000)
The vma_heap allocator was originally designed to prefer high addresses
in order to find bugs in ANV's high address handling.  However, there
are cases where you might want the allocator to prefer lower addresses
for some reason.  This provides a configure bit for exactly this
purpose.

Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/5019>

src/util/vma.c
src/util/vma.h

index 714ef01b211d7c7b90ec3c3b54b22df524f73047..f17ec0c08f1211e46a3220138247a19e678a558e 100644 (file)
@@ -38,12 +38,18 @@ struct util_vma_hole {
 #define util_vma_foreach_hole_safe(_hole, _heap) \
    list_for_each_entry_safe(struct util_vma_hole, _hole, &(_heap)->holes, link)
 
 #define util_vma_foreach_hole_safe(_hole, _heap) \
    list_for_each_entry_safe(struct util_vma_hole, _hole, &(_heap)->holes, link)
 
+#define util_vma_foreach_hole_safe_rev(_hole, _heap) \
+   list_for_each_entry_safe_rev(struct util_vma_hole, _hole, &(_heap)->holes, link)
+
 void
 util_vma_heap_init(struct util_vma_heap *heap,
                    uint64_t start, uint64_t size)
 {
    list_inithead(&heap->holes);
    util_vma_heap_free(heap, start, size);
 void
 util_vma_heap_init(struct util_vma_heap *heap,
                    uint64_t start, uint64_t size)
 {
    list_inithead(&heap->holes);
    util_vma_heap_free(heap, start, size);
+
+   /* Default to using high addresses */
+   heap->alloc_high = true;
 }
 
 void
 }
 
 void
@@ -141,29 +147,52 @@ util_vma_heap_alloc(struct util_vma_heap *heap,
 
    util_vma_heap_validate(heap);
 
 
    util_vma_heap_validate(heap);
 
-   util_vma_foreach_hole_safe(hole, heap) {
-      if (size > hole->size)
-         continue;
+   if (heap->alloc_high) {
+      util_vma_foreach_hole_safe(hole, heap) {
+         if (size > hole->size)
+            continue;
 
 
-      /* Compute the offset as the highest address where a chunk of the given
-       * size can be without going over the top of the hole.
-       *
-       * This calculation is known to not overflow because we know that
-       * hole->size + hole->offset can only overflow to 0 and size > 0.
-       */
-      uint64_t offset = (hole->size - size) + hole->offset;
+         /* Compute the offset as the highest address where a chunk of the
+          * given size can be without going over the top of the hole.
+          *
+          * This calculation is known to not overflow because we know that
+          * hole->size + hole->offset can only overflow to 0 and size > 0.
+          */
+         uint64_t offset = (hole->size - size) + hole->offset;
 
 
-      /* Align the offset.  We align down and not up because we are allocating
-       * from the top of the hole and not the bottom.
-       */
-      offset = (offset / alignment) * alignment;
+         /* Align the offset.  We align down and not up because we are
+          * allocating from the top of the hole and not the bottom.
+          */
+         offset = (offset / alignment) * alignment;
 
 
-      if (offset < hole->offset)
-         continue;
+         if (offset < hole->offset)
+            continue;
 
 
-      util_vma_hole_alloc(hole, offset, size);
-      util_vma_heap_validate(heap);
-      return offset;
+         util_vma_hole_alloc(hole, offset, size);
+         util_vma_heap_validate(heap);
+         return offset;
+      }
+   } else {
+      util_vma_foreach_hole_safe_rev(hole, heap) {
+         if (size > hole->size)
+            continue;
+
+         uint64_t offset = hole->offset;
+
+         /* Align the offset */
+         uint64_t misalign = offset % alignment;
+         if (misalign) {
+            uint64_t pad = alignment - misalign;
+            if (pad > hole->size - size)
+               continue;
+
+            offset += pad;
+         }
+
+         util_vma_hole_alloc(hole, offset, size);
+         util_vma_heap_validate(heap);
+         return offset;
+      }
    }
 
    /* Failed to allocate */
    }
 
    /* Failed to allocate */
index 91c7ee6e66a40fc76cd49e337a0de0841c986145..58b4f8bf94115ec8214e1991136a929f8d4482fa 100644 (file)
@@ -34,6 +34,12 @@ extern "C" {
 
 struct util_vma_heap {
    struct list_head holes;
 
 struct util_vma_heap {
    struct list_head holes;
+
+   /** If true, util_vma_heap_alloc will prefer high addresses
+    *
+    * Default is true.
+    */
+   bool alloc_high;
 };
 
 void util_vma_heap_init(struct util_vma_heap *heap,
 };
 
 void util_vma_heap_init(struct util_vma_heap *heap,