From 15b3cc73bfc86c53d4e2ad4bab8faa2b337655ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Mon, 15 Aug 2022 21:42:05 +0200 Subject: [PATCH] aco: implement custom memory resource MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This basic allocator implements an arena allocation strategy and cannot free individual allocations. It is intended for very fast memory allocations in situations where memory is used to build up a few objects and then is released all at once. This class mimics std::pmr::monotonic_buffer_resource. Reviewed-by: Timur Kristóf Part-of: --- src/amd/compiler/aco_util.h | 82 +++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/src/amd/compiler/aco_util.h b/src/amd/compiler/aco_util.h index fd404480949..676879fffdd 100644 --- a/src/amd/compiler/aco_util.h +++ b/src/amd/compiler/aco_util.h @@ -27,6 +27,7 @@ #define ACO_UTIL_H #include "util/bitscan.h" +#include "util/u_math.h" #include #include @@ -394,6 +395,87 @@ IDSet::Iterator::operator*() const return (word << 6) | bit; } +/* + * Light-weight memory resource which allows to sequentially allocate from + * a buffer. Both, the release() method and the destructor release all managed + * memory. + * + * The memory resource is not thread-safe. + * This class mimics std::pmr::monotonic_buffer_resource + */ +class monotonic_buffer_resource final { +public: + explicit monotonic_buffer_resource(size_t size = initial_size) + { + /* The size parameter refers to the total size of the buffer. + * The usable data_size is size - sizeof(Buffer). + */ + size = std::max(size, minimum_size); + buffer = (Buffer*)malloc(size); + buffer->next = nullptr; + buffer->data_size = size - sizeof(Buffer); + buffer->current_idx = 0; + } + + ~monotonic_buffer_resource() + { + release(); + free(buffer); + } + + /* delete copy-constructor and -assigment to avoid double free() */ + monotonic_buffer_resource(const monotonic_buffer_resource&) = delete; + monotonic_buffer_resource& operator=(const monotonic_buffer_resource&) = delete; + + void* allocate(size_t size, size_t alignment) + { + buffer->current_idx = align(buffer->current_idx, alignment); + if (buffer->current_idx + size <= buffer->data_size) { + uint8_t* ptr = &buffer->data[buffer->current_idx]; + buffer->current_idx += size; + return ptr; + } + + /* create new larger buffer */ + uint32_t total_size = buffer->data_size + sizeof(Buffer); + do { + total_size *= 2; + } while (total_size - sizeof(Buffer) < size); + Buffer* next = buffer; + buffer = (Buffer*)malloc(total_size); + buffer->next = next; + buffer->data_size = total_size - sizeof(Buffer); + buffer->current_idx = 0; + + return allocate(size, alignment); + } + + void release() + { + while (buffer->next) { + Buffer* next = buffer->next; + free(buffer); + buffer = next; + } + buffer->current_idx = 0; + } + + bool operator==(const monotonic_buffer_resource& other) { return buffer == other.buffer; } + +private: + struct Buffer { + Buffer* next; + uint32_t current_idx; + uint32_t data_size; + uint8_t data[]; + }; + + Buffer* buffer; + static constexpr size_t initial_size = 4096; + static constexpr size_t minimum_size = 128; + static_assert(minimum_size > sizeof(Buffer)); +}; + } // namespace aco #endif // ACO_UTIL_H