From 333ff79e1bd4e788d8331863d04b9fb6bc2fb8ce Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 18 Nov 2024 10:05:04 +0100 Subject: [PATCH 1/4] Add provider_ba_global_split_merge to the umf_test namespace Signed-off-by: Lukasz Dorau --- test/common/provider.hpp | 18 ++++++++++++++ test/disjointCoarseMallocPool.cpp | 40 +++++++++++++++---------------- 2 files changed, 37 insertions(+), 21 deletions(-) diff --git a/test/common/provider.hpp b/test/common/provider.hpp index 148f34dc8..5f128e2b3 100644 --- a/test/common/provider.hpp +++ b/test/common/provider.hpp @@ -126,9 +126,27 @@ struct provider_ba_global : public provider_base_t { const char *get_name() noexcept { return "umf_ba_global"; } }; +struct provider_ba_global_split_merge : public provider_ba_global { + const char *get_name() noexcept { return "umf_ba_global_split_merge"; } + umf_result_t allocation_merge([[maybe_unused]] void *lowPtr, + [[maybe_unused]] void *highPtr, + [[maybe_unused]] size_t totalSize) { + return UMF_RESULT_SUCCESS; + } + + umf_result_t allocation_split([[maybe_unused]] void *ptr, + [[maybe_unused]] size_t totalSize, + [[maybe_unused]] size_t firstSize) { + return UMF_RESULT_SUCCESS; + } +}; + umf_memory_provider_ops_t BA_GLOBAL_PROVIDER_OPS = umf::providerMakeCOps(); +umf_memory_provider_ops_t BA_GLOBAL_SPLIT_MERGE_OPS = + umf::providerMakeCOps(); + struct provider_mock_out_of_mem : public provider_base_t { provider_ba_global helper_prov; int allocNum = 0; diff --git a/test/disjointCoarseMallocPool.cpp b/test/disjointCoarseMallocPool.cpp index 32e1d24f3..f1e494b0c 100644 --- a/test/disjointCoarseMallocPool.cpp +++ b/test/disjointCoarseMallocPool.cpp @@ -12,15 +12,13 @@ #include #include +using umf_test::BA_GLOBAL_SPLIT_MERGE_OPS; using umf_test::KB; using umf_test::MB; using umf_test::test; #define GetStats umfCoarseMemoryProviderGetStats -umf_memory_provider_ops_t UMF_MALLOC_MEMORY_PROVIDER_OPS = - umf::providerMakeCOps(); - struct CoarseWithMemoryStrategyTest : umf_test::test, ::testing::WithParamInterface { @@ -39,13 +37,13 @@ INSTANTIATE_TEST_SUITE_P( UMF_COARSE_MEMORY_STRATEGY_CHECK_ALL_SIZE)); TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_basic) { - umf_memory_provider_handle_t malloc_memory_provider; + umf_memory_provider_handle_t ba_global_split_merge_provider; umf_result_t umf_result; - umf_result = umfMemoryProviderCreate(&UMF_MALLOC_MEMORY_PROVIDER_OPS, NULL, - &malloc_memory_provider); + umf_result = umfMemoryProviderCreate(&BA_GLOBAL_SPLIT_MERGE_OPS, NULL, + &ba_global_split_merge_provider); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_NE(malloc_memory_provider, nullptr); + ASSERT_NE(ba_global_split_merge_provider, nullptr); const size_t init_buffer_size = 20 * MB; @@ -55,7 +53,7 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_basic) { sizeof(coarse_memory_provider_params)); coarse_memory_provider_params.allocation_strategy = allocation_strategy; coarse_memory_provider_params.upstream_memory_provider = - malloc_memory_provider; + ba_global_split_merge_provider; coarse_memory_provider_params.destroy_upstream_memory_provider = true; coarse_memory_provider_params.immediate_init_from_upstream = true; coarse_memory_provider_params.init_buffer = nullptr; @@ -224,20 +222,20 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_basic) { ASSERT_EQ(GetStats(prov).alloc_size, init_buffer_size); umfPoolDestroy(pool); - // Both coarse_memory_provider and malloc_memory_provider + // Both coarse_memory_provider and ba_global_split_merge_provider // have already been destroyed by umfPoolDestroy(), because: // UMF_POOL_CREATE_FLAG_OWN_PROVIDER was set in umfPoolCreate() and // coarse_memory_provider_params.destroy_upstream_memory_provider = true; } TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_simple1) { - umf_memory_provider_handle_t malloc_memory_provider; + umf_memory_provider_handle_t ba_global_split_merge_provider; umf_result_t umf_result; - umf_result = umfMemoryProviderCreate(&UMF_MALLOC_MEMORY_PROVIDER_OPS, NULL, - &malloc_memory_provider); + umf_result = umfMemoryProviderCreate(&BA_GLOBAL_SPLIT_MERGE_OPS, NULL, + &ba_global_split_merge_provider); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_NE(malloc_memory_provider, nullptr); + ASSERT_NE(ba_global_split_merge_provider, nullptr); const size_t init_buffer_size = 20 * MB; @@ -247,7 +245,7 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_simple1) { sizeof(coarse_memory_provider_params)); coarse_memory_provider_params.allocation_strategy = allocation_strategy; coarse_memory_provider_params.upstream_memory_provider = - malloc_memory_provider; + ba_global_split_merge_provider; coarse_memory_provider_params.immediate_init_from_upstream = true; coarse_memory_provider_params.init_buffer = NULL; coarse_memory_provider_params.init_buffer_size = init_buffer_size; @@ -337,17 +335,17 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_simple1) { umfPoolDestroy(pool); umfMemoryProviderDestroy(coarse_memory_provider); - umfMemoryProviderDestroy(malloc_memory_provider); + umfMemoryProviderDestroy(ba_global_split_merge_provider); } TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_simple2) { - umf_memory_provider_handle_t malloc_memory_provider; + umf_memory_provider_handle_t ba_global_split_merge_provider; umf_result_t umf_result; - umf_result = umfMemoryProviderCreate(&UMF_MALLOC_MEMORY_PROVIDER_OPS, NULL, - &malloc_memory_provider); + umf_result = umfMemoryProviderCreate(&BA_GLOBAL_SPLIT_MERGE_OPS, NULL, + &ba_global_split_merge_provider); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_NE(malloc_memory_provider, nullptr); + ASSERT_NE(ba_global_split_merge_provider, nullptr); const size_t init_buffer_size = 20 * MB; @@ -357,7 +355,7 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_simple2) { sizeof(coarse_memory_provider_params)); coarse_memory_provider_params.allocation_strategy = allocation_strategy; coarse_memory_provider_params.upstream_memory_provider = - malloc_memory_provider; + ba_global_split_merge_provider; coarse_memory_provider_params.immediate_init_from_upstream = true; coarse_memory_provider_params.init_buffer = NULL; coarse_memory_provider_params.init_buffer_size = init_buffer_size; @@ -416,7 +414,7 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_simple2) { umfPoolDestroy(pool); umfMemoryProviderDestroy(coarse_memory_provider); - umfMemoryProviderDestroy(malloc_memory_provider); + umfMemoryProviderDestroy(ba_global_split_merge_provider); } struct alloc_ptr_size { From e45cec79ad035bec07cd71221230c3f13291475b Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 18 Nov 2024 14:30:11 +0100 Subject: [PATCH 2/4] Split and merge in Coarse provider to enable IPC API Coarse provider has to always call: - umfMemoryProviderAllocationSplit(upstream_provider) or - umfMemoryProviderAllocationMerge(upstream_provider) when splitting or merging memory blocks, because the IPC API would not work on split/merged memory blocks otherwise. Signed-off-by: Lukasz Dorau --- src/provider/provider_coarse.c | 348 ++++++++++----------------------- test/CMakeLists.txt | 5 + test/provider_coarse.cpp | 184 ++++++++++++----- 3 files changed, 235 insertions(+), 302 deletions(-) diff --git a/src/provider/provider_coarse.c b/src/provider/provider_coarse.c index c3027b91d..fda80712c 100644 --- a/src/provider/provider_coarse.c +++ b/src/provider/provider_coarse.c @@ -23,11 +23,6 @@ #define COARSE_BASE_NAME "coarse" -#define IS_ORIGIN_OF_BLOCK(origin, block) \ - (((uintptr_t)(block)->data >= (uintptr_t)(origin)->data) && \ - ((uintptr_t)(block)->data + (block)->size <= \ - (uintptr_t)(origin)->data + (origin)->size)) - typedef struct coarse_memory_provider_t { umf_memory_provider_handle_t upstream_memory_provider; @@ -42,9 +37,6 @@ typedef struct coarse_memory_provider_t { size_t used_size; size_t alloc_size; - // upstream_blocks - tree of all blocks allocated from the upstream provider - struct ravl *upstream_blocks; - // all_blocks - tree of all blocks - sorted by an address of data struct ravl *all_blocks; @@ -158,21 +150,7 @@ static block_t *get_block_next(ravl_node_t *node) { } #endif /* NDEBUG */ -static bool is_same_origin(struct ravl *upstream_blocks, block_t *block1, - block_t *block2) { - ravl_data_t rdata1 = {(uintptr_t)block1->data, NULL}; - ravl_node_t *ravl_origin1 = - ravl_find(upstream_blocks, &rdata1, RAVL_PREDICATE_LESS_EQUAL); - assert(ravl_origin1); - - block_t *origin1 = get_node_block(ravl_origin1); - assert(IS_ORIGIN_OF_BLOCK(origin1, block1)); - - return (IS_ORIGIN_OF_BLOCK(origin1, block2)); -} - -// The functions "coarse_ravl_*" handle lists of blocks: -// - coarse_provider->all_blocks and coarse_provider->upstream_blocks +// The functions "coarse_ravl_*" handles the coarse_provider->all_blocks list of blocks // sorted by a pointer (block_t->data) to the beginning of the block data. // // coarse_ravl_add_new - allocate and add a new block to the tree @@ -468,7 +446,6 @@ static umf_result_t user_block_merge(coarse_memory_provider_t *coarse_provider, *merged_node = NULL; - struct ravl *upstream_blocks = coarse_provider->upstream_blocks; struct ravl *all_blocks = coarse_provider->all_blocks; struct ravl *free_blocks = coarse_provider->free_blocks; @@ -478,13 +455,25 @@ static umf_result_t user_block_merge(coarse_memory_provider_t *coarse_provider, bool same_used = ((block1->used == used) && (block2->used == used)); bool contignous_data = (block1->data + block1->size == block2->data); - bool same_origin = is_same_origin(upstream_blocks, block1, block2); // check if blocks can be merged - if (!same_used || !contignous_data || !same_origin) { + if (!same_used || !contignous_data) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; } + if (coarse_provider->upstream_memory_provider) { + // check if blocks can be merged by the upstream provider + umf_result_t umf_result = umfMemoryProviderAllocationMerge( + coarse_provider->upstream_memory_provider, block1->data, + block2->data, block1->size + block2->size); + if (umf_result != UMF_RESULT_SUCCESS) { + LOG_ERR("umfMemoryProviderAllocationMerge(lowPtr=%p, highPtr=%p, " + "totalSize=%zu) failed", + block1->data, block2->data, block1->size + block2->size); + return umf_result; + } + } + if (block1->free_list_ptr) { free_blocks_rm_node(free_blocks, block1->free_list_ptr); block1->free_list_ptr = NULL; @@ -554,104 +543,6 @@ free_block_merge_with_next(coarse_memory_provider_t *coarse_provider, return merged_node; } -// upstream_block_merge - merge the given two upstream blocks -static umf_result_t -upstream_block_merge(coarse_memory_provider_t *coarse_provider, - ravl_node_t *node1, ravl_node_t *node2, - ravl_node_t **merged_node) { - assert(node1); - assert(node2); - assert(merged_node); - - *merged_node = NULL; - - umf_memory_provider_handle_t upstream_provider = - coarse_provider->upstream_memory_provider; - if (!upstream_provider) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - - block_t *block1 = get_node_block(node1); - block_t *block2 = get_node_block(node2); - assert(block1->data < block2->data); - - bool contignous_data = (block1->data + block1->size == block2->data); - if (!contignous_data) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - - // check if blocks can be merged by the upstream provider - umf_result_t merge_status = umfMemoryProviderAllocationMerge( - coarse_provider->upstream_memory_provider, block1->data, block2->data, - block1->size + block2->size); - if (merge_status != UMF_RESULT_SUCCESS) { - return merge_status; - } - - // update the size - block1->size += block2->size; - - struct ravl *upstream_blocks = coarse_provider->upstream_blocks; - block_t *block_rm = coarse_ravl_rm(upstream_blocks, block2->data); - assert(block_rm == block2); - (void)block_rm; // WA for unused variable error - umf_ba_global_free(block2); - - *merged_node = node1; - - return UMF_RESULT_SUCCESS; -} - -// upstream_block_merge_with_prev - merge the given upstream block -// with the previous one if both have continuous data. -// Remove the merged block from the tree of upstream blocks. -static ravl_node_t * -upstream_block_merge_with_prev(coarse_memory_provider_t *coarse_provider, - ravl_node_t *node) { - assert(node); - - ravl_node_t *node_prev = get_node_prev(node); - if (!node_prev) { - return node; - } - - ravl_node_t *merged_node = NULL; - umf_result_t umf_result = - upstream_block_merge(coarse_provider, node_prev, node, &merged_node); - if (umf_result != UMF_RESULT_SUCCESS) { - return node; - } - - assert(merged_node != NULL); - - return merged_node; -} - -// upstream_block_merge_with_next - merge the given upstream block -// with the next one if both have continuous data. -// Remove the merged block from the tree of upstream blocks. -static ravl_node_t * -upstream_block_merge_with_next(coarse_memory_provider_t *coarse_provider, - ravl_node_t *node) { - assert(node); - - ravl_node_t *node_next = get_node_next(node); - if (!node_next) { - return node; - } - - ravl_node_t *merged_node = NULL; - umf_result_t umf_result = - upstream_block_merge(coarse_provider, node, node_next, &merged_node); - if (umf_result != UMF_RESULT_SUCCESS) { - return node; - } - - assert(merged_node != NULL); - - return merged_node; -} - #ifndef NDEBUG // begin of DEBUG code typedef struct debug_cb_args_t { @@ -660,8 +551,6 @@ typedef struct debug_cb_args_t { size_t sum_blocks_size; size_t num_all_blocks; size_t num_free_blocks; - size_t num_alloc_blocks; - size_t sum_alloc_size; } debug_cb_args_t; static void debug_verify_all_blocks_cb(void *data, void *arg) { @@ -690,18 +579,6 @@ static void debug_verify_all_blocks_cb(void *data, void *arg) { assert(block->data); assert(block->size > 0); - // There shouldn't be two adjacent unused blocks - // if they are continuous and have the same origin. - if (block_prev && !block_prev->used && !block->used && - (block_prev->data + block_prev->size == block->data)) { - assert(!is_same_origin(provider->upstream_blocks, block_prev, block)); - } - - if (block_next && !block_next->used && !block->used && - (block->data + block->size == block_next->data)) { - assert(!is_same_origin(provider->upstream_blocks, block, block_next)); - } - // data addresses in the list are in ascending order if (block_prev) { assert(block_prev->data < block->data); @@ -722,45 +599,6 @@ static void debug_verify_all_blocks_cb(void *data, void *arg) { } } -static void debug_verify_upstream_blocks_cb(void *data, void *arg) { - assert(data); - assert(arg); - - ravl_data_t *node_data = data; - block_t *alloc = node_data->value; - assert(alloc); - - debug_cb_args_t *cb_args = (debug_cb_args_t *)arg; - coarse_memory_provider_t *provider = cb_args->provider; - - ravl_node_t *node = - ravl_find(provider->upstream_blocks, data, RAVL_PREDICATE_EQUAL); - assert(node); - - block_t *alloc_next = get_block_next(node); - block_t *alloc_prev = get_block_prev(node); - - cb_args->num_alloc_blocks++; - cb_args->sum_alloc_size += alloc->size; - - assert(alloc->data); - assert(alloc->size > 0); - - // data addresses in the list are in ascending order - if (alloc_prev) { - assert(alloc_prev->data < alloc->data); - } - - if (alloc_next) { - assert(alloc->data < alloc_next->data); - } - - // data should not overlap - if (alloc_next) { - assert((alloc->data + alloc->size) <= alloc_next->data); - } -} - static umf_result_t coarse_memory_provider_get_stats(void *provider, coarse_memory_provider_stats_t *stats); @@ -783,39 +621,19 @@ static bool debug_check(coarse_memory_provider_t *provider) { assert(cb_args.sum_blocks_size == provider->alloc_size); assert(provider->alloc_size >= provider->used_size); - // verify the upstream_blocks list - ravl_foreach(provider->upstream_blocks, debug_verify_upstream_blocks_cb, - &cb_args); - - assert(cb_args.sum_alloc_size == provider->alloc_size); - assert(cb_args.num_alloc_blocks == stats.num_upstream_blocks); - return true; } #endif /* NDEBUG */ // end of DEBUG code static umf_result_t -coarse_add_upstream_block(coarse_memory_provider_t *coarse_provider, void *addr, - size_t size) { - ravl_node_t *alloc_node = NULL; - - block_t *alloc = coarse_ravl_add_new(coarse_provider->upstream_blocks, addr, - size, &alloc_node); - if (alloc == NULL) { - return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; - } - +coarse_add_new_block(coarse_memory_provider_t *coarse_provider, void *addr, + size_t size) { block_t *new_block = coarse_ravl_add_new(coarse_provider->all_blocks, addr, size, NULL); if (new_block == NULL) { - coarse_ravl_rm(coarse_provider->upstream_blocks, addr); return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; } - // check if the new upstream block can be merged with its neighbours - alloc_node = upstream_block_merge_with_prev(coarse_provider, alloc_node); - alloc_node = upstream_block_merge_with_next(coarse_provider, alloc_node); - new_block->used = true; coarse_provider->alloc_size += size; coarse_provider->used_size += size; @@ -934,18 +752,11 @@ static umf_result_t coarse_memory_provider_initialize(void *params, // most of the error handling paths below set this error umf_result = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; - coarse_provider->upstream_blocks = - ravl_new_sized(coarse_ravl_comp, sizeof(ravl_data_t)); - if (coarse_provider->upstream_blocks == NULL) { - LOG_ERR("out of the host memory"); - goto err_free_name; - } - coarse_provider->free_blocks = ravl_new_sized(coarse_ravl_comp, sizeof(ravl_data_t)); if (coarse_provider->free_blocks == NULL) { LOG_ERR("out of the host memory"); - goto err_delete_ravl_upstream_blocks; + goto err_free_name; } coarse_provider->all_blocks = @@ -978,9 +789,9 @@ static umf_result_t coarse_memory_provider_initialize(void *params, coarse_params->init_buffer_size); } else if (coarse_params->init_buffer) { - umf_result = coarse_add_upstream_block(coarse_provider, - coarse_provider->init_buffer, - coarse_params->init_buffer_size); + umf_result = + coarse_add_new_block(coarse_provider, coarse_provider->init_buffer, + coarse_params->init_buffer_size); if (umf_result != UMF_RESULT_SUCCESS) { goto err_destroy_mutex; } @@ -1008,8 +819,6 @@ static umf_result_t coarse_memory_provider_initialize(void *params, ravl_delete(coarse_provider->all_blocks); err_delete_ravl_free_blocks: ravl_delete(coarse_provider->free_blocks); -err_delete_ravl_upstream_blocks: - ravl_delete(coarse_provider->upstream_blocks); err_free_name: umf_ba_global_free(coarse_provider->name); err_free_coarse_provider: @@ -1017,38 +826,25 @@ static umf_result_t coarse_memory_provider_initialize(void *params, return umf_result; } -static void coarse_ravl_cb_rm_upstream_blocks_node(void *data, void *arg) { +static void coarse_ravl_cb_rm_all_blocks_node(void *data, void *arg) { assert(data); assert(arg); coarse_memory_provider_t *coarse_provider = (struct coarse_memory_provider_t *)arg; ravl_data_t *node_data = data; - block_t *alloc = node_data->value; - assert(alloc); + block_t *block = node_data->value; + assert(block); if (coarse_provider->upstream_memory_provider && !coarse_provider->disable_upstream_provider_free) { - // We continue to deallocate alloc blocks even if the upstream provider doesn't return success. + // we continue to deallocate blocks even if the upstream provider doesn't return success umfMemoryProviderFree(coarse_provider->upstream_memory_provider, - alloc->data, alloc->size); + block->data, block->size); } - assert(coarse_provider->alloc_size >= alloc->size); - coarse_provider->alloc_size -= alloc->size; - - umf_ba_global_free(alloc); -} - -static void coarse_ravl_cb_rm_all_blocks_node(void *data, void *arg) { - assert(data); - assert(arg); - - coarse_memory_provider_t *coarse_provider = - (struct coarse_memory_provider_t *)arg; - ravl_data_t *node_data = data; - block_t *block = node_data->value; - assert(block); + assert(coarse_provider->alloc_size >= block->size); + coarse_provider->alloc_size -= block->size; if (block->used) { assert(coarse_provider->used_size >= block->size); @@ -1071,12 +867,8 @@ static void coarse_memory_provider_finalize(void *provider) { ravl_foreach(coarse_provider->all_blocks, coarse_ravl_cb_rm_all_blocks_node, coarse_provider); assert(coarse_provider->used_size == 0); - - ravl_foreach(coarse_provider->upstream_blocks, - coarse_ravl_cb_rm_upstream_blocks_node, coarse_provider); assert(coarse_provider->alloc_size == 0); - ravl_delete(coarse_provider->upstream_blocks); ravl_delete(coarse_provider->all_blocks); ravl_delete(coarse_provider->free_blocks); @@ -1090,6 +882,21 @@ static void coarse_memory_provider_finalize(void *provider) { umf_ba_global_free(coarse_provider); } +static umf_result_t +can_upstream_split(umf_memory_provider_handle_t upstream_memory_provider, + void *ptr, size_t totalSize, size_t firstSize) { + // check if the block can be split by the upstream provider + umf_result_t umf_result = umfMemoryProviderAllocationSplit( + upstream_memory_provider, ptr, totalSize, firstSize); + if (umf_result != UMF_RESULT_SUCCESS) { + LOG_ERR("umfMemoryProviderAllocationSplit(ptr=%p, totalSize = %zu = " + "(%zu + %zu)) failed", + ptr, totalSize, firstSize, totalSize - firstSize); + } + + return umf_result; +} + static umf_result_t create_aligned_block(coarse_memory_provider_t *coarse_provider, size_t orig_size, size_t alignment, block_t **current) { @@ -1103,6 +910,16 @@ create_aligned_block(coarse_memory_provider_t *coarse_provider, uintptr_t aligned_data = ALIGN_UP(orig_data, alignment); size_t padding = aligned_data - orig_data; if (alignment > 0 && padding > 0) { + if (coarse_provider->upstream_memory_provider) { + // check if block can be split by the upstream provider + umf_result_t umf_result = + can_upstream_split(coarse_provider->upstream_memory_provider, + curr->data, curr->size, padding); + if (umf_result != UMF_RESULT_SUCCESS) { + return umf_result; + } + } + block_t *aligned_block = coarse_ravl_add_new( coarse_provider->all_blocks, curr->data + padding, curr->size - padding, NULL); @@ -1130,6 +947,17 @@ create_aligned_block(coarse_memory_provider_t *coarse_provider, static umf_result_t split_current_block(coarse_memory_provider_t *coarse_provider, block_t *curr, size_t size) { + + if (coarse_provider->upstream_memory_provider) { + // check if block can be split by the upstream provider + umf_result_t umf_result = + can_upstream_split(coarse_provider->upstream_memory_provider, + curr->data, curr->size, size); + if (umf_result != UMF_RESULT_SUCCESS) { + return umf_result; + } + } + ravl_node_t *new_node = NULL; block_t *new_block = @@ -1194,6 +1022,26 @@ find_free_block(struct ravl *free_blocks, size_t size, size_t alignment, } } +static int free_blocks_re_add(coarse_memory_provider_t *coarse_provider, + block_t *block) { + assert(coarse_provider); + + ravl_node_t *node = + coarse_ravl_find_node(coarse_provider->all_blocks, block->data); + if (node == NULL) { + // the block was not found + LOG_ERR("memory block not found (ptr = %p, size = %zu)", block->data, + block->size); + return -1; + } + + // merge with prev and/or next block if they are unused and have continuous data + node = free_block_merge_with_prev(coarse_provider, node); + node = free_block_merge_with_next(coarse_provider, node); + + return free_blocks_add(coarse_provider->free_blocks, get_node_block(node)); +} + static umf_result_t coarse_memory_provider_alloc(void *provider, size_t size, size_t alignment, void **resultPtr) { @@ -1236,8 +1084,8 @@ static umf_result_t coarse_memory_provider_alloc(void *provider, size_t size, umf_result = create_aligned_block(coarse_provider, size, alignment, &curr); if (umf_result != UMF_RESULT_SUCCESS) { - utils_mutex_unlock(&coarse_provider->lock); - return umf_result; + free_blocks_re_add(coarse_provider, curr); + goto err_unlock; } } @@ -1245,8 +1093,8 @@ static umf_result_t coarse_memory_provider_alloc(void *provider, size_t size, // Split the current block and put the new block after the one that we use. umf_result = split_current_block(coarse_provider, curr, size); if (umf_result != UMF_RESULT_SUCCESS) { - utils_mutex_unlock(&coarse_provider->lock); - return umf_result; + free_blocks_re_add(coarse_provider, curr); + goto err_unlock; } curr->size = size; @@ -1286,7 +1134,7 @@ static umf_result_t coarse_memory_provider_alloc(void *provider, size_t size, ASSERT_IS_ALIGNED(((uintptr_t)(*resultPtr)), alignment); - umf_result = coarse_add_upstream_block(coarse_provider, *resultPtr, size); + umf_result = coarse_add_new_block(coarse_provider, *resultPtr, size); if (umf_result != UMF_RESULT_SUCCESS) { if (!coarse_provider->disable_upstream_provider_free) { umfMemoryProviderFree(coarse_provider->upstream_memory_provider, @@ -1455,11 +1303,6 @@ coarse_memory_provider_get_stats(void *provider, coarse_memory_provider_t *coarse_provider = (struct coarse_memory_provider_t *)provider; - // count blocks - size_t num_upstream_blocks = 0; - ravl_foreach(coarse_provider->upstream_blocks, ravl_cb_count, - &num_upstream_blocks); - size_t num_all_blocks = 0; ravl_foreach(coarse_provider->all_blocks, ravl_cb_count, &num_all_blocks); @@ -1469,7 +1312,6 @@ coarse_memory_provider_get_stats(void *provider, stats->alloc_size = coarse_provider->alloc_size; stats->used_size = coarse_provider->used_size; - stats->num_upstream_blocks = num_upstream_blocks; stats->num_all_blocks = num_all_blocks; stats->num_free_blocks = num_free_blocks; @@ -1518,6 +1360,16 @@ static umf_result_t coarse_memory_provider_allocation_split(void *provider, assert(debug_check(coarse_provider)); + if (coarse_provider->upstream_memory_provider) { + // check if block can be split by the upstream provider + umf_result = + can_upstream_split(coarse_provider->upstream_memory_provider, ptr, + totalSize, firstSize); + if (umf_result != UMF_RESULT_SUCCESS) { + return umf_result; + } + } + ravl_node_t *node = coarse_ravl_find_node(coarse_provider->all_blocks, ptr); if (node == NULL) { LOG_ERR("memory block not found"); @@ -1626,7 +1478,7 @@ static umf_result_t coarse_memory_provider_allocation_merge(void *provider, } if ((uintptr_t)highPtr != ((uintptr_t)lowPtr + low_block->size)) { - LOG_ERR("given pointers cannot be merged"); + LOG_ERR("given allocations are not adjacent"); umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT; goto err_mutex_unlock; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 1f2ef5959..f243aaa51 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -70,6 +70,11 @@ function(build_umf_test) PRIVATE UMF_POOL_SCALABLE_ENABLED=1) endif() + if(UMF_DISABLE_HWLOC) + target_compile_definitions(${TEST_TARGET_NAME} + PRIVATE UMF_DISABLE_HWLOC=1) + endif() + if(NOT MSVC) # Suppress 'cast discards const qualifier' warnings. Parametrized GTEST # tests retrieve arguments using 'GetParam()', which applies a 'const' diff --git a/test/provider_coarse.cpp b/test/provider_coarse.cpp index c2de4c06a..dfa6b3d68 100644 --- a/test/provider_coarse.cpp +++ b/test/provider_coarse.cpp @@ -10,19 +10,20 @@ #include "provider.hpp" #include +#include +using umf_test::BA_GLOBAL_SPLIT_MERGE_OPS; using umf_test::KB; using umf_test::MB; using umf_test::test; #define GetStats umfCoarseMemoryProviderGetStats -#define UPSTREAM_NAME "umf_ba_global" +#define UPSTREAM_NAME "umf_ba_global_split_merge" #define BASE_NAME "coarse" #define COARSE_NAME BASE_NAME " (" UPSTREAM_NAME ")" -umf_memory_provider_ops_t UMF_MALLOC_MEMORY_PROVIDER_OPS = - umf::providerMakeCOps(); +#define FILE_PATH ((char *)"tmp_file") struct CoarseWithMemoryStrategyTest : umf_test::test, @@ -42,13 +43,13 @@ INSTANTIATE_TEST_SUITE_P( UMF_COARSE_MEMORY_STRATEGY_CHECK_ALL_SIZE)); TEST_F(test, coarseProvider_name_upstream) { - umf_memory_provider_handle_t malloc_memory_provider; + umf_memory_provider_handle_t ba_global_provider; umf_result_t umf_result; - umf_result = umfMemoryProviderCreate(&UMF_MALLOC_MEMORY_PROVIDER_OPS, NULL, - &malloc_memory_provider); + umf_result = umfMemoryProviderCreate(&BA_GLOBAL_SPLIT_MERGE_OPS, NULL, + &ba_global_provider); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_NE(malloc_memory_provider, nullptr); + ASSERT_NE(ba_global_provider, nullptr); const size_t init_buffer_size = 20 * MB; @@ -56,8 +57,7 @@ TEST_F(test, coarseProvider_name_upstream) { // make sure there are no undefined members - prevent a UB memset(&coarse_memory_provider_params, 0, sizeof(coarse_memory_provider_params)); - coarse_memory_provider_params.upstream_memory_provider = - malloc_memory_provider; + coarse_memory_provider_params.upstream_memory_provider = ba_global_provider; coarse_memory_provider_params.destroy_upstream_memory_provider = true; coarse_memory_provider_params.immediate_init_from_upstream = true; coarse_memory_provider_params.init_buffer = nullptr; @@ -87,7 +87,7 @@ TEST_F(test, coarseProvider_name_upstream) { 0); umfMemoryProviderDestroy(coarse_memory_provider); - // malloc_memory_provider has already been destroyed + // ba_global_provider has already been destroyed // by umfMemoryProviderDestroy(coarse_memory_provider), because: // coarse_memory_provider_params.destroy_upstream_memory_provider = true; } @@ -183,13 +183,13 @@ TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_wrong_params_0) { // wrong parameters: given both an upstream_memory_provider // and an init_buffer while only one of them is allowed TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_wrong_params_1) { - umf_memory_provider_handle_t malloc_memory_provider; + umf_memory_provider_handle_t ba_global_provider; umf_result_t umf_result; - umf_result = umfMemoryProviderCreate(&UMF_MALLOC_MEMORY_PROVIDER_OPS, NULL, - &malloc_memory_provider); + umf_result = umfMemoryProviderCreate(&BA_GLOBAL_SPLIT_MERGE_OPS, NULL, + &ba_global_provider); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_NE(malloc_memory_provider, nullptr); + ASSERT_NE(ba_global_provider, nullptr); const size_t init_buffer_size = 20 * MB; @@ -203,8 +203,7 @@ TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_wrong_params_1) { memset(&coarse_memory_provider_params, 0, sizeof(coarse_memory_provider_params)); coarse_memory_provider_params.allocation_strategy = allocation_strategy; - coarse_memory_provider_params.upstream_memory_provider = - malloc_memory_provider; + coarse_memory_provider_params.upstream_memory_provider = ba_global_provider; coarse_memory_provider_params.immediate_init_from_upstream = true; coarse_memory_provider_params.init_buffer = buf; coarse_memory_provider_params.init_buffer_size = init_buffer_size; @@ -216,26 +215,25 @@ TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_wrong_params_1) { ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); ASSERT_EQ(coarse_memory_provider, nullptr); - umfMemoryProviderDestroy(malloc_memory_provider); + umfMemoryProviderDestroy(ba_global_provider); } // wrong parameters: init_buffer_size must not equal 0 when immediate_init_from_upstream is true TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_wrong_params_2) { - umf_memory_provider_handle_t malloc_memory_provider; + umf_memory_provider_handle_t ba_global_provider; umf_result_t umf_result; - umf_result = umfMemoryProviderCreate(&UMF_MALLOC_MEMORY_PROVIDER_OPS, NULL, - &malloc_memory_provider); + umf_result = umfMemoryProviderCreate(&BA_GLOBAL_SPLIT_MERGE_OPS, NULL, + &ba_global_provider); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_NE(malloc_memory_provider, nullptr); + ASSERT_NE(ba_global_provider, nullptr); coarse_memory_provider_params_t coarse_memory_provider_params; // make sure there are no undefined members - prevent a UB memset(&coarse_memory_provider_params, 0, sizeof(coarse_memory_provider_params)); coarse_memory_provider_params.allocation_strategy = allocation_strategy; - coarse_memory_provider_params.upstream_memory_provider = - malloc_memory_provider; + coarse_memory_provider_params.upstream_memory_provider = ba_global_provider; coarse_memory_provider_params.immediate_init_from_upstream = true; coarse_memory_provider_params.init_buffer = nullptr; coarse_memory_provider_params.init_buffer_size = 0; @@ -247,7 +245,7 @@ TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_wrong_params_2) { ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); ASSERT_EQ(coarse_memory_provider, nullptr); - umfMemoryProviderDestroy(malloc_memory_provider); + umfMemoryProviderDestroy(ba_global_provider); } // wrong parameters: init_buffer_size must not equal 0 when init_buffer is not NULL @@ -281,21 +279,20 @@ TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_wrong_params_3) { // wrong parameters: init_buffer_size must equal 0 when init_buffer is NULL and immediate_init_from_upstream is false TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_wrong_params_4) { - umf_memory_provider_handle_t malloc_memory_provider; + umf_memory_provider_handle_t ba_global_provider; umf_result_t umf_result; - umf_result = umfMemoryProviderCreate(&UMF_MALLOC_MEMORY_PROVIDER_OPS, NULL, - &malloc_memory_provider); + umf_result = umfMemoryProviderCreate(&BA_GLOBAL_SPLIT_MERGE_OPS, NULL, + &ba_global_provider); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_NE(malloc_memory_provider, nullptr); + ASSERT_NE(ba_global_provider, nullptr); coarse_memory_provider_params_t coarse_memory_provider_params; // make sure there are no undefined members - prevent a UB memset(&coarse_memory_provider_params, 0, sizeof(coarse_memory_provider_params)); coarse_memory_provider_params.allocation_strategy = allocation_strategy; - coarse_memory_provider_params.upstream_memory_provider = - malloc_memory_provider; + coarse_memory_provider_params.upstream_memory_provider = ba_global_provider; coarse_memory_provider_params.immediate_init_from_upstream = false; coarse_memory_provider_params.init_buffer = NULL; coarse_memory_provider_params.init_buffer_size = 20 * MB; @@ -307,7 +304,7 @@ TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_wrong_params_4) { ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); ASSERT_EQ(coarse_memory_provider, nullptr); - umfMemoryProviderDestroy(malloc_memory_provider); + umfMemoryProviderDestroy(ba_global_provider); } // wrong parameters: destroy_upstream_memory_provider is true, but an upstream provider is not provided @@ -340,14 +337,96 @@ TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_wrong_params_5) { ASSERT_EQ(coarse_memory_provider, nullptr); } +#if !defined(_WIN32) && !defined(UMF_DISABLE_HWLOC) +TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_merge_upstream) { + umf_memory_provider_handle_t file_memory_provider; + umf_result_t umf_result; + + umf_file_memory_provider_params_t file_params = + umfFileMemoryProviderParamsDefault(FILE_PATH); + file_params.visibility = UMF_MEM_MAP_SHARED; + + umf_result = umfMemoryProviderCreate(umfFileMemoryProviderOps(), + &file_params, &file_memory_provider); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(file_memory_provider, nullptr); + + const size_t init_buffer_size = 1 * KB; + + coarse_memory_provider_params_t coarse_memory_provider_params; + // make sure there are no undefined members - prevent a UB + memset(&coarse_memory_provider_params, 0, + sizeof(coarse_memory_provider_params)); + coarse_memory_provider_params.upstream_memory_provider = + file_memory_provider; + coarse_memory_provider_params.immediate_init_from_upstream = true; + coarse_memory_provider_params.init_buffer = NULL; + coarse_memory_provider_params.init_buffer_size = init_buffer_size; + + umf_memory_provider_handle_t coarse_memory_provider; + umf_result = umfMemoryProviderCreate(umfCoarseMemoryProviderOps(), + &coarse_memory_provider_params, + &coarse_memory_provider); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(coarse_memory_provider, nullptr); + + umf_memory_provider_handle_t cp = coarse_memory_provider; + char *ptr1 = nullptr; + char *ptr2 = nullptr; + + ASSERT_EQ(GetStats(cp).used_size, 0 * MB); + ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size); + ASSERT_EQ(GetStats(cp).num_all_blocks, 1); + + /* test umfMemoryProviderAllocationMerge */ + umf_result = + umfMemoryProviderAlloc(cp, init_buffer_size, 0, (void **)&ptr1); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(ptr1, nullptr); + ASSERT_EQ(GetStats(cp).used_size, init_buffer_size); + ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size); + ASSERT_EQ(GetStats(cp).num_all_blocks, 1); + + umf_result = + umfMemoryProviderAlloc(cp, init_buffer_size, 0, (void **)&ptr2); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(ptr2, nullptr); + ASSERT_EQ(GetStats(cp).used_size, 2 * init_buffer_size); + ASSERT_EQ(GetStats(cp).alloc_size, 2 * init_buffer_size); + ASSERT_EQ(GetStats(cp).num_all_blocks, 2); + + if ((uintptr_t)ptr1 < (uintptr_t)ptr2) { + umf_result = umfMemoryProviderAllocationMerge(cp, ptr1, ptr2, + 2 * init_buffer_size); + } else { + umf_result = umfMemoryProviderAllocationMerge(cp, ptr2, ptr1, + 2 * init_buffer_size); + ptr1 = ptr2; + } + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_EQ(GetStats(cp).used_size, 2 * init_buffer_size); + ASSERT_EQ(GetStats(cp).alloc_size, 2 * init_buffer_size); + ASSERT_EQ(GetStats(cp).num_all_blocks, 1); + + umf_result = umfMemoryProviderFree(cp, ptr1, 2 * init_buffer_size); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_EQ(GetStats(cp).used_size, 0); + ASSERT_EQ(GetStats(cp).alloc_size, 2 * init_buffer_size); + ASSERT_EQ(GetStats(cp).num_all_blocks, 1); + + umfMemoryProviderDestroy(coarse_memory_provider); + umfMemoryProviderDestroy(file_memory_provider); +} +#endif /* !defined(_WIN32) && !defined(UMF_DISABLE_HWLOC) */ + TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_split_merge) { - umf_memory_provider_handle_t malloc_memory_provider; + umf_memory_provider_handle_t ba_global_provider; umf_result_t umf_result; - umf_result = umfMemoryProviderCreate(&UMF_MALLOC_MEMORY_PROVIDER_OPS, NULL, - &malloc_memory_provider); + umf_result = umfMemoryProviderCreate(&BA_GLOBAL_SPLIT_MERGE_OPS, NULL, + &ba_global_provider); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_NE(malloc_memory_provider, nullptr); + ASSERT_NE(ba_global_provider, nullptr); const size_t init_buffer_size = 20 * MB; @@ -355,8 +434,7 @@ TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_split_merge) { // make sure there are no undefined members - prevent a UB memset(&coarse_memory_provider_params, 0, sizeof(coarse_memory_provider_params)); - coarse_memory_provider_params.upstream_memory_provider = - malloc_memory_provider; + coarse_memory_provider_params.upstream_memory_provider = ba_global_provider; coarse_memory_provider_params.immediate_init_from_upstream = true; coarse_memory_provider_params.init_buffer = NULL; coarse_memory_provider_params.init_buffer_size = init_buffer_size; @@ -429,17 +507,17 @@ TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_split_merge) { ASSERT_EQ(GetStats(cp).num_all_blocks, 1); umfMemoryProviderDestroy(coarse_memory_provider); - umfMemoryProviderDestroy(malloc_memory_provider); + umfMemoryProviderDestroy(ba_global_provider); } TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_split_merge_negative) { - umf_memory_provider_handle_t malloc_memory_provider; + umf_memory_provider_handle_t ba_global_provider; umf_result_t umf_result; - umf_result = umfMemoryProviderCreate(&UMF_MALLOC_MEMORY_PROVIDER_OPS, NULL, - &malloc_memory_provider); + umf_result = umfMemoryProviderCreate(&BA_GLOBAL_SPLIT_MERGE_OPS, NULL, + &ba_global_provider); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_NE(malloc_memory_provider, nullptr); + ASSERT_NE(ba_global_provider, nullptr); const size_t init_buffer_size = 20 * MB; @@ -447,8 +525,7 @@ TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_split_merge_negative) { // make sure there are no undefined members - prevent a UB memset(&coarse_memory_provider_params, 0, sizeof(coarse_memory_provider_params)); - coarse_memory_provider_params.upstream_memory_provider = - malloc_memory_provider; + coarse_memory_provider_params.upstream_memory_provider = ba_global_provider; coarse_memory_provider_params.immediate_init_from_upstream = true; coarse_memory_provider_params.init_buffer = NULL; coarse_memory_provider_params.init_buffer_size = init_buffer_size; @@ -544,7 +621,7 @@ TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_split_merge_negative) { ASSERT_EQ(GetStats(cp).num_all_blocks, 1); umfMemoryProviderDestroy(coarse_memory_provider); - umfMemoryProviderDestroy(malloc_memory_provider); + umfMemoryProviderDestroy(ba_global_provider); } TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_purge_no_upstream) { @@ -607,13 +684,13 @@ TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_purge_no_upstream) { } TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_purge_with_upstream) { - umf_memory_provider_handle_t malloc_memory_provider; + umf_memory_provider_handle_t ba_global_provider; umf_result_t umf_result; - umf_result = umfMemoryProviderCreate(&UMF_MALLOC_MEMORY_PROVIDER_OPS, NULL, - &malloc_memory_provider); + umf_result = umfMemoryProviderCreate(&BA_GLOBAL_SPLIT_MERGE_OPS, NULL, + &ba_global_provider); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_NE(malloc_memory_provider, nullptr); + ASSERT_NE(ba_global_provider, nullptr); const size_t init_buffer_size = 20 * MB; @@ -621,8 +698,7 @@ TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_purge_with_upstream) { // make sure there are no undefined members - prevent a UB memset(&coarse_memory_provider_params, 0, sizeof(coarse_memory_provider_params)); - coarse_memory_provider_params.upstream_memory_provider = - malloc_memory_provider; + coarse_memory_provider_params.upstream_memory_provider = ba_global_provider; coarse_memory_provider_params.immediate_init_from_upstream = true; coarse_memory_provider_params.init_buffer = NULL; coarse_memory_provider_params.init_buffer_size = init_buffer_size; @@ -643,7 +719,7 @@ TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_purge_with_upstream) { umf_result = umfMemoryProviderPurgeLazy(coarse_memory_provider, nullptr, 1); ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); - // malloc_memory_provider returns UMF_RESULT_ERROR_UNKNOWN + // ba_global_provider returns UMF_RESULT_ERROR_UNKNOWN umf_result = umfMemoryProviderPurgeLazy(coarse_memory_provider, (void *)0x01, 1); ASSERT_EQ(umf_result, UMF_RESULT_ERROR_UNKNOWN); @@ -658,11 +734,11 @@ TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_purge_with_upstream) { umfMemoryProviderPurgeForce(coarse_memory_provider, nullptr, 1); ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); - // malloc_memory_provider returns UMF_RESULT_ERROR_UNKNOWN + // ba_global_provider returns UMF_RESULT_ERROR_UNKNOWN umf_result = umfMemoryProviderPurgeForce(coarse_memory_provider, (void *)0x01, 1); ASSERT_EQ(umf_result, UMF_RESULT_ERROR_UNKNOWN); umfMemoryProviderDestroy(coarse_memory_provider); - umfMemoryProviderDestroy(malloc_memory_provider); + umfMemoryProviderDestroy(ba_global_provider); } From de334f0457248469f9fe7655f74a984d5385291f Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 18 Nov 2024 18:25:49 +0100 Subject: [PATCH 3/4] Implement IPC API of the Coarse provider Fixes: #900 Signed-off-by: Lukasz Dorau --- src/provider/provider_coarse.c | 88 ++++++++++++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 3 deletions(-) diff --git a/src/provider/provider_coarse.c b/src/provider/provider_coarse.c index fda80712c..a7bb3b9be 100644 --- a/src/provider/provider_coarse.c +++ b/src/provider/provider_coarse.c @@ -1504,6 +1504,91 @@ static umf_result_t coarse_memory_provider_allocation_merge(void *provider, return umf_result; } +static umf_result_t coarse_memory_provider_get_ipc_handle_size(void *provider, + size_t *size) { + assert(provider); + assert(size); + + coarse_memory_provider_t *coarse_provider = + (struct coarse_memory_provider_t *)provider; + if (!coarse_provider->upstream_memory_provider) { + LOG_ERR("missing upstream memory provider"); + return UMF_RESULT_ERROR_NOT_SUPPORTED; + } + + return umfMemoryProviderGetIPCHandleSize( + coarse_provider->upstream_memory_provider, size); +} + +static umf_result_t +coarse_memory_provider_get_ipc_handle(void *provider, const void *ptr, + size_t size, void *providerIpcData) { + assert(provider); + assert(ptr); + assert(providerIpcData); + + coarse_memory_provider_t *coarse_provider = + (struct coarse_memory_provider_t *)provider; + if (!coarse_provider->upstream_memory_provider) { + LOG_ERR("missing upstream memory provider"); + return UMF_RESULT_ERROR_NOT_SUPPORTED; + } + + return umfMemoryProviderGetIPCHandle( + coarse_provider->upstream_memory_provider, ptr, size, providerIpcData); +} + +static umf_result_t +coarse_memory_provider_put_ipc_handle(void *provider, void *providerIpcData) { + assert(provider); + assert(providerIpcData); + + coarse_memory_provider_t *coarse_provider = + (struct coarse_memory_provider_t *)provider; + if (!coarse_provider->upstream_memory_provider) { + LOG_ERR("missing upstream memory provider"); + return UMF_RESULT_ERROR_NOT_SUPPORTED; + } + + return umfMemoryProviderPutIPCHandle( + coarse_provider->upstream_memory_provider, providerIpcData); +} + +static umf_result_t +coarse_memory_provider_open_ipc_handle(void *provider, void *providerIpcData, + void **ptr) { + assert(provider); + assert(providerIpcData); + assert(ptr); + + coarse_memory_provider_t *coarse_provider = + (struct coarse_memory_provider_t *)provider; + if (!coarse_provider->upstream_memory_provider) { + LOG_ERR("missing upstream memory provider"); + return UMF_RESULT_ERROR_NOT_SUPPORTED; + } + + return umfMemoryProviderOpenIPCHandle( + coarse_provider->upstream_memory_provider, providerIpcData, ptr); +} + +static umf_result_t coarse_memory_provider_close_ipc_handle(void *provider, + void *ptr, + size_t size) { + assert(provider); + assert(ptr); + + coarse_memory_provider_t *coarse_provider = + (struct coarse_memory_provider_t *)provider; + if (!coarse_provider->upstream_memory_provider) { + LOG_ERR("missing upstream memory provider"); + return UMF_RESULT_ERROR_NOT_SUPPORTED; + } + + return umfMemoryProviderCloseIPCHandle( + coarse_provider->upstream_memory_provider, ptr, size); +} + umf_memory_provider_ops_t UMF_COARSE_MEMORY_PROVIDER_OPS = { .version = UMF_VERSION_CURRENT, .initialize = coarse_memory_provider_initialize, @@ -1519,14 +1604,11 @@ umf_memory_provider_ops_t UMF_COARSE_MEMORY_PROVIDER_OPS = { .ext.purge_force = coarse_memory_provider_purge_force, .ext.allocation_merge = coarse_memory_provider_allocation_merge, .ext.allocation_split = coarse_memory_provider_allocation_split, - // TODO - /* .ipc.get_ipc_handle_size = coarse_memory_provider_get_ipc_handle_size, .ipc.get_ipc_handle = coarse_memory_provider_get_ipc_handle, .ipc.put_ipc_handle = coarse_memory_provider_put_ipc_handle, .ipc.open_ipc_handle = coarse_memory_provider_open_ipc_handle, .ipc.close_ipc_handle = coarse_memory_provider_close_ipc_handle, - */ }; umf_memory_provider_ops_t *umfCoarseMemoryProviderOps(void) { From 2ac56a19b096f0f3914889d89c5109e307525d51 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 20 Nov 2024 10:48:13 +0100 Subject: [PATCH 4/4] Add the coarseProvider_split_merge_file_prov test Signed-off-by: Lukasz Dorau --- test/CMakeLists.txt | 8 +++ test/provider_coarse.cpp | 106 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 112 insertions(+), 2 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f243aaa51..d32a11950 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -60,6 +60,14 @@ function(build_umf_test) SRCS ${ARG_SRCS} LIBS ${TEST_LIBS}) + if(UMF_BUILD_LEVEL_ZERO_PROVIDER) + target_compile_definitions(${TEST_TARGET_NAME} + PRIVATE UMF_BUILD_LEVEL_ZERO_PROVIDER=1) + endif() + if(UMF_BUILD_CUDA_PROVIDER) + target_compile_definitions(${TEST_TARGET_NAME} + PRIVATE UMF_BUILD_CUDA_PROVIDER=1) + endif() if(UMF_POOL_JEMALLOC_ENABLED) target_compile_definitions(${TEST_TARGET_NAME} PRIVATE UMF_POOL_JEMALLOC_ENABLED=1) diff --git a/test/provider_coarse.cpp b/test/provider_coarse.cpp index dfa6b3d68..cf799e309 100644 --- a/test/provider_coarse.cpp +++ b/test/provider_coarse.cpp @@ -7,11 +7,13 @@ #include -#include "provider.hpp" - +#include +#include #include #include +#include "provider.hpp" + using umf_test::BA_GLOBAL_SPLIT_MERGE_OPS; using umf_test::KB; using umf_test::MB; @@ -417,6 +419,106 @@ TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_merge_upstream) { umfMemoryProviderDestroy(coarse_memory_provider); umfMemoryProviderDestroy(file_memory_provider); } + +TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_split_merge_file_prov) { + umf_memory_provider_handle_t file_memory_provider; + umf_result_t umf_result; + + umf_file_memory_provider_params_t file_params = + umfFileMemoryProviderParamsDefault(FILE_PATH); + file_params.visibility = UMF_MEM_MAP_SHARED; + + umf_result = umfMemoryProviderCreate(umfFileMemoryProviderOps(), + &file_params, &file_memory_provider); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(file_memory_provider, nullptr); + + const size_t init_buffer_size = 8 * KB; + + coarse_memory_provider_params_t coarse_memory_provider_params; + // make sure there are no undefined members - prevent a UB + memset(&coarse_memory_provider_params, 0, + sizeof(coarse_memory_provider_params)); + coarse_memory_provider_params.upstream_memory_provider = + file_memory_provider; + coarse_memory_provider_params.immediate_init_from_upstream = true; + coarse_memory_provider_params.init_buffer = NULL; + coarse_memory_provider_params.init_buffer_size = init_buffer_size; + coarse_memory_provider_params.destroy_upstream_memory_provider = true; + + umf_memory_provider_handle_t coarse_memory_provider; + umf_result = umfMemoryProviderCreate(umfCoarseMemoryProviderOps(), + &coarse_memory_provider_params, + &coarse_memory_provider); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(coarse_memory_provider, nullptr); + + umf_memory_pool_handle_t pool; + umf_result = + umfPoolCreate(umfProxyPoolOps(), coarse_memory_provider, nullptr, + UMF_POOL_CREATE_FLAG_OWN_PROVIDER, &pool); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(pool, nullptr); + + umf_memory_provider_handle_t cp = coarse_memory_provider; + void *ptr1 = nullptr; + void *ptr2 = nullptr; + + ASSERT_EQ(GetStats(cp).used_size, 0 * MB); + ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size); + ASSERT_EQ(GetStats(cp).num_all_blocks, 1); + + ptr1 = umfPoolMalloc(pool, init_buffer_size / 2); + ASSERT_NE(ptr1, nullptr); + ASSERT_EQ(GetStats(cp).used_size, init_buffer_size / 2); + ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size); + ASSERT_EQ(GetStats(cp).num_all_blocks, 2); + + ptr2 = umfPoolMalloc(pool, init_buffer_size / 2); + ASSERT_NE(ptr2, nullptr); + ASSERT_EQ(GetStats(cp).used_size, init_buffer_size); + ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size); + ASSERT_EQ(GetStats(cp).num_all_blocks, 2); + + umf_ipc_handle_t ipcHandle1 = nullptr; + umf_ipc_handle_t ipcHandle2 = nullptr; + size_t handleSize1 = 0; + size_t handleSize2 = 0; + void *handle1 = nullptr; + void *handle2 = nullptr; + + umf_result = umfGetIPCHandle(ptr1, &ipcHandle1, &handleSize1); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = umfGetIPCHandle(ptr2, &ipcHandle2, &handleSize2); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_EQ(handleSize1, handleSize2); + + umf_result = umfOpenIPCHandle(pool, ipcHandle1, &handle1); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = umfOpenIPCHandle(pool, ipcHandle2, &handle2); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_result = umfCloseIPCHandle(handle1); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = umfCloseIPCHandle(handle2); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_result = umfPutIPCHandle(ipcHandle1); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = umfPutIPCHandle(ipcHandle2); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_result = umfPoolFree(pool, ptr1); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = umfPoolFree(pool, ptr2); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + ASSERT_EQ(GetStats(cp).used_size, 0); + ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size); + ASSERT_EQ(GetStats(cp).num_all_blocks, 1); + + umfPoolDestroy(pool); +} #endif /* !defined(_WIN32) && !defined(UMF_DISABLE_HWLOC) */ TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_split_merge) {