diff --git a/benchmark/multithread.cpp b/benchmark/multithread.cpp index 8239c8cd49..c698ed0452 100644 --- a/benchmark/multithread.cpp +++ b/benchmark/multithread.cpp @@ -117,10 +117,15 @@ int main() { #endif #if defined(UMF_BUILD_LIBUMF_POOL_DISJOINT) - auto disjointParams = umfDisjointPoolParamsDefault(); + umf_disjoint_pool_params_handle_t hDisjointParams = nullptr; + umf_result_t ret = umfDisjointPoolParamsCreate(&hDisjointParams); + if (ret != UMF_RESULT_SUCCESS) { + std::cerr << "disjoint pool params create failed" << std::endl; + return -1; + } std::cout << "disjoint_pool mt_alloc_free: "; - mt_alloc_free(poolCreateExtParams{umfDisjointPoolOps(), &disjointParams, + mt_alloc_free(poolCreateExtParams{umfDisjointPoolOps(), hDisjointParams, umfOsMemoryProviderOps(), &osParams}); #else std::cout << "skipping disjoint_pool mt_alloc_free" << std::endl; @@ -129,5 +134,11 @@ int main() { // ctest looks for "PASSED" in the output std::cout << "PASSED" << std::endl; + ret = umfDisjointPoolParamsDestroy(hDisjointParams); + if (ret != UMF_RESULT_SUCCESS) { + std::cerr << "disjoint pool params destroy failed" << std::endl; + return -1; + } + return 0; } diff --git a/benchmark/ubench.c b/benchmark/ubench.c index 15890d4e91..0ac174de65 100644 --- a/benchmark/ubench.c +++ b/benchmark/ubench.c @@ -260,16 +260,47 @@ UBENCH_EX(simple, disjoint_pool_with_os_memory_provider) { exit(-1); } - umf_disjoint_pool_params_t disjoint_memory_pool_params = {0}; - disjoint_memory_pool_params.SlabMinSize = DISJOINT_POOL_SLAB_MIN_SIZE; - disjoint_memory_pool_params.MaxPoolableSize = - DISJOINT_POOL_MAX_POOLABLE_SIZE; - disjoint_memory_pool_params.Capacity = DISJOINT_POOL_CAPACITY; - disjoint_memory_pool_params.MinBucketSize = DISJOINT_POOL_MIN_BUCKET_SIZE; + umf_disjoint_pool_params_handle_t disjoint_memory_pool_params = NULL; + umf_result = umfDisjointPoolParamsCreate(&disjoint_memory_pool_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "ERROR: umfDisjointPoolParamsCreate failed\n"); + exit(-1); + } + + umf_result = umfDisjointPoolParamsSetSlabMinSize( + disjoint_memory_pool_params, DISJOINT_POOL_SLAB_MIN_SIZE); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, + "error: umfDisjointPoolParamsSetSlabMinSize() failed\n"); + exit(-1); + } + + umf_result = umfDisjointPoolParamsSetMaxPoolableSize( + disjoint_memory_pool_params, DISJOINT_POOL_MAX_POOLABLE_SIZE); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, + "error: umfDisjointPoolParamsSetMaxPoolableSize() failed\n"); + exit(-1); + } + + umf_result = umfDisjointPoolParamsSetCapacity(disjoint_memory_pool_params, + DISJOINT_POOL_CAPACITY); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "error: umfDisjointPoolParamsSetCapacity() failed\n"); + exit(-1); + } + + umf_result = umfDisjointPoolParamsSetMinBucketSize( + disjoint_memory_pool_params, DISJOINT_POOL_MIN_BUCKET_SIZE); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, + "error: umfDisjointPoolParamsSetMinBucketSize() failed\n"); + exit(-1); + } umf_memory_pool_handle_t disjoint_pool; umf_result = umfPoolCreate(umfDisjointPoolOps(), os_memory_provider, - &disjoint_memory_pool_params, 0, &disjoint_pool); + disjoint_memory_pool_params, 0, &disjoint_pool); if (umf_result != UMF_RESULT_SUCCESS) { fprintf(stderr, "error: umfPoolCreate() failed\n"); exit(-1); @@ -284,6 +315,7 @@ UBENCH_EX(simple, disjoint_pool_with_os_memory_provider) { } umfPoolDestroy(disjoint_pool); + umfDisjointPoolParamsDestroy(disjoint_memory_pool_params); umfMemoryProviderDestroy(os_memory_provider); free(array); } @@ -458,19 +490,50 @@ UBENCH_EX(ipc, disjoint_pool_with_level_zero_provider) { goto err_free_ipc_handles; } - umf_disjoint_pool_params_t disjoint_params = {0}; - disjoint_params.SlabMinSize = BUFFER_SIZE * 10; - disjoint_params.MaxPoolableSize = 4ull * 1024ull * 1024ull; - disjoint_params.Capacity = 64ull * 1024ull; - disjoint_params.MinBucketSize = 64; - umf_pool_create_flags_t flags = UMF_POOL_CREATE_FLAG_OWN_PROVIDER; + umf_disjoint_pool_params_handle_t disjoint_params = NULL; + umf_result = umfDisjointPoolParamsCreate(&disjoint_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "ERROR: umfDisjointPoolParamsCreate failed\n"); + goto err_provider_destroy; + } + + umf_result = + umfDisjointPoolParamsSetSlabMinSize(disjoint_params, BUFFER_SIZE * 10); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, + "error: umfDisjointPoolParamsSetSlabMinSize() failed\n"); + goto err_params_destroy; + } + + umf_result = umfDisjointPoolParamsSetMaxPoolableSize( + disjoint_params, 4ull * 1024ull * 1024ull); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, + "error: umfDisjointPoolParamsSetMaxPoolableSize() failed\n"); + goto err_params_destroy; + } + + umf_result = + umfDisjointPoolParamsSetCapacity(disjoint_params, 64ull * 1024ull); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "error: umfDisjointPoolParamsSetCapacity() failed\n"); + goto err_params_destroy; + } + + umf_result = umfDisjointPoolParamsSetMinBucketSize(disjoint_params, 64); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, + "error: umfDisjointPoolParamsSetMinBucketSize() failed\n"); + goto err_params_destroy; + } + + umf_pool_create_flags_t flags = UMF_POOL_CREATE_FLAG_NONE; umf_memory_pool_handle_t pool; - umf_result = umfPoolCreate(umfDisjointPoolOps(), provider, &disjoint_params, + umf_result = umfPoolCreate(umfDisjointPoolOps(), provider, disjoint_params, flags, &pool); if (umf_result != UMF_RESULT_SUCCESS) { fprintf(stderr, "error: umfPoolCreate() failed\n"); - umfMemoryProviderDestroy(provider); - goto err_free_ipc_handles; + goto err_params_destroy; } for (size_t i = 0; i < N_BUFFERS; ++i) { @@ -495,6 +558,12 @@ UBENCH_EX(ipc, disjoint_pool_with_level_zero_provider) { umfPoolDestroy(pool); +err_params_destroy: + umfDisjointPoolParamsDestroy(disjoint_params); + +err_provider_destroy: + umfMemoryProviderDestroy(provider); + err_free_ipc_handles: free(ipc_handles); diff --git a/examples/cuda_shared_memory/cuda_shared_memory.c b/examples/cuda_shared_memory/cuda_shared_memory.c index 55a7dd12f1..22e5e3f10a 100644 --- a/examples/cuda_shared_memory/cuda_shared_memory.c +++ b/examples/cuda_shared_memory/cuda_shared_memory.c @@ -67,23 +67,48 @@ int main(void) { // Setup parameters for the Disjoint Pool. It will be used for managing the // memory allocated using memory provider. - umf_disjoint_pool_params_t disjoint_memory_pool_params = - umfDisjointPoolParamsDefault(); + umf_disjoint_pool_params_handle_t hDisjointParams = NULL; + res = umfDisjointPoolParamsCreate(&hDisjointParams); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "disjoint pool params create failed\n"); + ret = -1; + goto memory_provider_destroy; + } // Set the Slab Min Size to 64KB - the page size for GPU allocations - disjoint_memory_pool_params.SlabMinSize = 64 * 1024L; + res = umfDisjointPoolParamsSetSlabMinSize(hDisjointParams, 64 * 1024L); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to set the slab min size!\n"); + ret = -1; + goto pool_params_destroy; + } // We would keep only single slab per each allocation bucket - disjoint_memory_pool_params.Capacity = 1; + res = umfDisjointPoolParamsSetCapacity(hDisjointParams, 1); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to set the capacity!\n"); + ret = -1; + goto pool_params_destroy; + } // Set the maximum poolable size to 64KB - objects with size above this // limit will not be stored/allocated from the pool. - disjoint_memory_pool_params.MaxPoolableSize = 64 * 1024L; + res = umfDisjointPoolParamsSetMaxPoolableSize(hDisjointParams, 64 * 1024L); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to set the max poolable size!\n"); + ret = -1; + goto pool_params_destroy; + } // Enable tracing - disjoint_memory_pool_params.PoolTrace = 1; + res = umfDisjointPoolParamsSetTrace(hDisjointParams, 1); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to set the pool trace!\n"); + ret = -1; + goto pool_params_destroy; + } // Create Disjoint Pool memory pool. umf_memory_pool_handle_t cu_disjoint_memory_pool; - res = umfPoolCreate(umfDisjointPoolOps(), cu_memory_provider, - &disjoint_memory_pool_params, UMF_POOL_CREATE_FLAG_NONE, - &cu_disjoint_memory_pool); + res = + umfPoolCreate(umfDisjointPoolOps(), cu_memory_provider, hDisjointParams, + UMF_POOL_CREATE_FLAG_NONE, &cu_disjoint_memory_pool); if (res != UMF_RESULT_SUCCESS) { fprintf(stderr, "Failed to create a memory pool!\n"); ret = -1; @@ -116,6 +141,9 @@ int main(void) { memory_pool_destroy: umfPoolDestroy(cu_disjoint_memory_pool); +pool_params_destroy: + umfDisjointPoolParamsDestroy(hDisjointParams); + memory_provider_destroy: umfMemoryProviderDestroy(cu_memory_provider); diff --git a/examples/dram_and_fsdax/dram_and_fsdax.c b/examples/dram_and_fsdax/dram_and_fsdax.c index ac7b0434c2..0d21ce6204 100644 --- a/examples/dram_and_fsdax/dram_and_fsdax.c +++ b/examples/dram_and_fsdax/dram_and_fsdax.c @@ -67,12 +67,23 @@ static umf_memory_pool_handle_t create_fsdax_pool(const char *path) { // so it should be used with a pool manager that will take over // the managing of the provided memory - for example the jemalloc pool // with the `disable_provider_free` parameter set to true. - umf_jemalloc_pool_params_t pool_params; - pool_params.disable_provider_free = true; + umf_jemalloc_pool_params_handle_t pool_params; + umf_result = umfJemallocPoolParamsCreate(&pool_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to create jemalloc params!\n"); + umfMemoryProviderDestroy(provider_fsdax); + return NULL; + } + umf_result = umfJemallocPoolParamsSetKeepAllMemory(pool_params, true); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to set KeepAllMemory!\n"); + umfMemoryProviderDestroy(provider_fsdax); + return NULL; + } // Create an FSDAX memory pool umf_result = - umfPoolCreate(umfJemallocPoolOps(), provider_fsdax, &pool_params, + umfPoolCreate(umfJemallocPoolOps(), provider_fsdax, pool_params, UMF_POOL_CREATE_FLAG_OWN_PROVIDER, &pool_fsdax); if (umf_result != UMF_RESULT_SUCCESS) { fprintf(stderr, "Failed to create an FSDAX memory pool!\n"); @@ -80,6 +91,11 @@ static umf_memory_pool_handle_t create_fsdax_pool(const char *path) { return NULL; } + umf_result = umfJemallocPoolParamsDestroy(pool_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to destroy jemalloc params!\n"); + } + return pool_fsdax; } diff --git a/examples/ipc_level_zero/ipc_level_zero.c b/examples/ipc_level_zero/ipc_level_zero.c index 9a6b4177bd..cfab57b0d9 100644 --- a/examples/ipc_level_zero/ipc_level_zero.c +++ b/examples/ipc_level_zero/ipc_level_zero.c @@ -35,17 +35,29 @@ int create_level_zero_pool(ze_context_handle_t context, return -1; } + umf_disjoint_pool_params_handle_t disjoint_params = NULL; + umf_result = umfDisjointPoolParamsCreate(&disjoint_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "ERROR: Failed to create pool params!\n"); + goto provider_destroy; + } + // create pool umf_pool_create_flags_t flags = UMF_POOL_CREATE_FLAG_OWN_PROVIDER; - umf_disjoint_pool_params_t disjoint_params = umfDisjointPoolParamsDefault(); - umf_result = umfPoolCreate(umfDisjointPoolOps(), provider, &disjoint_params, + umf_result = umfPoolCreate(umfDisjointPoolOps(), provider, disjoint_params, flags, pool); + umfDisjointPoolParamsDestroy(disjoint_params); if (umf_result != UMF_RESULT_SUCCESS) { fprintf(stderr, "ERROR: Failed to create pool!\n"); - return -1; + goto provider_destroy; } return 0; + +provider_destroy: + umfMemoryProviderDestroy(provider); + + return -1; } int main(void) { diff --git a/examples/level_zero_shared_memory/level_zero_shared_memory.c b/examples/level_zero_shared_memory/level_zero_shared_memory.c index 06413a0189..1a38becebb 100644 --- a/examples/level_zero_shared_memory/level_zero_shared_memory.c +++ b/examples/level_zero_shared_memory/level_zero_shared_memory.c @@ -72,27 +72,54 @@ int main(void) { // Setup parameters for the Disjoint Pool. It will be used for managing the // memory allocated using memory provider. - umf_disjoint_pool_params_t disjoint_memory_pool_params = - umfDisjointPoolParamsDefault(); + umf_disjoint_pool_params_handle_t disjoint_memory_pool_params = NULL; + res = umfDisjointPoolParamsCreate(&disjoint_memory_pool_params); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to create pool params!\n"); + ret = -1; + goto memory_provider_destroy; + } // Set the Slab Min Size to 64KB - the page size for GPU allocations - disjoint_memory_pool_params.SlabMinSize = 64 * 1024L; + res = umfDisjointPoolParamsSetSlabMinSize(disjoint_memory_pool_params, + 64 * 1024L); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to set Slab Min Size!\n"); + ret = -1; + goto disjoint_params_destroy; + } // We would keep only single slab per each allocation bucket - disjoint_memory_pool_params.Capacity = 1; + res = umfDisjointPoolParamsSetCapacity(disjoint_memory_pool_params, 1); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to set Capacity!\n"); + ret = -1; + goto disjoint_params_destroy; + } // Set the maximum poolable size to 64KB - objects with size above this // limit will not be stored/allocated from the pool. - disjoint_memory_pool_params.MaxPoolableSize = 64 * 1024L; + res = umfDisjointPoolParamsSetMaxPoolableSize(disjoint_memory_pool_params, + 64 * 1024L); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to set Max Poolable Size!\n"); + ret = -1; + goto disjoint_params_destroy; + } // Enable tracing - disjoint_memory_pool_params.PoolTrace = 1; + res = umfDisjointPoolParamsSetTrace(disjoint_memory_pool_params, 1); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to set Trace!\n"); + ret = -1; + goto disjoint_params_destroy; + } // Create Disjoint Pool memory pool. umf_memory_pool_handle_t ze_disjoint_memory_pool; res = umfPoolCreate(umfDisjointPoolOps(), ze_memory_provider, - &disjoint_memory_pool_params, UMF_POOL_CREATE_FLAG_NONE, + disjoint_memory_pool_params, UMF_POOL_CREATE_FLAG_NONE, &ze_disjoint_memory_pool); if (res != UMF_RESULT_SUCCESS) { fprintf(stderr, "Failed to create a memory pool!\n"); ret = -1; - goto memory_provider_destroy; + goto disjoint_params_destroy; } printf("Disjoint Pool created at %p\n", (void *)ze_disjoint_memory_pool); @@ -121,6 +148,9 @@ int main(void) { memory_pool_destroy: umfPoolDestroy(ze_disjoint_memory_pool); +disjoint_params_destroy: + umfDisjointPoolParamsDestroy(disjoint_memory_pool_params); + memory_provider_destroy: umfMemoryProviderDestroy(ze_memory_provider); diff --git a/include/umf/pools/pool_disjoint.h b/include/umf/pools/pool_disjoint.h index 2fe5355a2d..fdf682ae5b 100644 --- a/include/umf/pools/pool_disjoint.h +++ b/include/umf/pools/pool_disjoint.h @@ -16,68 +16,93 @@ extern "C" { /// i.e. if multiple pools use the same shared limits, sum of those pools' /// sizes cannot exceed MaxSize. typedef struct umf_disjoint_pool_shared_limits_t - umf_disjoint_pool_shared_limits_t; + *umf_disjoint_pool_shared_limits_handle_t; -/// @brief Create a pool limits struct -/// @param MaxSize specifies hard limit for memory allocated from a provider -/// @return pointer to created pool limits struct -umf_disjoint_pool_shared_limits_t * +struct umf_disjoint_pool_params_t; +/// @brief handle to the parameters of the disjoint pool. +typedef struct umf_disjoint_pool_params_t *umf_disjoint_pool_params_handle_t; + +/// @brief Create a pool limits struct. +/// @param MaxSize specifies hard limit for memory allocated from a provider. +/// @return handle to the created shared limits struct. +umf_disjoint_pool_shared_limits_handle_t umfDisjointPoolSharedLimitsCreate(size_t MaxSize); -/// @brief Destroy previously created pool limits struct -/// @param PoolLimits pointer to a pool limits struct +/// @brief Destroy previously created pool limits struct. +/// @param hSharedLimits handle to the shared limits struct. void umfDisjointPoolSharedLimitsDestroy( - umf_disjoint_pool_shared_limits_t *PoolLimits); - -/// @brief Configuration of Disjoint Pool -typedef struct umf_disjoint_pool_params_t { - /// 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; - - /// Allocations up to this limit will be subject to chunking/pooling - size_t MaxPoolableSize; - - /// When pooling, each bucket will hold a max of 'Capacity' unfreed slabs - size_t Capacity; - - /// Holds the minimum bucket size valid for allocation of a memory type. - /// This value must be a power of 2. - size_t MinBucketSize; - - /// Holds size of the pool managed by the allocator. - size_t CurPoolSize; - - /// Whether to print pool usage statistics - int PoolTrace; - - /// Memory limits that can be shared between multitple pool instances, - /// i.e. if multiple pools use the same SharedLimits sum of those pools' - /// sizes cannot exceed MaxSize. - umf_disjoint_pool_shared_limits_t *SharedLimits; - - /// Name used in traces - const char *Name; -} umf_disjoint_pool_params_t; + umf_disjoint_pool_shared_limits_handle_t hSharedLimits); + +/// @brief Create a struct to store parameters of disjoint pool. +/// @param hParams [out] handle to the newly created parameters struct. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t +umfDisjointPoolParamsCreate(umf_disjoint_pool_params_handle_t *hParams); + +/// @brief Destroy parameters struct. +/// @param hParams handle to the parameters of the disjoint pool. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t +umfDisjointPoolParamsDestroy(umf_disjoint_pool_params_handle_t hParams); + +/// @brief Set minimum allocation size that will be requested from the memory provider. +/// @param hParams handle to the parameters of the disjoint pool. +/// @param slabMinSize minimum allocation size. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t +umfDisjointPoolParamsSetSlabMinSize(umf_disjoint_pool_params_handle_t hParams, + size_t slabMinSize); + +/// @brief Set size limit for allocations that are subject to pooling. +/// @param hParams handle to the parameters of the disjoint pool. +/// @param maxPoolableSize maximum poolable size. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfDisjointPoolParamsSetMaxPoolableSize( + umf_disjoint_pool_params_handle_t hParams, size_t maxPoolableSize); + +/// @brief Set maximum capacity of each bucket. Each bucket will hold a +/// max of \p maxCapacity unfreed slabs. +/// @param hParams handle to the parameters of the disjoint pool. +/// @param maxCapacity maximum capacity of each bucket. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t +umfDisjointPoolParamsSetCapacity(umf_disjoint_pool_params_handle_t hParams, + size_t maxCapacity); + +/// @brief Set minimum bucket allocation size. +/// @param hParams handle to the parameters of the disjoint pool. +/// @param minBucketSize minimum bucket size. Must be power of 2. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t +umfDisjointPoolParamsSetMinBucketSize(umf_disjoint_pool_params_handle_t hParams, + size_t minBucketSize); + +/// @brief Set trace level for pool usage statistics. +/// @param hParams handle to the parameters of the disjoint pool. +/// @param poolTrace trace level. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t +umfDisjointPoolParamsSetTrace(umf_disjoint_pool_params_handle_t hParams, + int poolTrace); + +/// @brief Set shared limits for disjoint pool. +/// @param hParams handle to the parameters of the disjoint pool. +/// @param hSharedLimits handle tp the shared limits. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfDisjointPoolParamsSetSharedLimits( + umf_disjoint_pool_params_handle_t hParams, + umf_disjoint_pool_shared_limits_handle_t hSharedLimits); + +/// @brief Set custom name of the disjoint pool to be used in the traces. +/// @param hParams handle to the parameters of the disjoint pool. +/// @param name custom name of the pool. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t +umfDisjointPoolParamsSetName(umf_disjoint_pool_params_handle_t hParams, + const char *name); umf_memory_pool_ops_t *umfDisjointPoolOps(void); -/// @brief Create default params struct for disjoint pool -static inline umf_disjoint_pool_params_t umfDisjointPoolParamsDefault(void) { - umf_disjoint_pool_params_t params = { - 0, /* SlabMinSize */ - 0, /* MaxPoolableSize */ - 0, /* Capacity */ - UMF_DISJOINT_POOL_MIN_BUCKET_DEFAULT_SIZE, /* MinBucketSize */ - 0, /* CurPoolSize */ - 0, /* PoolTrace */ - NULL, /* SharedLimits */ - "disjoint_pool" /* Name */ - }; - - return params; -} - #ifdef __cplusplus } #endif diff --git a/include/umf/pools/pool_jemalloc.h b/include/umf/pools/pool_jemalloc.h index dfd75746b3..0cbecd38f7 100644 --- a/include/umf/pools/pool_jemalloc.h +++ b/include/umf/pools/pool_jemalloc.h @@ -17,11 +17,31 @@ extern "C" { #include #include -/// @brief Configuration of Jemalloc Pool -typedef struct umf_jemalloc_pool_params_t { - /// Set to true if umfMemoryProviderFree() should never be called. - bool disable_provider_free; -} umf_jemalloc_pool_params_t; +struct umf_jemalloc_pool_params_t; + +/// @brief handle to the parameters of the jemalloc pool. +typedef struct umf_jemalloc_pool_params_t *umf_jemalloc_pool_params_handle_t; + +/// @brief Create a struct to store parameters of jemalloc pool. +/// @param hParams [out] handle to the newly created parameters struct. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t +umfJemallocPoolParamsCreate(umf_jemalloc_pool_params_handle_t *hParams); + +/// @brief Destroy parameters struct. +/// @param hParams handle to the parameters of the jemalloc pool. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t +umfJemallocPoolParamsDestroy(umf_jemalloc_pool_params_handle_t hParams); + +/// @brief Set if \p umfMemoryProviderFree() should never be called. +/// @param hParams handle to the parameters of the jemalloc pool. +/// @param keepAllMemory \p true if the jemalloc pool should not call +/// \p umfMemoryProviderFree, \p false otherwise. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t +umfJemallocPoolParamsSetKeepAllMemory(umf_jemalloc_pool_params_handle_t hParams, + bool keepAllMemory); umf_memory_pool_ops_t *umfJemallocPoolOps(void); diff --git a/src/pool/pool_disjoint.cpp b/src/pool/pool_disjoint.cpp index 2cf8df7a4a..e0298b43df 100644 --- a/src/pool/pool_disjoint.cpp +++ b/src/pool/pool_disjoint.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -57,13 +58,43 @@ typedef struct umf_disjoint_pool_shared_limits_t { std::atomic TotalSize; } umf_disjoint_pool_shared_limits_t; +// Configuration of Disjoint Pool +typedef struct umf_disjoint_pool_params_t { + // Minimum allocation size that will be requested from the memory provider. + size_t SlabMinSize; + + // Allocations up to this limit will be subject to chunking/pooling + size_t MaxPoolableSize; + + // When pooling, each bucket will hold a max of 'Capacity' unfreed slabs + size_t Capacity; + + // Holds the minimum bucket size valid for allocation of a memory type. + // This value must be a power of 2. + size_t MinBucketSize; + + // Holds size of the pool managed by the allocator. + size_t CurPoolSize; + + // Whether to print pool usage statistics + int PoolTrace; + + // Memory limits that can be shared between multitple pool instances, + // i.e. if multiple pools use the same SharedLimits sum of those pools' + // sizes cannot exceed MaxSize. + umf_disjoint_pool_shared_limits_handle_t SharedLimits; + + // Name used in traces + char *Name; +} umf_disjoint_pool_params_t; + class DisjointPool { public: class AllocImpl; using Config = umf_disjoint_pool_params_t; umf_result_t initialize(umf_memory_provider_handle_t provider, - umf_disjoint_pool_params_t *parameters); + umf_disjoint_pool_params_handle_t parameters); void *malloc(size_t size); void *calloc(size_t, size_t); void *realloc(void *, size_t); @@ -85,8 +116,151 @@ umfDisjointPoolSharedLimitsCreate(size_t MaxSize) { } void umfDisjointPoolSharedLimitsDestroy( - umf_disjoint_pool_shared_limits_t *limits) { - delete limits; + umf_disjoint_pool_shared_limits_handle_t hSharedLimits) { + delete hSharedLimits; +} + +umf_result_t +umfDisjointPoolParamsCreate(umf_disjoint_pool_params_handle_t *hParams) { + static const char *DEFAULT_NAME = "disjoint_pool"; + + if (!hParams) { + LOG_ERR("disjoint pool params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + umf_disjoint_pool_params_handle_t params = new umf_disjoint_pool_params_t{}; + if (params == nullptr) { + LOG_ERR("cannot allocate memory for disjoint pool params"); + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + params->SlabMinSize = 0; + params->MaxPoolableSize = 0; + params->Capacity = 0; + params->MinBucketSize = UMF_DISJOINT_POOL_MIN_BUCKET_DEFAULT_SIZE; + params->CurPoolSize = 0; + params->PoolTrace = 0; + params->SharedLimits = nullptr; + params->Name = nullptr; + + umf_result_t ret = umfDisjointPoolParamsSetName(params, DEFAULT_NAME); + if (ret != UMF_RESULT_SUCCESS) { + delete params; + return ret; + } + + *hParams = params; + + return UMF_RESULT_SUCCESS; +} + +umf_result_t +umfDisjointPoolParamsDestroy(umf_disjoint_pool_params_handle_t hParams) { + if (hParams) { + delete[] hParams->Name; + delete hParams; + } + + return UMF_RESULT_SUCCESS; +} + +umf_result_t +umfDisjointPoolParamsSetSlabMinSize(umf_disjoint_pool_params_handle_t hParams, + size_t slabMinSize) { + if (!hParams) { + LOG_ERR("disjoint pool params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + hParams->SlabMinSize = slabMinSize; + return UMF_RESULT_SUCCESS; +} + +umf_result_t umfDisjointPoolParamsSetMaxPoolableSize( + umf_disjoint_pool_params_handle_t hParams, size_t maxPoolableSize) { + if (!hParams) { + LOG_ERR("disjoint pool params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + hParams->MaxPoolableSize = maxPoolableSize; + return UMF_RESULT_SUCCESS; +} + +umf_result_t +umfDisjointPoolParamsSetCapacity(umf_disjoint_pool_params_handle_t hParams, + size_t maxCapacity) { + if (!hParams) { + LOG_ERR("disjoint pool params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + hParams->Capacity = maxCapacity; + return UMF_RESULT_SUCCESS; +} + +umf_result_t +umfDisjointPoolParamsSetMinBucketSize(umf_disjoint_pool_params_handle_t hParams, + size_t minBucketSize) { + if (!hParams) { + LOG_ERR("disjoint pool params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + // minBucketSize parameter must be a power of 2 and greater than 0. + if (minBucketSize == 0 || (minBucketSize & (minBucketSize - 1))) { + LOG_ERR("minBucketSize must be a power of 2 and greater than 0"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + hParams->MinBucketSize = minBucketSize; + return UMF_RESULT_SUCCESS; +} + +umf_result_t +umfDisjointPoolParamsSetTrace(umf_disjoint_pool_params_handle_t hParams, + int poolTrace) { + if (!hParams) { + LOG_ERR("disjoint pool params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + hParams->PoolTrace = poolTrace; + return UMF_RESULT_SUCCESS; +} + +umf_result_t umfDisjointPoolParamsSetSharedLimits( + umf_disjoint_pool_params_handle_t hParams, + umf_disjoint_pool_shared_limits_handle_t hSharedLimits) { + if (!hParams) { + LOG_ERR("disjoint pool params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + hParams->SharedLimits = hSharedLimits; + return UMF_RESULT_SUCCESS; +} + +umf_result_t +umfDisjointPoolParamsSetName(umf_disjoint_pool_params_handle_t hParams, + const char *name) { + if (!hParams) { + LOG_ERR("disjoint pool params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + char *newName = new char[std::strlen(name) + 1]; + if (newName == nullptr) { + LOG_ERR("cannot allocate memory for disjoint pool name"); + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + delete[] hParams->Name; + hParams->Name = newName; + std::strcpy(hParams->Name, name); + + return UMF_RESULT_SUCCESS; } // Allocations are a minimum of 4KB/64KB/2MB even when a smaller size is @@ -351,11 +525,15 @@ class DisjointPool::AllocImpl { public: AllocImpl(umf_memory_provider_handle_t hProvider, - umf_disjoint_pool_params_t *params) + umf_disjoint_pool_params_handle_t params) : MemHandle{hProvider}, params(*params) { VALGRIND_DO_CREATE_MEMPOOL(this, 0, 0); + // deep copy of the Name + this->params.Name = new char[std::strlen(params->Name) + 1]; + std::strcpy(this->params.Name, params->Name); + // Generate buckets sized such as: 64, 96, 128, 192, ..., CutOff. // Powers of 2 and the value halfway between the powers of 2. auto Size1 = this->params.MinBucketSize; @@ -379,7 +557,10 @@ class DisjointPool::AllocImpl { } } - ~AllocImpl() { VALGRIND_DO_DESTROY_MEMPOOL(this); } + ~AllocImpl() { + VALGRIND_DO_DESTROY_MEMPOOL(this); + delete[] this->params.Name; + } void *allocate(size_t Size, size_t Alignment, bool &FromPool); void *allocate(size_t Size, bool &FromPool); @@ -1015,8 +1196,9 @@ void DisjointPool::AllocImpl::printStats(bool &TitlePrinted, } } -umf_result_t DisjointPool::initialize(umf_memory_provider_handle_t provider, - umf_disjoint_pool_params_t *parameters) { +umf_result_t +DisjointPool::initialize(umf_memory_provider_handle_t provider, + umf_disjoint_pool_params_handle_t parameters) { if (!provider) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; } diff --git a/src/pool/pool_jemalloc.c b/src/pool/pool_jemalloc.c index fa1022e83c..3ec7c78050 100644 --- a/src/pool/pool_jemalloc.c +++ b/src/pool/pool_jemalloc.c @@ -41,6 +41,12 @@ typedef struct jemalloc_memory_pool_t { bool disable_provider_free; } jemalloc_memory_pool_t; +// Configuration of Jemalloc Pool +typedef struct umf_jemalloc_pool_params_t { + /// Set to true if umfMemoryProviderFree() should never be called. + bool disable_provider_free; +} umf_jemalloc_pool_params_t; + static __TLS umf_result_t TLS_last_allocation_error; static jemalloc_memory_pool_t *pool_by_arena_index[MALLCTL_ARENAS_ALL]; @@ -53,6 +59,52 @@ static jemalloc_memory_pool_t *get_pool_by_arena_index(unsigned arena_ind) { return pool_by_arena_index[arena_ind]; } +umf_result_t +umfJemallocPoolParamsCreate(umf_jemalloc_pool_params_handle_t *hParams) { + if (!hParams) { + LOG_ERR("jemalloc pool params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + umf_jemalloc_pool_params_t *params_data = + umf_ba_global_alloc(sizeof(*params_data)); + if (!params_data) { + LOG_ERR("cannot allocate memory for jemalloc poolparams"); + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + params_data->disable_provider_free = false; + + *hParams = (umf_jemalloc_pool_params_handle_t)params_data; + + return UMF_RESULT_SUCCESS; +} + +umf_result_t +umfJemallocPoolParamsDestroy(umf_jemalloc_pool_params_handle_t hParams) { + if (!hParams) { + LOG_ERR("jemalloc pool params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + umf_ba_global_free(hParams); + + return UMF_RESULT_SUCCESS; +} + +umf_result_t +umfJemallocPoolParamsSetKeepAllMemory(umf_jemalloc_pool_params_handle_t hParams, + bool keepAllMemory) { + if (!hParams) { + LOG_ERR("jemalloc pool params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + hParams->disable_provider_free = keepAllMemory; + + return UMF_RESULT_SUCCESS; +} + // arena_extent_alloc - an extent allocation function conforms to the extent_alloc_t type and upon // success returns a pointer to size bytes of mapped memory on behalf of arena arena_ind such that // the extent's base address is a multiple of alignment, as well as setting *zero to indicate @@ -401,8 +453,8 @@ static umf_result_t op_initialize(umf_memory_provider_handle_t provider, assert(provider); assert(out_pool); - umf_jemalloc_pool_params_t *je_params = - (umf_jemalloc_pool_params_t *)params; + umf_jemalloc_pool_params_handle_t je_params = + (umf_jemalloc_pool_params_handle_t)params; extent_hooks_t *pHooks = &arena_extent_hooks; size_t unsigned_size = sizeof(unsigned); diff --git a/test/c_api/disjoint_pool.c b/test/c_api/disjoint_pool.c index 13cd65ab05..4d4634def1 100644 --- a/test/c_api/disjoint_pool.c +++ b/test/c_api/disjoint_pool.c @@ -13,12 +13,16 @@ void test_disjoint_pool_default_params(void) { umf_memory_provider_handle_t provider = nullProviderCreate(); umf_result_t retp; umf_memory_pool_handle_t pool = NULL; - umf_disjoint_pool_params_t params = umfDisjointPoolParamsDefault(); - retp = umfPoolCreate(umfDisjointPoolOps(), provider, ¶ms, 0, &pool); + umf_disjoint_pool_params_handle_t params = NULL; + + retp = umfDisjointPoolParamsCreate(¶ms); + UT_ASSERTeq(retp, UMF_RESULT_SUCCESS); + retp = umfPoolCreate(umfDisjointPoolOps(), provider, params, 0, &pool); UT_ASSERTeq(retp, UMF_RESULT_SUCCESS); umfPoolDestroy(pool); + umfDisjointPoolParamsDestroy(params); umfMemoryProviderDestroy(provider); } @@ -26,19 +30,25 @@ void test_disjoint_pool_shared_limits(void) { umf_memory_provider_handle_t provider = nullProviderCreate(); umf_result_t retp; umf_memory_pool_handle_t pool = NULL; - umf_disjoint_pool_params_t params = umfDisjointPoolParamsDefault(); + umf_disjoint_pool_params_handle_t params = NULL; + + retp = umfDisjointPoolParamsCreate(¶ms); + UT_ASSERTeq(retp, UMF_RESULT_SUCCESS); - umf_disjoint_pool_shared_limits_t *limits = + umf_disjoint_pool_shared_limits_handle_t limits = umfDisjointPoolSharedLimitsCreate(1024); - params.SharedLimits = limits; + UT_ASSERTne(limits, NULL); - retp = umfPoolCreate(umfDisjointPoolOps(), provider, ¶ms, 0, &pool); + retp = umfDisjointPoolParamsSetSharedLimits(params, limits); + UT_ASSERTeq(retp, UMF_RESULT_SUCCESS); + retp = umfPoolCreate(umfDisjointPoolOps(), provider, ¶ms, 0, &pool); UT_ASSERTeq(retp, UMF_RESULT_SUCCESS); umfPoolDestroy(pool); umfMemoryProviderDestroy(provider); umfDisjointPoolSharedLimitsDestroy(limits); + umfDisjointPoolParamsDestroy(params); } int main(void) { diff --git a/test/c_api/multi_pool.c b/test/c_api/multi_pool.c index 9b5f73e774..518f992ea2 100644 --- a/test/c_api/multi_pool.c +++ b/test/c_api/multi_pool.c @@ -17,10 +17,16 @@ umf_memory_pool_handle_t createDisjointPool(umf_memory_provider_handle_t provider) { umf_memory_pool_handle_t pool = NULL; - umf_disjoint_pool_params_t params = umfDisjointPoolParamsDefault(); - umf_result_t ret = - umfPoolCreate(umfDisjointPoolOps(), provider, ¶ms, 0, &pool); + umf_disjoint_pool_params_handle_t params = NULL; + + umf_result_t ret = umfDisjointPoolParamsCreate(¶ms); + UT_ASSERTeq(ret, UMF_RESULT_SUCCESS); + + ret = umfPoolCreate(umfDisjointPoolOps(), provider, params, 0, &pool); UT_ASSERTeq(ret, UMF_RESULT_SUCCESS); + + umfDisjointPoolParamsDestroy(params); + return pool; } diff --git a/test/disjointCoarseMallocPool.cpp b/test/disjointCoarseMallocPool.cpp index 3c5ec6166d..32e1d24f36 100644 --- a/test/disjointCoarseMallocPool.cpp +++ b/test/disjointCoarseMallocPool.cpp @@ -68,20 +68,34 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_basic) { ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(coarse_memory_provider, nullptr); - umf_disjoint_pool_params_t disjoint_memory_pool_params = {}; - disjoint_memory_pool_params.SlabMinSize = 4096; - disjoint_memory_pool_params.MaxPoolableSize = 4096; - disjoint_memory_pool_params.Capacity = 4; - disjoint_memory_pool_params.MinBucketSize = 64; - disjoint_memory_pool_params.PoolTrace = 1; + umf_disjoint_pool_params_handle_t disjoint_pool_params = NULL; + umf_result = umfDisjointPoolParamsCreate(&disjoint_pool_params); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(disjoint_pool_params, nullptr); + umf_result = + umfDisjointPoolParamsSetSlabMinSize(disjoint_pool_params, 4096); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = + umfDisjointPoolParamsSetMaxPoolableSize(disjoint_pool_params, 4096); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = umfDisjointPoolParamsSetCapacity(disjoint_pool_params, 4); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = + umfDisjointPoolParamsSetMinBucketSize(disjoint_pool_params, 64); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = umfDisjointPoolParamsSetTrace(disjoint_pool_params, 1); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); umf_memory_pool_handle_t pool; umf_result = umfPoolCreate(umfDisjointPoolOps(), coarse_memory_provider, - &disjoint_memory_pool_params, + disjoint_pool_params, UMF_POOL_CREATE_FLAG_OWN_PROVIDER, &pool); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(pool, nullptr); + umf_result = umfDisjointPoolParamsDestroy(disjoint_pool_params); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + // test umf_memory_provider_handle_t prov = NULL; @@ -245,20 +259,33 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_simple1) { ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(coarse_memory_provider, nullptr); - umf_disjoint_pool_params_t disjoint_memory_pool_params = {}; - disjoint_memory_pool_params.SlabMinSize = 4096; - disjoint_memory_pool_params.MaxPoolableSize = 4096; - disjoint_memory_pool_params.Capacity = 4; - disjoint_memory_pool_params.MinBucketSize = 64; - disjoint_memory_pool_params.PoolTrace = 1; + umf_disjoint_pool_params_handle_t disjoint_pool_params = NULL; + umf_result = umfDisjointPoolParamsCreate(&disjoint_pool_params); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(disjoint_pool_params, nullptr); + umf_result = + umfDisjointPoolParamsSetSlabMinSize(disjoint_pool_params, 4096); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = + umfDisjointPoolParamsSetMaxPoolableSize(disjoint_pool_params, 4096); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = umfDisjointPoolParamsSetCapacity(disjoint_pool_params, 4); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = + umfDisjointPoolParamsSetMinBucketSize(disjoint_pool_params, 64); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = umfDisjointPoolParamsSetTrace(disjoint_pool_params, 1); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); umf_memory_pool_handle_t pool; - umf_result = umfPoolCreate(umfDisjointPoolOps(), coarse_memory_provider, - &disjoint_memory_pool_params, - UMF_POOL_CREATE_FLAG_NONE, &pool); + umf_result = + umfPoolCreate(umfDisjointPoolOps(), coarse_memory_provider, + disjoint_pool_params, UMF_POOL_CREATE_FLAG_NONE, &pool); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(pool, nullptr); + umf_result = umfDisjointPoolParamsDestroy(disjoint_pool_params); + umf_memory_provider_handle_t prov = NULL; umfPoolGetMemoryProvider(pool, &prov); ASSERT_NE(prov, nullptr); @@ -342,20 +369,34 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_simple2) { ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(coarse_memory_provider, nullptr); - umf_disjoint_pool_params_t disjoint_memory_pool_params = {}; - disjoint_memory_pool_params.SlabMinSize = 4096; - disjoint_memory_pool_params.MaxPoolableSize = 4096; - disjoint_memory_pool_params.Capacity = 4; - disjoint_memory_pool_params.MinBucketSize = 64; - disjoint_memory_pool_params.PoolTrace = 1; + umf_disjoint_pool_params_handle_t disjoint_pool_params = NULL; + umf_result = umfDisjointPoolParamsCreate(&disjoint_pool_params); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(disjoint_pool_params, nullptr); + umf_result = + umfDisjointPoolParamsSetSlabMinSize(disjoint_pool_params, 4096); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = + umfDisjointPoolParamsSetMaxPoolableSize(disjoint_pool_params, 4096); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = umfDisjointPoolParamsSetCapacity(disjoint_pool_params, 4); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = + umfDisjointPoolParamsSetMinBucketSize(disjoint_pool_params, 64); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = umfDisjointPoolParamsSetTrace(disjoint_pool_params, 1); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); umf_memory_pool_handle_t pool; - umf_result = umfPoolCreate(umfDisjointPoolOps(), coarse_memory_provider, - &disjoint_memory_pool_params, - UMF_POOL_CREATE_FLAG_NONE, &pool); + umf_result = + umfPoolCreate(umfDisjointPoolOps(), coarse_memory_provider, + disjoint_pool_params, UMF_POOL_CREATE_FLAG_NONE, &pool); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(pool, nullptr); + umf_result = umfDisjointPoolParamsDestroy(disjoint_pool_params); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + // test double sizes[] = {2, 4, 0.5, 1, 8, 0.25}; size_t alignment[] = {0, 4, 0, 16, 32, 128}; @@ -419,20 +460,34 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMMapPool_random) { ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(coarse_memory_provider, nullptr); - umf_disjoint_pool_params_t disjoint_memory_pool_params = {}; - disjoint_memory_pool_params.SlabMinSize = 1024; - disjoint_memory_pool_params.MaxPoolableSize = 1024; - disjoint_memory_pool_params.Capacity = 2; - disjoint_memory_pool_params.MinBucketSize = 16; - disjoint_memory_pool_params.PoolTrace = 1; + umf_disjoint_pool_params_handle_t disjoint_pool_params = NULL; + umf_result = umfDisjointPoolParamsCreate(&disjoint_pool_params); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(disjoint_pool_params, nullptr); + umf_result = + umfDisjointPoolParamsSetSlabMinSize(disjoint_pool_params, 1024); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = + umfDisjointPoolParamsSetMaxPoolableSize(disjoint_pool_params, 1024); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = umfDisjointPoolParamsSetCapacity(disjoint_pool_params, 2); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = + umfDisjointPoolParamsSetMinBucketSize(disjoint_pool_params, 16); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = umfDisjointPoolParamsSetTrace(disjoint_pool_params, 1); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); umf_memory_pool_handle_t pool; - umf_result = umfPoolCreate(umfDisjointPoolOps(), coarse_memory_provider, - &disjoint_memory_pool_params, - UMF_POOL_CREATE_FLAG_NONE, &pool); + umf_result = + umfPoolCreate(umfDisjointPoolOps(), coarse_memory_provider, + disjoint_pool_params, UMF_POOL_CREATE_FLAG_NONE, &pool); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(pool, nullptr); + umf_result = umfDisjointPoolParamsDestroy(disjoint_pool_params); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + // set constant seed so each test run will have the same scenario uint32_t seed = 1234; std::mt19937 mt(seed); diff --git a/test/pools/disjoint_pool.cpp b/test/pools/disjoint_pool.cpp index 5f048a7e60..319997c823 100644 --- a/test/pools/disjoint_pool.cpp +++ b/test/pools/disjoint_pool.cpp @@ -2,6 +2,8 @@ // Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include + #include "pool.hpp" #include "poolFixtures.hpp" #include "pool_disjoint.h" @@ -9,13 +11,43 @@ #include "provider_null.h" #include "provider_trace.h" -umf_disjoint_pool_params_t poolConfig() { - umf_disjoint_pool_params_t config{}; - config.SlabMinSize = 4096; - config.MaxPoolableSize = 4096; - config.Capacity = 4; - config.MinBucketSize = 64; - return config; +using disjoint_params_unique_handle_t = + std::unique_ptr; + +static constexpr size_t DEFAULT_DISJOINT_SLAB_MIN_SIZE = 4096; +static constexpr size_t DEFAULT_DISJOINT_MAX_POOLABLE_SIZE = 4096; +static constexpr size_t DEFAULT_DISJOINT_CAPACITY = 4; +static constexpr size_t DEFAULT_DISJOINT_MIN_BUCKET_SIZE = 64; + +disjoint_params_unique_handle_t poolConfig() { + umf_disjoint_pool_params_handle_t config = nullptr; + umf_result_t res = umfDisjointPoolParamsCreate(&config); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error("Failed to create pool params"); + } + res = umfDisjointPoolParamsSetSlabMinSize(config, + DEFAULT_DISJOINT_SLAB_MIN_SIZE); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error("Failed to set slab min size"); + } + res = umfDisjointPoolParamsSetMaxPoolableSize( + config, DEFAULT_DISJOINT_MAX_POOLABLE_SIZE); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error("Failed to set max poolable size"); + } + res = umfDisjointPoolParamsSetCapacity(config, DEFAULT_DISJOINT_CAPACITY); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error("Failed to set capacity"); + } + res = umfDisjointPoolParamsSetMinBucketSize( + config, DEFAULT_DISJOINT_MIN_BUCKET_SIZE); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error("Failed to set min bucket size"); + } + + return disjoint_params_unique_handle_t(config, + &umfDisjointPoolParamsDestroy); } using umf_test::test; @@ -47,12 +79,14 @@ TEST_F(test, freeErrorPropagation) { provider_handle = providerUnique.get(); // force all allocations to go to memory provider - umf_disjoint_pool_params_t params = poolConfig(); - params.MaxPoolableSize = 0; + disjoint_params_unique_handle_t params = poolConfig(); + umf_result_t retp = + umfDisjointPoolParamsSetMaxPoolableSize(params.get(), 0); + EXPECT_EQ(retp, UMF_RESULT_SUCCESS); umf_memory_pool_handle_t pool = NULL; - umf_result_t retp = - umfPoolCreate(umfDisjointPoolOps(), provider_handle, ¶ms, 0, &pool); + retp = umfPoolCreate(umfDisjointPoolOps(), provider_handle, params.get(), 0, + &pool); EXPECT_EQ(retp, UMF_RESULT_SUCCESS); auto poolHandle = umf_test::wrapPoolUnique(pool); @@ -92,8 +126,10 @@ TEST_F(test, sharedLimits) { static constexpr size_t SlabMinSize = 1024; static constexpr size_t MaxSize = 4 * SlabMinSize; - auto config = poolConfig(); - config.SlabMinSize = SlabMinSize; + disjoint_params_unique_handle_t config = poolConfig(); + umf_result_t ret = + umfDisjointPoolParamsSetSlabMinSize(config.get(), SlabMinSize); + EXPECT_EQ(ret, UMF_RESULT_SUCCESS); auto limits = std::unique_ptr(defaultPoolConfig.Capacity) / 2))); +INSTANTIATE_TEST_SUITE_P(disjointPoolTests, umfMemTest, + ::testing::Values(std::make_tuple( + poolCreateExtParams{ + umfDisjointPoolOps(), + (void *)defaultPoolConfig.get(), + &MOCK_OUT_OF_MEM_PROVIDER_OPS, + (void *)&DEFAULT_DISJOINT_CAPACITY, nullptr}, + static_cast(DEFAULT_DISJOINT_CAPACITY) / 2))); INSTANTIATE_TEST_SUITE_P(disjointMultiPoolTests, umfMultiPoolTest, ::testing::Values(poolCreateExtParams{ - umfDisjointPoolOps(), (void *)&defaultPoolConfig, + umfDisjointPoolOps(), + (void *)defaultPoolConfig.get(), &BA_GLOBAL_PROVIDER_OPS, nullptr, nullptr})); diff --git a/test/pools/jemalloc_pool.cpp b/test/pools/jemalloc_pool.cpp index 8659e9836a..3a78c53714 100644 --- a/test/pools/jemalloc_pool.cpp +++ b/test/pools/jemalloc_pool.cpp @@ -42,3 +42,122 @@ TEST_F(test, metadataNotAllocatedUsingProvider) { [pool = pool.get()](void *ptr) { umfPoolFree(pool, ptr); }); } } + +using jemallocPoolParams = bool; +struct umfJemallocPoolParamsTest + : umf_test::test, + ::testing::WithParamInterface { + + struct validation_params_t { + bool keep_all_memory; + }; + + struct provider_validator : public umf_test::provider_ba_global { + using base_provider = umf_test::provider_ba_global; + + umf_result_t initialize(validation_params_t *params) { + EXPECT_NE(params, nullptr); + expected_params = params; + return UMF_RESULT_SUCCESS; + } + umf_result_t free(void *ptr, size_t size) { + EXPECT_EQ(expected_params->keep_all_memory, false); + return base_provider::free(ptr, size); + } + + validation_params_t *expected_params; + }; + + static constexpr umf_memory_provider_ops_t VALIDATOR_PROVIDER_OPS = + umf::providerMakeCOps(); + + umfJemallocPoolParamsTest() : expected_params{false}, params(nullptr) {} + void SetUp() override { + test::SetUp(); + expected_params.keep_all_memory = this->GetParam(); + umf_result_t ret = umfJemallocPoolParamsCreate(¶ms); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ret = umfJemallocPoolParamsSetKeepAllMemory( + params, expected_params.keep_all_memory); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + } + + void TearDown() override { + umfJemallocPoolParamsDestroy(params); + test::TearDown(); + } + + umf::pool_unique_handle_t makePool() { + umf_memory_provider_handle_t hProvider = nullptr; + umf_memory_pool_handle_t hPool = nullptr; + + auto ret = umfMemoryProviderCreate(&VALIDATOR_PROVIDER_OPS, + &expected_params, &hProvider); + EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + + ret = umfPoolCreate(umfJemallocPoolOps(), hProvider, params, + UMF_POOL_CREATE_FLAG_OWN_PROVIDER, &hPool); + EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + + return umf::pool_unique_handle_t(hPool, &umfPoolDestroy); + } + + void allocFreeFlow() { + static const size_t ALLOC_SIZE = 128; + static const size_t NUM_ALLOCATIONS = 100; + std::vector ptrs; + + auto pool = makePool(); + ASSERT_NE(pool, nullptr); + + for (size_t i = 0; i < NUM_ALLOCATIONS; ++i) { + auto *ptr = umfPoolMalloc(pool.get(), ALLOC_SIZE); + ASSERT_NE(ptr, nullptr); + ptrs.push_back(ptr); + } + + for (size_t i = 0; i < NUM_ALLOCATIONS; ++i) { + auto ret = umfPoolFree(pool.get(), ptrs[i]); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + } + + // Now pool can call free during pool destruction + expected_params.keep_all_memory = false; + } + + validation_params_t expected_params; + umf_jemalloc_pool_params_handle_t params; +}; + +TEST_P(umfJemallocPoolParamsTest, allocFree) { allocFreeFlow(); } + +TEST_P(umfJemallocPoolParamsTest, updateParams) { + expected_params.keep_all_memory = !expected_params.keep_all_memory; + umf_result_t ret = umfJemallocPoolParamsSetKeepAllMemory( + params, expected_params.keep_all_memory); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + allocFreeFlow(); +} + +TEST_P(umfJemallocPoolParamsTest, invalidParams) { + umf_result_t ret = umfJemallocPoolParamsCreate(nullptr); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + ret = umfJemallocPoolParamsSetKeepAllMemory(nullptr, true); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + ret = umfJemallocPoolParamsSetKeepAllMemory(nullptr, false); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + ret = umfJemallocPoolParamsDestroy(nullptr); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(umfJemallocPoolParamsTest); + +/* TODO: enable this test after the issue #903 is fixed. +(https://github.com/oneapi-src/unified-memory-framework/issues/903) +INSTANTIATE_TEST_SUITE_P(jemallocPoolTest, umfJemallocPoolParamsTest, + testing::Values(false, true)); +*/ diff --git a/test/provider_os_memory.cpp b/test/provider_os_memory.cpp index 3c3cb7c7b1..fc6469a0d8 100644 --- a/test/provider_os_memory.cpp +++ b/test/provider_os_memory.cpp @@ -9,8 +9,10 @@ #include "test_helpers.h" #include -#include #include +#if (defined UMF_POOL_DISJOINT_ENABLED) +#include +#endif #ifdef UMF_POOL_JEMALLOC_ENABLED #include #endif @@ -383,19 +385,43 @@ auto os_params = osMemoryProviderParamsShared(); HostMemoryAccessor hostAccessor; -umf_disjoint_pool_params_t disjointPoolParams() { - umf_disjoint_pool_params_t params = umfDisjointPoolParamsDefault(); - params.SlabMinSize = 4096; - params.MaxPoolableSize = 4096; - params.Capacity = 4; - params.MinBucketSize = 64; - return params; +#if (defined UMF_POOL_DISJOINT_ENABLED) +using disjoint_params_unique_handle_t = + std::unique_ptr; + +disjoint_params_unique_handle_t disjointPoolParams() { + umf_disjoint_pool_params_handle_t params = nullptr; + umf_result_t res = umfDisjointPoolParamsCreate(¶ms); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error("Failed to create pool params"); + } + res = umfDisjointPoolParamsSetSlabMinSize(params, 4096); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error("Failed to set slab min size"); + } + res = umfDisjointPoolParamsSetMaxPoolableSize(params, 4096); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error("Failed to set max poolable size"); + } + res = umfDisjointPoolParamsSetCapacity(params, 4); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error("Failed to set capacity"); + } + res = umfDisjointPoolParamsSetMinBucketSize(params, 64); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error("Failed to set min bucket size"); + } + + return disjoint_params_unique_handle_t(params, + &umfDisjointPoolParamsDestroy); } -umf_disjoint_pool_params_t disjointParams = disjointPoolParams(); +disjoint_params_unique_handle_t disjointParams = disjointPoolParams(); +#endif static std::vector ipcTestParamsList = { #if (defined UMF_POOL_DISJOINT_ENABLED) - {umfDisjointPoolOps(), &disjointParams, umfOsMemoryProviderOps(), + {umfDisjointPoolOps(), disjointParams.get(), umfOsMemoryProviderOps(), &os_params, &hostAccessor, false}, #endif #ifdef UMF_POOL_JEMALLOC_ENABLED diff --git a/test/providers/ipc_cuda_prov_consumer.c b/test/providers/ipc_cuda_prov_consumer.c index 5be6785a15..3286cee28f 100644 --- a/test/providers/ipc_cuda_prov_consumer.c +++ b/test/providers/ipc_cuda_prov_consumer.c @@ -26,9 +26,19 @@ int main(int argc, char *argv[]) { cuda_memory_provider_params_t cu_params = create_cuda_prov_params(UMF_MEMORY_TYPE_DEVICE); - umf_disjoint_pool_params_t pool_params = umfDisjointPoolParamsDefault(); + umf_disjoint_pool_params_handle_t pool_params = NULL; - return run_consumer(port, umfDisjointPoolOps(), &pool_params, - umfCUDAMemoryProviderOps(), &cu_params, memcopy, - &cu_params); + umf_result_t umf_result = umfDisjointPoolParamsCreate(&pool_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to create pool params!\n"); + return -1; + } + + int ret = run_consumer(port, umfDisjointPoolOps(), pool_params, + umfCUDAMemoryProviderOps(), &cu_params, memcopy, + &cu_params); + + umfDisjointPoolParamsDestroy(pool_params); + + return ret; } diff --git a/test/providers/ipc_cuda_prov_producer.c b/test/providers/ipc_cuda_prov_producer.c index bd4673ce7c..d11004d6d4 100644 --- a/test/providers/ipc_cuda_prov_producer.c +++ b/test/providers/ipc_cuda_prov_producer.c @@ -26,9 +26,19 @@ int main(int argc, char *argv[]) { cuda_memory_provider_params_t cu_params = create_cuda_prov_params(UMF_MEMORY_TYPE_DEVICE); - umf_disjoint_pool_params_t pool_params = umfDisjointPoolParamsDefault(); + umf_disjoint_pool_params_handle_t pool_params = NULL; - return run_producer(port, umfDisjointPoolOps(), &pool_params, - umfCUDAMemoryProviderOps(), &cu_params, memcopy, - &cu_params); + umf_result_t umf_result = umfDisjointPoolParamsCreate(&pool_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to create pool params!\n"); + return -1; + } + + int ret = run_producer(port, umfDisjointPoolOps(), pool_params, + umfCUDAMemoryProviderOps(), &cu_params, memcopy, + &cu_params); + + umfDisjointPoolParamsDestroy(pool_params); + + return ret; } diff --git a/test/providers/ipc_level_zero_prov_consumer.c b/test/providers/ipc_level_zero_prov_consumer.c index 70b72a7fc1..4ec952f4fa 100644 --- a/test/providers/ipc_level_zero_prov_consumer.c +++ b/test/providers/ipc_level_zero_prov_consumer.c @@ -26,9 +26,19 @@ int main(int argc, char *argv[]) { level_zero_memory_provider_params_t l0_params = create_level_zero_prov_params(UMF_MEMORY_TYPE_DEVICE); - umf_disjoint_pool_params_t pool_params = umfDisjointPoolParamsDefault(); + umf_disjoint_pool_params_handle_t pool_params = NULL; - return run_consumer(port, umfDisjointPoolOps(), &pool_params, - umfLevelZeroMemoryProviderOps(), &l0_params, memcopy, - &l0_params); + umf_result_t umf_result = umfDisjointPoolParamsCreate(&pool_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to create pool params!\n"); + return -1; + } + + int ret = run_consumer(port, umfDisjointPoolOps(), pool_params, + umfLevelZeroMemoryProviderOps(), &l0_params, memcopy, + &l0_params); + + umfDisjointPoolParamsDestroy(pool_params); + + return ret; } diff --git a/test/providers/ipc_level_zero_prov_producer.c b/test/providers/ipc_level_zero_prov_producer.c index 8e758644fe..ba950c602d 100644 --- a/test/providers/ipc_level_zero_prov_producer.c +++ b/test/providers/ipc_level_zero_prov_producer.c @@ -26,9 +26,19 @@ int main(int argc, char *argv[]) { level_zero_memory_provider_params_t l0_params = create_level_zero_prov_params(UMF_MEMORY_TYPE_DEVICE); - umf_disjoint_pool_params_t pool_params = umfDisjointPoolParamsDefault(); + umf_disjoint_pool_params_handle_t pool_params = NULL; - return run_producer(port, umfDisjointPoolOps(), &pool_params, - umfLevelZeroMemoryProviderOps(), &l0_params, memcopy, - &l0_params); + umf_result_t umf_result = umfDisjointPoolParamsCreate(&pool_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to create pool params!\n"); + return -1; + } + + int ret = run_producer(port, umfDisjointPoolOps(), pool_params, + umfLevelZeroMemoryProviderOps(), &l0_params, memcopy, + &l0_params); + + umfDisjointPoolParamsDestroy(pool_params); + + return ret; }