diff --git a/source/common/unified_malloc_framework/include/umf/memory_pool.hpp b/source/common/unified_malloc_framework/include/umf/memory_pool.hpp new file mode 100644 index 0000000000..423a803986 --- /dev/null +++ b/source/common/unified_malloc_framework/include/umf/memory_pool.hpp @@ -0,0 +1,41 @@ +#include +#include +#include + +namespace umf +{ +namespace polymorphic +{ + +struct memory_pool { + virtual void *malloc(size_t size) = 0; + virtual void *calloc(size_t, size_t) = 0; + virtual void *realloc(void *, size_t) = 0; + virtual void *aligned_malloc(size_t size, size_t alignment) = 0; + virtual size_t malloc_usable_size(void *) = 0; + virtual void free(void *ptr) = 0; +}; + +// wraps c handle in c++ type +struct memory_pool_c : public memory_pool { + memory_pool_c(umf_memory_pool_handle_t hPool): hPool(hPool) {} + void *malloc(size_t size) {return umfPoolMalloc(hPool, size);} // TODO: check last_allocation_error and throw? + void *calloc(size_t num, size_t size) {return umfPoolCalloc(hPool, num, size);} // TODO: check last_allocation_error and throw? + void *realloc(void *ptr, size_t size) {return umfPoolRealloc(hPool, ptr, size);} // TODO: check last_allocation_error and throw? + void *aligned_malloc(size_t size, size_t alignment) {return umfPoolAlignedMalloc(hPool, size, alignment);} // TODO: check last_allocation_error and throw? + size_t malloc_usable_size(void *ptr) {return umfPoolMallocUsableSize(hPool, ptr);} + void free(void *ptr) {return umfPoolFree(hPool, ptr);} +private: + umf_memory_pool_handle_t hPool; +}; + +} + +// creates c handle from a c++ type, fills ops struct, call pool_create, etc. +template // could be constrained by concept +umf_memory_pool_handle_t memoryPoolHandleCreate(Args&&...) { + // implementation as in umf_helpers.hpp or similar + return nullptr; +} + +} diff --git a/source/common/unified_malloc_framework/include/umf/memory_provider.hpp b/source/common/unified_malloc_framework/include/umf/memory_provider.hpp new file mode 100644 index 0000000000..95389cff42 --- /dev/null +++ b/source/common/unified_malloc_framework/include/umf/memory_provider.hpp @@ -0,0 +1,44 @@ +#include +#include + +namespace umf +{ +namespace polymorphic +{ + +struct memory_provider { + virtual enum umf_result_t alloc(size_t, size_t, void **) = 0; + virtual enum umf_result_t free(void *ptr, size_t size) = 0; + virtual enum umf_result_t get_recommended_page_size(size_t size, + size_t *pageSize)= 0; + virtual enum umf_result_t get_min_page_size(void *ptr, size_t *pageSize) = 0; + virtual enum umf_result_t purge_lazy(void *ptr, size_t size) = 0; + virtual enum umf_result_t purge_force(void *ptr, size_t size) = 0; + virtual const char *get_name() = 0; +}; + +// wraps c handle in c++ type +struct memory_provider_c : public memory_provider { + memory_provider_c(umf_memory_provider_handle_t hProvider): hProvider(hProvider) {} + enum umf_result_t alloc(size_t size, size_t align, void **ptr) {return umfMemoryProviderAlloc(hProvider, size, align, ptr);} + enum umf_result_t free(void *ptr, size_t size) {return umfMemoryProviderFree(hProvider, ptr, size);} + enum umf_result_t get_recommended_page_size(size_t size, + size_t *pageSize) {return umfMemoryProviderGetRecommendedPageSize(hProvider, size, pageSize);} + enum umf_result_t get_min_page_size(void *ptr, size_t *pageSize) {return umfMemoryProviderGetMinPageSize(hProvider, ptr, pageSize);} + enum umf_result_t purge_lazy(void *ptr, size_t size) {return umfMemoryProviderPurgeLazy(hProvider, ptr, size);} + enum umf_result_t purge_force(void *ptr, size_t size) {return umfMemoryProviderPurgeForce(hProvider, ptr, size);} + const char *get_name() {return umfMemoryProviderGetName(hProvider);} +private: + umf_memory_provider_handle_t hProvider; +}; + +} + +// creates c handle from a c++ type, fills ops struct, call provider_create, etc. +template // could be constrained by concept +umf_memory_provider_handle_t memoryProviderHandleCreate(Args&&...) { + // implementation as in umf_helpers.hpp or similar + return nullptr; +} + +} diff --git a/source/common/unified_malloc_framework/include/umf/pools/disjoint_pool.h b/source/common/unified_malloc_framework/include/umf/pools/disjoint_pool.h new file mode 100644 index 0000000000..3340b13c7e --- /dev/null +++ b/source/common/unified_malloc_framework/include/umf/pools/disjoint_pool.h @@ -0,0 +1,26 @@ +#include +#include +#include + +struct UmfDisjointPoolConfig { + // Minimum allocation size that will be requested from the system. + // By default this is the minimum allocation size of each memory type. + size_t SlabMinSize = 0; + + // Allocations up to this limit will be subject to chunking/pooling + size_t MaxPoolableSize = 0; + + // When pooling, each bucket will hold a max of 4 unfreed slabs + size_t Capacity = 0; + + // Holds the minimum bucket size valid for allocation of a memory type. + size_t MinBucketSize = 0; + + // Holds size of the pool managed by the allocator. + size_t CurPoolSize = 0; + + // Whether to print pool usage statistics + int PoolTrace = 0; +}; + +umf_memory_pool_handle_t umfCreateDisjointPool(umf_memory_provider_handle_t upstream, umf_memory_provider_handle_t metadata, struct UmfDisjointPoolConfig *config); diff --git a/source/common/unified_malloc_framework/include/umf/pools/disjoint_pool.hpp b/source/common/unified_malloc_framework/include/umf/pools/disjoint_pool.hpp new file mode 100644 index 0000000000..a2e2cf2d94 --- /dev/null +++ b/source/common/unified_malloc_framework/include/umf/pools/disjoint_pool.hpp @@ -0,0 +1,84 @@ +//===---------- disjoint_pool.hpp - Allocator for USM memory --------------===// +// +// Part of the Unified-Runtime Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef DISJOINT_POOL +#define DISJOINT_POOL + +#include +#include +#include + +#include +#include + +namespace umf { + +// Configuration for specific USM allocator instance +class DisjointPoolConfig { + public: + DisjointPoolConfig(); + + std::string name = ""; + + struct SharedLimits { + SharedLimits() : TotalSize(0) {} + + // Maximum memory left unfreed + size_t MaxSize = 16 * 1024 * 1024; + + // Total size of pooled memory + std::atomic TotalSize; + }; + + // Minimum allocation size that will be requested from the system. + // By default this is the minimum allocation size of each memory type. + size_t SlabMinSize = 0; + + // Allocations up to this limit will be subject to chunking/pooling + size_t MaxPoolableSize = 0; + + // When pooling, each bucket will hold a max of 4 unfreed slabs + size_t Capacity = 0; + + // Holds the minimum bucket size valid for allocation of a memory type. + size_t MinBucketSize = 0; + + // Holds size of the pool managed by the allocator. + size_t CurPoolSize = 0; + + // Whether to print pool usage statistics + int PoolTrace = 0; + + std::shared_ptr limits; +}; + +class DisjointPool { + public: + class AllocImpl; + using Config = DisjointPoolConfig; + + // DisjointPool accepts providers as pointers to polymorphic types but other implementations could + // just accept a template arguments that match 'memory_provider' concept (or pass some other checks pre-c++20) + DisjointPool(std::unique_ptr upstream, std::unique_ptr metadata, DisjointPoolConfig parameters); + void *malloc(size_t size); + void *calloc(size_t, size_t); + void *realloc(void *, size_t); + void *aligned_malloc(size_t size, size_t alignment); + size_t malloc_usable_size(void *); + void free(void *ptr); + + DisjointPool(); + ~DisjointPool(); + + private: + std::unique_ptr impl; +}; + +} // namespace umf + +#endif diff --git a/source/common/unified_malloc_framework/src/disjoint_pool.cpp b/source/common/unified_malloc_framework/src/disjoint_pool.cpp new file mode 100644 index 0000000000..f357a6560f --- /dev/null +++ b/source/common/unified_malloc_framework/src/disjoint_pool.cpp @@ -0,0 +1,18 @@ +#include "disjoint_pool.h" +#include "disjoint_pool.hpp" + +#include "memory_pool.hpp" +#include "memory_provider.hpp" + +extern "C" umf_memory_pool_handle_t +umfCreateDisjointPool(umf_memory_provider_handle_t upstream, umf_memory_provider_handle_t metadata, struct UmfDisjointPoolConfig *config) { + umf::DisjointPoolConfig cpp_config; + // translate config to cpp_config + cpp_config.Capacity = config->Capacity; + // ... + + return umf::memoryPoolHandleCreate( + std::unique_ptr(new umf::polymorphic::memory_provider_c(upstream)), + std::unique_ptr(new umf::polymorphic::memory_provider_c(metadata)), + cpp_config); +}