*/
#include <stdlib.h>
+#include <inttypes.h>
#include "util/u_math.h"
#include "util/vma.h"
#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);
+
+ /* Default to using high addresses */
+ heap->alloc_high = true;
}
void
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 */
util_vma_heap_validate(heap);
}
+
+void
+util_vma_heap_print(struct util_vma_heap *heap, FILE *fp,
+ const char *tab, uint64_t total_size)
+{
+ fprintf(fp, "%sutil_vma_heap:\n", tab);
+
+ uint64_t total_free = 0;
+ util_vma_foreach_hole(hole, heap) {
+ fprintf(fp, "%s hole: offset = %"PRIu64" (0x%"PRIx64", "
+ "size = %"PRIu64" (0x%"PRIx64")\n",
+ tab, hole->offset, hole->offset, hole->size, hole->size);
+ total_free += hole->size;
+ }
+ assert(total_free <= total_size);
+ fprintf(fp, "%s%"PRIu64"B (0x%"PRIx64") free (%.2f%% full)\n",
+ tab, total_free, total_free,
+ ((double)(total_size - total_free) / (double)total_size) * 100);
+}