diff --git a/src/base_alloc/base_alloc_global.c b/src/base_alloc/base_alloc_global.c index 1312ad8d5..9193bd91c 100644 --- a/src/base_alloc/base_alloc_global.c +++ b/src/base_alloc/base_alloc_global.c @@ -5,49 +5,116 @@ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ +/* A MT-safe base allocator */ + #include +#include #include #include "base_alloc.h" #include "base_alloc_global.h" +#include "base_alloc_internal.h" #include "utils_concurrency.h" - -#define SIZE_BA_POOL_CHUNK 128 +#include "utils_math.h" // global base allocator used by all providers and pools -static umf_ba_pool_t *BA_pool = NULL; static UTIL_ONCE_FLAG ba_is_initialized = UTIL_ONCE_FLAG_INIT; +// allocation classes need to be powers of 2 +#define ALLOCATION_CLASSES \ + { 16, 32, 64, 128 } +#define NUM_ALLOCATION_CLASSES 4 + +struct base_alloc_t { + size_t ac_sizes[NUM_ALLOCATION_CLASSES]; + umf_ba_pool_t *ac[NUM_ALLOCATION_CLASSES]; + size_t smallest_ac_size_log2; +}; + +static struct base_alloc_t BASE_ALLOC = {.ac_sizes = ALLOCATION_CLASSES}; + +void umf_ba_destroy_global(void) { + for (int i = 0; i < NUM_ALLOCATION_CLASSES; i++) { + if (BASE_ALLOC.ac[i]) { + umf_ba_destroy(BASE_ALLOC.ac[i]); + BASE_ALLOC.ac[i] = NULL; + } + } +} + static void umf_ba_create_global(void) { - assert(BA_pool == NULL); - BA_pool = umf_ba_create(SIZE_BA_POOL_CHUNK); - assert(BA_pool); + for (int i = 0; i < NUM_ALLOCATION_CLASSES; i++) { + // allocation classes need to be powers of 2 + assert(0 == (BASE_ALLOC.ac_sizes[i] & (BASE_ALLOC.ac_sizes[i] - 1))); + BASE_ALLOC.ac[i] = umf_ba_create(BASE_ALLOC.ac_sizes[i]); + if (!BASE_ALLOC.ac[i]) { + fprintf(stderr, + "base_alloc: Error. Cannot create base alloc allocation " + "class for size: %zu\n. Each allocation will fallback to " + "allocating memory from the OS.", + BASE_ALLOC.ac_sizes[i]); + } + } + + size_t smallestSize = BASE_ALLOC.ac_sizes[0]; + BASE_ALLOC.smallest_ac_size_log2 = log2Utils(smallestSize); + #if defined(_WIN32) && !defined(UMF_SHARED_LIBRARY) atexit(umf_ba_destroy_global); #endif } -void umf_ba_destroy_global(void) { - if (BA_pool) { - umf_ba_pool_t *pool = BA_pool; - BA_pool = NULL; - umf_ba_destroy(pool); +// returns index of the allocation class for a given size +static int size_to_idx(size_t size) { + assert(size <= BASE_ALLOC.ac_sizes[NUM_ALLOCATION_CLASSES - 1]); + + if (size <= BASE_ALLOC.ac_sizes[0]) { + return 0; } + + int isPowerOf2 = (0 == (size & (size - 1))); + int index = + (int)(log2Utils(size) + !isPowerOf2 - BASE_ALLOC.smallest_ac_size_log2); + + assert(index >= 0); + assert(index < NUM_ALLOCATION_CLASSES); + + return index; } -umf_ba_pool_t *umf_ba_get_pool(size_t size) { +void *umf_ba_global_alloc(size_t size) { util_init_once(&ba_is_initialized, umf_ba_create_global); - if (!BA_pool) { - return NULL; + if (size > BASE_ALLOC.ac_sizes[NUM_ALLOCATION_CLASSES - 1]) { + fprintf(stderr, + "base_alloc: allocation size larger than the biggest " + "allocation class. Falling back to OS memory allocation.\n"); + return ba_os_alloc(size); } - // TODO: a specific class-size base allocator can be returned here - assert(size <= SIZE_BA_POOL_CHUNK); + int ac_index = size_to_idx(size); + if (!BASE_ALLOC.ac[ac_index]) { + // if creating ac failed, fall back to os allocation + fprintf(stderr, "base_alloc: allocation class not created. Falling " + "back to OS memory allocation.\n"); + return ba_os_alloc(size); + } + + return umf_ba_alloc(BASE_ALLOC.ac[ac_index]); +} + +void umf_ba_global_free(void *ptr, size_t size) { + if (size > BASE_ALLOC.ac_sizes[NUM_ALLOCATION_CLASSES - 1]) { + ba_os_free(ptr, size); + return; + } - if (size > SIZE_BA_POOL_CHUNK) { - return NULL; + int ac_index = size_to_idx(size); + if (!BASE_ALLOC.ac[ac_index]) { + // if creating ac failed, memory must have been allocated by os + ba_os_free(ptr, size); + return; } - return BA_pool; + umf_ba_free(BASE_ALLOC.ac[ac_index], ptr); } diff --git a/src/base_alloc/base_alloc_global.h b/src/base_alloc/base_alloc_global.h index f8ae760e8..2f08533cc 100644 --- a/src/base_alloc/base_alloc_global.h +++ b/src/base_alloc/base_alloc_global.h @@ -14,7 +14,8 @@ extern "C" { #endif -umf_ba_pool_t *umf_ba_get_pool(size_t size); +void *umf_ba_global_alloc(size_t size); +void umf_ba_global_free(void *ptr, size_t size); void umf_ba_destroy_global(void); #ifdef __cplusplus diff --git a/src/memory_pool_default.c b/src/memory_pool_default.c index ef7b52e05..64c4315d6 100644 --- a/src/memory_pool_default.c +++ b/src/memory_pool_default.c @@ -25,26 +25,21 @@ umf_result_t umfPoolCreateInternal(const umf_memory_pool_ops_t *ops, } umf_result_t ret = UMF_RESULT_SUCCESS; - umf_ba_pool_t *base_allocator = umf_ba_get_pool(sizeof(umf_memory_pool_t)); - if (!base_allocator) { - return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; - } - - umf_memory_pool_handle_t pool = umf_ba_alloc(base_allocator); + umf_memory_pool_handle_t pool = + umf_ba_global_alloc(sizeof(umf_memory_pool_t)); if (!pool) { return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; } assert(ops->version == UMF_VERSION_CURRENT); - pool->base_allocator = base_allocator; pool->provider = provider; pool->own_provider = false; pool->ops = *ops; ret = ops->initialize(pool->provider, params, &pool->pool_priv); if (ret != UMF_RESULT_SUCCESS) { - umf_ba_free(base_allocator, pool); + umf_ba_global_free(pool, sizeof(umf_memory_pool_t)); return ret; } @@ -61,7 +56,7 @@ void umfPoolDestroy(umf_memory_pool_handle_t hPool) { umfMemoryProviderDestroy(hProvider); } // TODO: this free keeps memory in base allocator, so it can lead to OOM in some scenarios (it should be optimized) - umf_ba_free(hPool->base_allocator, hPool); + umf_ba_global_free(hPool, sizeof(umf_memory_pool_t)); } umf_result_t umfFree(void *ptr) { diff --git a/src/memory_pool_internal.h b/src/memory_pool_internal.h index bbbae844e..22478b7df 100644 --- a/src/memory_pool_internal.h +++ b/src/memory_pool_internal.h @@ -31,9 +31,6 @@ typedef struct umf_memory_pool_t { umf_memory_provider_handle_t provider; // Tells whether memory provider is owned by the pool. bool own_provider; - - // saved pointer to the global base allocator - umf_ba_pool_t *base_allocator; } umf_memory_pool_t; umf_result_t umfPoolCreateInternal(const umf_memory_pool_ops_t *ops, diff --git a/src/memory_pool_tracking.c b/src/memory_pool_tracking.c index 4c932df5f..8a292cd23 100644 --- a/src/memory_pool_tracking.c +++ b/src/memory_pool_tracking.c @@ -26,12 +26,8 @@ umf_result_t umfPoolCreateInternal(const umf_memory_pool_ops_t *ops, } umf_result_t ret = UMF_RESULT_SUCCESS; - umf_ba_pool_t *base_allocator = umf_ba_get_pool(sizeof(umf_memory_pool_t)); - if (!base_allocator) { - return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; - } - - umf_memory_pool_handle_t pool = umf_ba_alloc(base_allocator); + umf_memory_pool_handle_t pool = + umf_ba_global_alloc(sizeof(umf_memory_pool_t)); if (!pool) { return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; } @@ -44,7 +40,6 @@ umf_result_t umfPoolCreateInternal(const umf_memory_pool_ops_t *ops, goto err_provider_create; } - pool->base_allocator = base_allocator; pool->own_provider = false; pool->ops = *ops; @@ -59,7 +54,7 @@ umf_result_t umfPoolCreateInternal(const umf_memory_pool_ops_t *ops, err_pool_init: umfMemoryProviderDestroy(pool->provider); err_provider_create: - umf_ba_free(base_allocator, pool); + umf_ba_global_free(pool, sizeof(umf_memory_pool_t)); return ret; } @@ -74,7 +69,7 @@ void umfPoolDestroy(umf_memory_pool_handle_t hPool) { // Destroy tracking provider. umfMemoryProviderDestroy(hPool->provider); // TODO: this free keeps memory in base allocator, so it can lead to OOM in some scenarios (it should be optimized) - umf_ba_free(hPool->base_allocator, hPool); + umf_ba_global_free(hPool, sizeof(umf_memory_pool_t)); } umf_result_t umfFree(void *ptr) { diff --git a/src/memory_provider.c b/src/memory_provider.c index f5c7936d8..9cdbe6abb 100644 --- a/src/memory_provider.c +++ b/src/memory_provider.c @@ -22,9 +22,6 @@ typedef struct umf_memory_provider_t { umf_memory_provider_ops_t ops; void *provider_priv; - - // saved pointer to the global base allocator - umf_ba_pool_t *base_allocator; } umf_memory_provider_t; umf_result_t umfMemoryProviderCreate(const umf_memory_provider_ops_t *ops, @@ -35,13 +32,8 @@ umf_result_t umfMemoryProviderCreate(const umf_memory_provider_ops_t *ops, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - umf_ba_pool_t *base_allocator = - umf_ba_get_pool(sizeof(umf_memory_provider_t)); - if (!base_allocator) { - return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; - } - - umf_memory_provider_handle_t provider = umf_ba_alloc(base_allocator); + umf_memory_provider_handle_t provider = + umf_ba_global_alloc(sizeof(umf_memory_provider_t)); if (!provider) { return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; } @@ -49,12 +41,11 @@ umf_result_t umfMemoryProviderCreate(const umf_memory_provider_ops_t *ops, assert(ops->version == UMF_VERSION_CURRENT); provider->ops = *ops; - provider->base_allocator = base_allocator; void *provider_priv; umf_result_t ret = ops->initialize(params, &provider_priv); if (ret != UMF_RESULT_SUCCESS) { - umf_ba_free(base_allocator, provider); + umf_ba_global_free(provider, sizeof(umf_memory_provider_t)); return ret; } @@ -67,7 +58,7 @@ umf_result_t umfMemoryProviderCreate(const umf_memory_provider_ops_t *ops, void umfMemoryProviderDestroy(umf_memory_provider_handle_t hProvider) { hProvider->ops.finalize(hProvider->provider_priv); - umf_ba_free(hProvider->base_allocator, hProvider); + umf_ba_global_free(hProvider, sizeof(umf_memory_provider_t)); } static void diff --git a/src/memory_target.c b/src/memory_target.c index 0999d7013..3bae34092 100644 --- a/src/memory_target.c +++ b/src/memory_target.c @@ -24,27 +24,20 @@ umf_result_t umfMemoryTargetCreate(const umf_memory_target_ops_t *ops, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - umf_ba_pool_t *base_allocator = - umf_ba_get_pool(sizeof(umf_memory_target_t)); - if (!base_allocator) { - return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; - } - umf_memory_target_handle_t target = - (umf_memory_target_t *)umf_ba_alloc(base_allocator); + (umf_memory_target_t *)umf_ba_global_alloc(sizeof(umf_memory_target_t)); if (!target) { return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; } assert(ops->version == UMF_VERSION_CURRENT); - target->base_allocator = base_allocator; target->ops = ops; void *target_priv; umf_result_t ret = ops->initialize(params, &target_priv); if (ret != UMF_RESULT_SUCCESS) { - umf_ba_free(base_allocator, target); + umf_ba_global_free(target, sizeof(umf_memory_target_t)); return ret; } @@ -58,5 +51,5 @@ umf_result_t umfMemoryTargetCreate(const umf_memory_target_ops_t *ops, void umfMemoryTargetDestroy(umf_memory_target_handle_t memoryTarget) { assert(memoryTarget); memoryTarget->ops->finalize(memoryTarget->priv); - umf_ba_free(memoryTarget->base_allocator, memoryTarget); + umf_ba_global_free(memoryTarget, sizeof(umf_memory_target_t)); } diff --git a/src/memory_target.h b/src/memory_target.h index fccd809fe..3183b29ec 100644 --- a/src/memory_target.h +++ b/src/memory_target.h @@ -24,9 +24,6 @@ typedef struct umf_memory_target_ops_t umf_memory_target_ops_t; typedef struct umf_memory_target_t { const umf_memory_target_ops_t *ops; void *priv; - - // saved pointer to the global base allocator - umf_ba_pool_t *base_allocator; } umf_memory_target_t; typedef umf_memory_target_t *umf_memory_target_handle_t; diff --git a/src/memory_targets/memory_target_numa.c b/src/memory_targets/memory_target_numa.c index b2692904a..31bd79318 100644 --- a/src/memory_targets/memory_target_numa.c +++ b/src/memory_targets/memory_target_numa.c @@ -22,9 +22,6 @@ struct numa_memory_target_t { size_t id; - - // saved pointer to the global base allocator - umf_ba_pool_t *base_allocator; }; static umf_result_t numa_initialize(void *params, void **memTarget) { @@ -35,27 +32,19 @@ static umf_result_t numa_initialize(void *params, void **memTarget) { struct umf_numa_memory_target_config_t *config = (struct umf_numa_memory_target_config_t *)params; - umf_ba_pool_t *base_allocator = - umf_ba_get_pool(sizeof(struct numa_memory_target_t)); - if (!base_allocator) { - return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; - } - - struct numa_memory_target_t *numaTarget = umf_ba_alloc(base_allocator); + struct numa_memory_target_t *numaTarget = + umf_ba_global_alloc(sizeof(struct numa_memory_target_t)); if (!numaTarget) { return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; } - numaTarget->base_allocator = base_allocator; numaTarget->id = config->id; *memTarget = numaTarget; return UMF_RESULT_SUCCESS; } static void numa_finalize(void *memTarget) { - struct numa_memory_target_t *numaTarget = - (struct numa_memory_target_t *)memTarget; - umf_ba_free(numaTarget->base_allocator, memTarget); + umf_ba_global_free(memTarget, sizeof(struct numa_memory_target_t)); } // sets maxnode and allocates and initializes mask based on provided memory targets diff --git a/src/memspace.c b/src/memspace.c index fe4515893..60d8834e7 100644 --- a/src/memspace.c +++ b/src/memspace.c @@ -12,6 +12,7 @@ #include +#include "base_alloc_global.h" #include "memory_target.h" #include "memory_target_ops.h" #include "memspace_internal.h" @@ -105,5 +106,5 @@ void umfMemspaceDestroy(umf_memspace_handle_t memspace) { } umf_ba_linear_destroy(memspace->linear_allocator); - umf_ba_free(memspace->base_allocator, memspace); + umf_ba_global_free(memspace, sizeof(struct umf_memspace_t)); } diff --git a/src/memspace_internal.h b/src/memspace_internal.h index 834a68037..07fe1c18c 100644 --- a/src/memspace_internal.h +++ b/src/memspace_internal.h @@ -24,9 +24,6 @@ struct umf_memspace_t { size_t size; umf_memory_target_handle_t *nodes; - // saved pointer to the global base allocator - umf_ba_pool_t *base_allocator; - // own local linear base allocator umf_ba_linear_pool_t *linear_allocator; }; diff --git a/src/memspaces/memspace_numa.c b/src/memspaces/memspace_numa.c index 693ace2a6..89417a2f1 100644 --- a/src/memspaces/memspace_numa.c +++ b/src/memspaces/memspace_numa.c @@ -23,15 +23,9 @@ umfMemspaceCreateFromNumaArray(size_t *nodeIds, size_t numIds, } enum umf_result_t ret = UMF_RESULT_SUCCESS; - - umf_ba_pool_t *base_allocator = - umf_ba_get_pool(sizeof(struct umf_memspace_t)); - if (!base_allocator) { - return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; - } - umf_memspace_handle_t memspace = - (struct umf_memspace_t *)umf_ba_alloc(base_allocator); + (struct umf_memspace_t *)umf_ba_global_alloc( + sizeof(struct umf_memspace_t)); if (!memspace) { return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; } @@ -43,7 +37,6 @@ umfMemspaceCreateFromNumaArray(size_t *nodeIds, size_t numIds, goto err_umf_ba_linear_create; } - memspace->base_allocator = base_allocator; memspace->linear_allocator = linear_allocator; memspace->size = numIds; @@ -75,6 +68,6 @@ umfMemspaceCreateFromNumaArray(size_t *nodeIds, size_t numIds, err_nodes_alloc: umf_ba_linear_destroy(linear_allocator); err_umf_ba_linear_create: - umf_ba_free(base_allocator, memspace); + umf_ba_global_free(memspace, sizeof(struct umf_memspace_t)); return ret; } diff --git a/src/pool/pool_jemalloc.c b/src/pool/pool_jemalloc.c index f3023af78..cd7f0194b 100644 --- a/src/pool/pool_jemalloc.c +++ b/src/pool/pool_jemalloc.c @@ -25,9 +25,6 @@ typedef struct jemalloc_memory_pool_t { umf_memory_provider_handle_t provider; unsigned int arena_index; // index of jemalloc arena - - // saved pointer to the global base allocator - umf_ba_pool_t *base_allocator; } jemalloc_memory_pool_t; static __TLS umf_result_t TLS_last_allocation_error; @@ -362,18 +359,12 @@ static umf_result_t je_initialize(umf_memory_provider_handle_t provider, size_t unsigned_size = sizeof(unsigned); int err; - umf_ba_pool_t *base_allocator = - umf_ba_get_pool(sizeof(jemalloc_memory_pool_t)); - if (!base_allocator) { - return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; - } - - jemalloc_memory_pool_t *pool = umf_ba_alloc(base_allocator); + jemalloc_memory_pool_t *pool = + umf_ba_global_alloc(sizeof(jemalloc_memory_pool_t)); if (!pool) { return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; } - pool->base_allocator = base_allocator; pool->provider = provider; unsigned arena_index; @@ -404,7 +395,7 @@ static umf_result_t je_initialize(umf_memory_provider_handle_t provider, return UMF_RESULT_SUCCESS; err_free_pool: - umf_ba_free(base_allocator, pool); + umf_ba_global_free(pool, sizeof(jemalloc_memory_pool_t)); return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; } @@ -415,7 +406,7 @@ static void je_finalize(void *pool) { snprintf(cmd, sizeof(cmd), "arena.%u.destroy", je_pool->arena_index); mallctl(cmd, NULL, 0, NULL, 0); pool_by_arena_index[je_pool->arena_index] = NULL; - umf_ba_free(je_pool->base_allocator, je_pool); + umf_ba_global_free(je_pool, sizeof(jemalloc_memory_pool_t)); } static size_t je_malloc_usable_size(void *pool, void *ptr) { diff --git a/src/pool/pool_scalable.c b/src/pool/pool_scalable.c index 351f7c798..beb90e405 100644 --- a/src/pool/pool_scalable.c +++ b/src/pool/pool_scalable.c @@ -56,9 +56,6 @@ struct tbb_callbacks { struct tbb_memory_pool { umf_memory_provider_handle_t mem_provider; void *tbb_pool; - - // saved pointer to the global base allocator - umf_ba_pool_t *base_allocator; }; static struct tbb_callbacks g_tbb_ops; @@ -151,19 +148,13 @@ static umf_result_t tbb_pool_initialize(umf_memory_provider_handle_t provider, return UMF_RESULT_ERROR_UNKNOWN; } - umf_ba_pool_t *base_allocator = - umf_ba_get_pool(sizeof(struct tbb_memory_pool)); - if (!base_allocator) { - return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; - } - - struct tbb_memory_pool *pool_data = umf_ba_alloc(base_allocator); + struct tbb_memory_pool *pool_data = + umf_ba_global_alloc(sizeof(struct tbb_memory_pool)); if (!pool_data) { fprintf(stderr, "cannot allocate memory for metadata\n"); return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; } - pool_data->base_allocator = base_allocator; pool_data->mem_provider = provider; int ret = g_tbb_ops.pool_create_v1((intptr_t)pool_data, &policy, &(pool_data->tbb_pool)); @@ -180,7 +171,7 @@ static void tbb_pool_finalize(void *pool) { util_init_once(&tbb_is_initialized, init_tbb_global_state); struct tbb_memory_pool *pool_data = (struct tbb_memory_pool *)pool; g_tbb_ops.pool_destroy(pool_data->tbb_pool); - umf_ba_free(pool_data->base_allocator, pool_data); + umf_ba_global_free(pool_data, sizeof(struct tbb_memory_pool)); } static void *tbb_malloc(void *pool, size_t size) { diff --git a/src/provider/provider_os_memory.c b/src/provider/provider_os_memory.c index 142cf95bd..ec4f0cc9d 100644 --- a/src/provider/provider_os_memory.c +++ b/src/provider/provider_os_memory.c @@ -44,9 +44,6 @@ typedef struct os_memory_provider_t { int traces; // log level of debug traces hwloc_topology_t topo; - - // saved pointer to the global base allocator - umf_ba_pool_t *base_allocator; } os_memory_provider_t; #define TLS_MSG_BUF_LEN 1024 @@ -229,20 +226,14 @@ static umf_result_t os_initialize(void *params, void **provider) { umf_os_memory_provider_params_t *in_params = (umf_os_memory_provider_params_t *)params; - umf_ba_pool_t *base_allocator = - umf_ba_get_pool(sizeof(os_memory_provider_t)); - if (!base_allocator) { - return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; - } - os_memory_provider_t *os_provider = - (os_memory_provider_t *)umf_ba_alloc(base_allocator); + (os_memory_provider_t *)umf_ba_global_alloc( + sizeof(os_memory_provider_t)); if (!os_provider) { return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; } memset(os_provider, 0, sizeof(*os_provider)); - os_provider->base_allocator = base_allocator; int r = hwloc_topology_init(&os_provider->topo); if (r) { @@ -287,7 +278,7 @@ static umf_result_t os_initialize(void *params, void **provider) { err_destroy_hwloc_topology: hwloc_topology_destroy(os_provider->topo); err_free_os_provider: - umf_ba_free(base_allocator, os_provider); + umf_ba_global_free(os_provider, sizeof(os_memory_provider_t)); return ret; } @@ -300,7 +291,7 @@ static void os_finalize(void *provider) { os_memory_provider_t *os_provider = provider; hwloc_bitmap_free(os_provider->nodeset); hwloc_topology_destroy(os_provider->topo); - umf_ba_free(os_provider->base_allocator, os_provider); + umf_ba_global_free(os_provider, sizeof(os_memory_provider_t)); } static umf_result_t os_get_min_page_size(void *provider, void *ptr, diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b54e62daf..137d641df 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -135,3 +135,9 @@ add_umf_test(NAME base_alloc add_umf_test(NAME base_alloc_linear SRCS ${BA_SOURCES_FOR_TEST} test_base_alloc_linear.cpp LIBS umf_utils) +if(LINUX) + # TODO: fix this on windows + add_umf_test(NAME base_alloc_global + SRCS ${BA_SOURCES_FOR_TEST} pools/pool_base_alloc.cpp malloc_compliance_tests.cpp + LIBS umf_utils) +endif() diff --git a/test/common/pool.hpp b/test/common/pool.hpp index 488c27663..c4be6ff16 100644 --- a/test/common/pool.hpp +++ b/test/common/pool.hpp @@ -82,6 +82,22 @@ bool isCallocSupported(umf_memory_pool_handle_t hPool) { return supported; } +bool isAlignedAllocSupported(umf_memory_pool_handle_t hPool) { + static constexpr size_t allocSize = 8; + static constexpr size_t alignment = 8; + auto *ptr = umfPoolAlignedMalloc(hPool, allocSize, alignment); + + if (ptr) { + umfPoolFree(hPool, ptr); + return true; + } else if (umfPoolGetLastAllocationError(hPool) == + UMF_RESULT_ERROR_NOT_SUPPORTED) { + return false; + } else { + throw std::runtime_error("AlignedMalloc failed with unexpected error"); + } +} + typedef struct pool_base_t { umf_result_t initialize(umf_memory_provider_handle_t) noexcept { return UMF_RESULT_SUCCESS; diff --git a/test/common/provider.hpp b/test/common/provider.hpp index 2389d0bf6..20d547a81 100644 --- a/test/common/provider.hpp +++ b/test/common/provider.hpp @@ -63,6 +63,9 @@ typedef struct provider_base_t { const char *get_name() noexcept { return "base"; } } provider_base_t; +umf_memory_provider_ops_t BASE_PROVIDER_OPS = + umf::providerMakeCOps(); + struct provider_malloc : public provider_base_t { umf_result_t alloc(size_t size, size_t align, void **ptr) noexcept { if (!align) { diff --git a/test/poolFixtures.hpp b/test/poolFixtures.hpp index 152476646..522af1c6e 100644 --- a/test/poolFixtures.hpp +++ b/test/poolFixtures.hpp @@ -136,6 +136,9 @@ TEST_P(umfPoolTest, callocFree) { } void pow2AlignedAllocHelper(umf_memory_pool_handle_t pool) { + if (!umf_test::isAlignedAllocSupported(pool)) { + GTEST_SKIP(); + } static constexpr size_t maxAlignment = (1u << 22); static constexpr size_t numAllocs = 4; for (size_t alignment = 1; alignment <= maxAlignment; alignment <<= 1) { diff --git a/test/pools/pool_base_alloc.cpp b/test/pools/pool_base_alloc.cpp new file mode 100644 index 000000000..b25c9ee6b --- /dev/null +++ b/test/pools/pool_base_alloc.cpp @@ -0,0 +1,65 @@ +// Copyright (C) 2023 Intel Corporation +// Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include + +#include "umf/pools/pool_scalable.h" +#include "umf/providers/provider_os_memory.h" + +#include "pool.hpp" +#include "poolFixtures.hpp" +#include "provider.hpp" + +#include "base_alloc_global.h" + +struct base_alloc_pool : public umf_test::pool_base_t { + std::unordered_map sizes; + std::mutex m; + + void *malloc(size_t size) noexcept { + auto *ptr = umf_ba_global_alloc(size); + std::unique_lock l(m); + sizes[ptr] = size; + return ptr; + } + void *calloc(size_t, size_t) noexcept { + umf::getPoolLastStatusRef() = + UMF_RESULT_ERROR_NOT_SUPPORTED; + return NULL; + } + void *realloc(void *, size_t) noexcept { + umf::getPoolLastStatusRef() = + UMF_RESULT_ERROR_NOT_SUPPORTED; + return NULL; + } + void *aligned_malloc(size_t, size_t) noexcept { + umf::getPoolLastStatusRef() = + UMF_RESULT_ERROR_NOT_SUPPORTED; + return NULL; + } + size_t malloc_usable_size(void *ptr) noexcept { + std::unique_lock l(m); + return sizes[ptr]; + } + umf_result_t free(void *ptr) noexcept { + size_t size; + { + std::unique_lock l(m); + size = sizes[ptr]; + } + + umf_ba_global_free(ptr, size); + return UMF_RESULT_SUCCESS; + } + umf_result_t get_last_allocation_error() { + return umf::getPoolLastStatusRef(); + } +}; + +umf_memory_pool_ops_t BA_POOL_OPS = umf::poolMakeCOps(); + +INSTANTIATE_TEST_SUITE_P(baPool, umfPoolTest, + ::testing::Values(poolCreateExtParams{ + &BA_POOL_OPS, nullptr, + &umf_test::BASE_PROVIDER_OPS, nullptr}));