<div dir="ltr"><div><div>Marek & Nicolai,<br><br></div>FYI, I am NOT trying to NIH anything here.  My hope was that eventually, the radeon winsys code and the Intel drivers should share an allocator.  I considered starting by pulling the one out of the radeon winsys code and modifying it but there were a couple of issues (mentioned below) and I didn't want to start stuff off by changing the behavior of your driver. :-)  Please review and give your opinions as to whether or not the version here would work for radeon's use-cases.<br><br></div>--Jason<br></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, May 2, 2018 at 9:01 AM, Scott D Phillips <span dir="ltr"><<a href="mailto:scott.d.phillips@intel.com" target="_blank">scott.d.phillips@intel.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">From: Jason Ekstrand <<a href="mailto:jason.ekstrand@intel.com">jason.ekstrand@intel.com</a>><br>
<br>
This is simple linear-walk first-fit allocator roughly based on the<br>
allocator in the radeon winsys code.  This allocator has two primary<br>
functional differences:<br>
<br>
 1) It cleanly returns 0 on allocation failure<br>
<br>
 2) It allocates addresses top-down instead of bottom-up.<br>
<br>
The second one is needed for Intel because high addresses (with bit 47<br>
set) need to be canonicalized in order to work properly.  If we allocate<br>
bottom-up, then high addresses will be very rare (if they ever happen).<br>
We'd rather always have high addresses so that the canonicalization code<br>
gets better testing.<br>
---<br>
 src/util/Makefile.sources |   4 +-<br>
 src/util/meson.build      |   2 +<br>
 src/util/vma.c            | 231 ++++++++++++++++++++++++++++++<wbr>++++++++++++++++<br>
 src/util/vma.h            |  53 +++++++++++<br>
 4 files changed, 289 insertions(+), 1 deletion(-)<br>
 create mode 100644 src/util/vma.c<br>
 create mode 100644 src/util/vma.h<br>
<br>
diff --git a/src/util/Makefile.sources b/src/util/Makefile.sources<br>
index 104ecae8ed3..534520ce763 100644<br>
--- a/src/util/Makefile.sources<br>
+++ b/src/util/Makefile.sources<br>
@@ -56,7 +56,9 @@ MESA_UTIL_FILES := \<br>
        u_string.h \<br>
        u_thread.h \<br>
        u_vector.c \<br>
-       u_vector.h<br>
+       u_vector.h \<br>
+       vma.c \<br>
+       vma.h<br>
<br>
 MESA_UTIL_GENERATED_FILES = \<br>
        format_srgb.c<br>
diff --git a/src/util/meson.build b/src/util/meson.build<br>
index eece1cefef6..14660e0fa0c 100644<br>
--- a/src/util/meson.build<br>
+++ b/src/util/meson.build<br>
@@ -81,6 +81,8 @@ files_mesa_util = files(<br>
   'u_thread.h',<br>
   'u_vector.c',<br>
   'u_vector.h',<br>
+  'vma.c',<br>
+  'vma.h',<br>
 )<br>
<br>
 install_data('drirc', install_dir : get_option('sysconfdir'))<br>
diff --git a/src/util/vma.c b/src/util/vma.c<br>
new file mode 100644<br>
index 00000000000..0d4e097e21f<br>
--- /dev/null<br>
+++ b/src/util/vma.c<br>
@@ -0,0 +1,231 @@<br>
+/*<br>
+ * Copyright © 2018 Intel Corporation<br>
+ *<br>
+ * Permission is hereby granted, free of charge, to any person obtaining a<br>
+ * copy of this software and associated documentation files (the "Software"),<br>
+ * to deal in the Software without restriction, including without limitation<br>
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,<br>
+ * and/or sell copies of the Software, and to permit persons to whom the<br>
+ * Software is furnished to do so, subject to the following conditions:<br>
+ *<br>
+ * The above copyright notice and this permission notice (including the next<br>
+ * paragraph) shall be included in all copies or substantial portions of the<br>
+ * Software.<br>
+ *<br>
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR<br>
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,<br>
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL<br>
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER<br>
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING<br>
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS<br>
+ * IN THE SOFTWARE.<br>
+ */<br>
+<br>
+#include <stdlib.h><br>
+<br>
+#include "util/u_math.h"<br>
+#include "util/vma.h"<br>
+<br>
+struct util_vma_hole {<br>
+   struct list_head link;<br>
+   uint64_t offset;<br>
+   uint64_t size;<br>
+};<br>
+<br>
+#define util_vma_foreach_hole(_hole, _heap) \<br>
+   list_for_each_entry(struct util_vma_hole, _hole, &(_heap)->holes, link)<br>
+<br>
+#define util_vma_foreach_hole_safe(_<wbr>hole, _heap) \<br>
+   list_for_each_entry_safe(<wbr>struct util_vma_hole, _hole, &(_heap)->holes, link)<br>
+<br>
+void<br>
+util_vma_heap_init(struct util_vma_heap *heap,<br>
+                   uint64_t start, uint64_t size)<br>
+{<br>
+   list_inithead(&heap->holes);<br>
+   util_vma_heap_free(heap, start, size);<br>
+}<br>
+<br>
+void<br>
+util_vma_heap_finish(struct util_vma_heap *heap)<br>
+{<br>
+   util_vma_foreach_hole_safe(<wbr>hole, heap)<br>
+      free(hole);<br>
+}<br>
+<br>
+static void<br>
+util_vma_heap_validate(struct util_vma_heap *heap)<br>
+{<br>
+   uint64_t prev_offset = 0;<br>
+   util_vma_foreach_hole(hole, heap) {<br>
+      assert(hole->offset > 0);<br>
+      assert(hole->size > 0);<br>
+<br>
+      if (&hole->link == heap->holes.next) {<br>
+         /* This must be the top-most hole.  Assert that, if it overflows, it<br>
+          * overflows to 0, i.e. 2^64.<br>
+          */<br>
+         assert(hole->size + hole->offset == 0 ||<br>
+                hole->size + hole->offset > hole->offset);<br>
+      } else {<br>
+         /* This is not the top-most hole so it must not overflow and, in<br>
+          * fact, must be strictly lower than the top-most hole.  If<br>
+          * hole->size + hole->offset == prev_offset, then we failed to join<br>
+          * holes during a util_vma_heap_free.<br>
+          */<br>
+         assert(hole->size + hole->offset > hole->offset &&<br>
+                hole->size + hole->offset < prev_offset);<br>
+      }<br>
+      prev_offset = hole->offset;<br>
+   }<br>
+}<br>
+<br>
+uint64_t<br>
+util_vma_heap_alloc(struct util_vma_heap *heap,<br>
+                    uint64_t size, uint64_t alignment)<br>
+{<br>
+   /* The caller is expected to reject zero-size allocations */<br>
+   assert(size > 0);<br>
+<br>
+   assert(util_is_power_of_two_<wbr>nonzero(alignment));<br>
+<br>
+   util_vma_heap_validate(heap);<br>
+<br>
+   util_vma_foreach_hole_safe(<wbr>hole, heap) {<br>
+      if (size > hole->size)<br>
+         continue;<br>
+<br>
+      /* Compute the offset as the highest address where a chunk of the given<br>
+       * size can be without going over the top of the hole.<br>
+       *<br>
+       * This calculation is known to not overflow because we know that<br>
+       * hole->size + hole->offset can only overflow to 0 and size > 0.<br>
+       */<br>
+      uint64_t offset = (hole->size - size) + hole->offset;<br>
+<br>
+      /* Align the offset.  We align down and not up because we are allocating<br>
+       * from the top of the hole and not the bottom.<br>
+       */<br>
+      offset &= ~(alignment - 1);<br>
+<br>
+      if (offset < hole->offset)<br>
+         continue;<br>
+<br>
+      if (offset == hole->offset && size == hole->size) {<br>
+         /* Just get rid of the hole. */<br>
+         list_del(&hole->link);<br>
+         free(hole);<br>
+         util_vma_heap_validate(heap);<br>
+         return offset;<br>
+      }<br>
+<br>
+      assert(offset - hole->offset <= hole->size - size);<br>
+      uint64_t waste = (hole->size - size) - (offset - hole->offset);<br>
+      if (waste == 0) {<br>
+         /* We allocated at the top.  Shrink the hole down. */<br>
+         hole->size -= size;<br>
+         util_vma_heap_validate(heap);<br>
+         return offset;<br>
+      }<br>
+<br>
+      if (offset == hole->offset) {<br>
+         /* We allocated at the bottom. Shrink the hole up. */<br>
+         hole->offset += size;<br>
+         hole->size -= size;<br>
+         util_vma_heap_validate(heap);<br>
+         return offset;<br>
+      }<br>
+<br>
+      /* We allocated in the middle.  We need to split the old hole into two<br>
+       * holes, one high and one low.<br>
+       */<br>
+      struct util_vma_hole *high_hole = calloc(1, sizeof(*hole));<br>
+      high_hole->offset = offset + size;<br>
+      high_hole->size = waste;<br>
+<br>
+      /* Adjust the hole to be the amount of space left at he bottom of the<br>
+       * original hole.<br>
+       */<br>
+      hole->size = offset - hole->offset;<br>
+<br>
+      /* Place the new hole before the old hole so that the list is in order<br>
+       * from high to low.<br>
+       */<br>
+      list_addtail(&high_hole->link, &hole->link);<br>
+<br>
+      util_vma_heap_validate(heap);<br>
+<br>
+      return offset;<br>
+   }<br>
+<br>
+   /* Failed to allocate */<br>
+   return 0;<br>
+}<br>
+<br>
+void<br>
+util_vma_heap_free(struct util_vma_heap *heap,<br>
+                   uint64_t offset, uint64_t size)<br>
+{<br>
+   /* An offset of 0 is reserved for allocation failure.  It is not a valid<br>
+    * address and cannot be freed.<br>
+    */<br>
+   assert(offset > 0);<br>
+<br>
+   /* Freeing something with a size of 0 is also not valid. */<br>
+   assert(size > 0);<br>
+<br>
+   /* It's possible for offset + size to wrap around if we touch the top of<br>
+    * the 64-bit address space, but we cannot go any higher than 2^64.<br>
+    */<br>
+   assert(offset + size == 0 || offset + size > offset);<br>
+<br>
+   util_vma_heap_validate(heap);<br>
+<br>
+   /* Find immediately higher and lower holes if they exist. */<br>
+   struct util_vma_hole *high_hole = NULL, *low_hole = NULL;<br>
+   util_vma_foreach_hole(hole, heap) {<br>
+      if (hole->offset <= offset) {<br>
+         low_hole = hole;<br>
+         break;<br>
+      }<br>
+      high_hole = hole;<br>
+   }<br>
+<br>
+   if (high_hole)<br>
+      assert(offset + size <= high_hole->offset);<br>
+   bool high_adjacent = high_hole && offset + size == high_hole->offset;<br>
+<br>
+   if (low_hole) {<br>
+      assert(low_hole->offset + low_hole->size > low_hole->offset);<br>
+      assert(low_hole->offset + low_hole->size <= offset);<br>
+   }<br>
+   bool low_adjacent = low_hole && low_hole->offset + low_hole->size == offset;<br>
+<br>
+   if (low_adjacent && high_adjacent) {<br>
+      /* Merge the two holes */<br>
+      low_hole->size += size + high_hole->size;<br>
+      list_del(&high_hole->link);<br>
+      free(high_hole);<br>
+   } else if (low_adjacent) {<br>
+      /* Merge into the low hole */<br>
+      low_hole->size += size;<br>
+   } else if (high_adjacent) {<br>
+      /* Merge into the high hole */<br>
+      high_hole->offset = offset;<br>
+      high_hole->size += size;<br>
+   } else {<br>
+      /* Neither hole is adjacent; make a new one */<br>
+      struct util_vma_hole *hole = calloc(1, sizeof(*hole));<br>
+<br>
+      hole->offset = offset;<br>
+      hole->size = size;<br>
+<br>
+      /* Add it after the high hole so we maintain high-to-low ordering */<br>
+      if (high_hole)<br>
+         list_add(&hole->link, &high_hole->link);<br>
+      else<br>
+         list_add(&hole->link, &heap->holes);<br>
+   }<br>
+<br>
+   util_vma_heap_validate(heap);<br>
+}<br>
diff --git a/src/util/vma.h b/src/util/vma.h<br>
new file mode 100644<br>
index 00000000000..ed69914e4cb<br>
--- /dev/null<br>
+++ b/src/util/vma.h<br>
@@ -0,0 +1,53 @@<br>
+/*<br>
+ * Copyright © 2018 Intel Corporation<br>
+ *<br>
+ * Permission is hereby granted, free of charge, to any person obtaining a<br>
+ * copy of this software and associated documentation files (the "Software"),<br>
+ * to deal in the Software without restriction, including without limitation<br>
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,<br>
+ * and/or sell copies of the Software, and to permit persons to whom the<br>
+ * Software is furnished to do so, subject to the following conditions:<br>
+ *<br>
+ * The above copyright notice and this permission notice (including the next<br>
+ * paragraph) shall be included in all copies or substantial portions of the<br>
+ * Software.<br>
+ *<br>
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR<br>
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,<br>
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL<br>
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER<br>
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING<br>
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS<br>
+ * IN THE SOFTWARE.<br>
+ */<br>
+<br>
+#ifndef _UTIL_VMA_H<br>
+#define _UTIL_VMA_H<br>
+<br>
+#include <stdint.h><br>
+<br>
+#include "list.h"<br>
+<br>
+#ifdef __cplusplus<br>
+extern "C" {<br>
+#endif<br>
+<br>
+struct util_vma_heap {<br>
+   struct list_head holes;<br>
+};<br>
+<br>
+void util_vma_heap_init(struct util_vma_heap *heap,<br>
+                        uint64_t start, uint64_t size);<br>
+void util_vma_heap_finish(struct util_vma_heap *heap);<br>
+<br>
+uint64_t util_vma_heap_alloc(struct util_vma_heap *heap,<br>
+                             uint64_t size, uint64_t alignment);<br>
+<br>
+void util_vma_heap_free(struct util_vma_heap *heap,<br>
+                        uint64_t offset, uint64_t size);<br>
+<br>
+#ifdef __cplusplus<br>
+} /* extern C */<br>
+#endif<br>
+<br>
+#endif /* _UTIL_DEBUG_H */<br>
<span class="HOEnZb"><font color="#888888">-- <br>
2.14.3<br>
<br>
</font></span></blockquote></div><br></div>