<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Thu, May 3, 2018 at 6:12 PM, Kenneth Graunke <span dir="ltr"><<a href="mailto:kenneth@whitecape.org" target="_blank">kenneth@whitecape.org</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 | 232 ++++++++++++++++++++++++++++++<wbr>++++++++<br>
src/util/vma.h | 53 +++++++++<br>
4 files changed, 290 insertions(+), 1 deletion(-)<br>
create mode 100644 src/util/vma.c<br>
create mode 100644 src/util/vma.h<br>
<br>
This is the exact same patch as Scott recently sent:<br>
<a href="https://patchwork.freedesktop.org/patch/219951/" rel="noreferrer" target="_blank">https://patchwork.freedesktop.<wbr>org/patch/219951/</a><br>
<br>
It may make more sense to review it on that existing thread. I mostly<br>
resent it here to note that it's required for this series.<br></blockquote><div><br></div><div>You could review it. :-P<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
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..3d61f6969ed<br>
--- /dev/null<br>
+++ b/src/util/vma.c<br>
@@ -0,0 +1,232 @@<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(alignment > 0);<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.17.0<br>
<br>
______________________________<wbr>_________________<br>
mesa-dev mailing list<br>
<a href="mailto:mesa-dev@lists.freedesktop.org">mesa-dev@lists.freedesktop.org</a><br>
<a href="https://lists.freedesktop.org/mailman/listinfo/mesa-dev" rel="noreferrer" target="_blank">https://lists.freedesktop.org/<wbr>mailman/listinfo/mesa-dev</a><br>
</font></span></blockquote></div><br></div></div>