From c6749f2b7a92f0d11d7b831d984249e5d3d4d786 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Fri, 29 Nov 2024 11:54:44 +0100 Subject: [PATCH 1/3] Remove the Coarse provider Fixes: #900 Signed-off-by: Lukasz Dorau --- include/umf/providers/provider_coarse.h | 116 -- src/CMakeLists.txt | 1 - src/libumf.def | 2 - src/libumf.map | 2 - src/provider/provider_coarse.c | 1693 ----------------------- test/CMakeLists.txt | 15 +- test/disjointCoarseMallocPool.cpp | 317 +---- test/memoryPoolAPI.cpp | 8 +- test/poolFixtures.hpp | 25 +- test/pools/disjoint_pool.cpp | 19 +- test/pools/jemalloc_coarse_devdax.cpp | 10 +- test/pools/jemalloc_coarse_file.cpp | 4 +- test/pools/jemalloc_pool.cpp | 8 +- test/pools/pool_base_alloc.cpp | 2 +- test/pools/pool_coarse.hpp | 2 - test/pools/scalable_coarse_devdax.cpp | 10 +- test/pools/scalable_coarse_file.cpp | 4 +- test/pools/scalable_pool.cpp | 3 +- test/provider_coarse.cpp | 668 --------- 19 files changed, 86 insertions(+), 2823 deletions(-) delete mode 100644 include/umf/providers/provider_coarse.h delete mode 100644 src/provider/provider_coarse.c delete mode 100644 test/provider_coarse.cpp diff --git a/include/umf/providers/provider_coarse.h b/include/umf/providers/provider_coarse.h deleted file mode 100644 index 6ed6e0fbc..000000000 --- a/include/umf/providers/provider_coarse.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2023-2024 Intel Corporation - * - * Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -*/ - -#ifndef UMF_COARSE_PROVIDER_H -#define UMF_COARSE_PROVIDER_H - -#include -#include - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/// @brief Coarse Memory Provider allocation strategy -typedef enum coarse_memory_provider_strategy_t { - /// Always allocate a free block of the (size + alignment) size - /// and cut out the properly aligned part leaving two remaining parts. - /// It is the fastest strategy but causes memory fragmentation - /// when alignment is greater than 0. - /// It is the best strategy when alignment always equals 0. - UMF_COARSE_MEMORY_STRATEGY_FASTEST = 0, - - /// Check if the first free block of the 'size' size has the correct alignment. - /// If not, use the `UMF_COARSE_MEMORY_STRATEGY_FASTEST` strategy. - UMF_COARSE_MEMORY_STRATEGY_FASTEST_BUT_ONE, - - /// Look through all free blocks of the 'size' size - /// and choose the first one with the correct alignment. - /// If none of them had the correct alignment, - /// use the `UMF_COARSE_MEMORY_STRATEGY_FASTEST` strategy. - UMF_COARSE_MEMORY_STRATEGY_CHECK_ALL_SIZE, - - /// The maximum value (it has to be the last one). - UMF_COARSE_MEMORY_STRATEGY_MAX -} coarse_memory_provider_strategy_t; - -/// @brief Coarse Memory Provider settings struct. -typedef struct coarse_memory_provider_params_t { - /// Handle to the upstream memory provider. - /// It has to be NULL if init_buffer is set - /// (exactly one of them has to be non-NULL). - umf_memory_provider_handle_t upstream_memory_provider; - - /// Memory allocation strategy. - /// See coarse_memory_provider_strategy_t for details. - coarse_memory_provider_strategy_t allocation_strategy; - - /// A pre-allocated buffer that will be the only memory that - /// the coarse provider can provide (the fixed-size memory provider option). - /// If it is non-NULL, `init_buffer_size ` has to contain its size. - /// It has to be NULL if upstream_memory_provider is set - /// (exactly one of them has to be non-NULL). - void *init_buffer; - - /// Size of the initial buffer: - /// 1) `init_buffer` if it is non-NULL xor - /// 2) that will be allocated from the upstream_memory_provider - /// (if it is non-NULL) in the `.initialize` operation. - size_t init_buffer_size; - - /// When it is true and the upstream_memory_provider is given, - /// the init buffer (of `init_buffer_size` bytes) would be pre-allocated - /// during creation time using the `upstream_memory_provider`. - /// If upstream_memory_provider is not given, - /// the init_buffer is always used instead - /// (regardless of the value of this parameter). - bool immediate_init_from_upstream; - - /// Destroy upstream_memory_provider in finalize(). - bool destroy_upstream_memory_provider; -} coarse_memory_provider_params_t; - -/// @brief Coarse Memory Provider stats (TODO move to CTL) -typedef struct coarse_memory_provider_stats_t { - /// Total allocation size. - size_t alloc_size; - - /// Size of used memory. - size_t used_size; - - /// Number of memory blocks allocated from the upstream provider. - size_t num_upstream_blocks; - - /// Total number of allocated memory blocks. - size_t num_all_blocks; - - /// Number of free memory blocks. - size_t num_free_blocks; -} coarse_memory_provider_stats_t; - -umf_memory_provider_ops_t *umfCoarseMemoryProviderOps(void); - -// TODO use CTL -coarse_memory_provider_stats_t -umfCoarseMemoryProviderGetStats(umf_memory_provider_handle_t provider); - -/// @brief Create default params for the coarse memory provider -static inline coarse_memory_provider_params_t -umfCoarseMemoryProviderParamsDefault(void) { - coarse_memory_provider_params_t coarse_memory_provider_params; - memset(&coarse_memory_provider_params, 0, - sizeof(coarse_memory_provider_params)); - return coarse_memory_provider_params; -} - -#ifdef __cplusplus -} -#endif - -#endif // UMF_COARSE_PROVIDER_H diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8b1e2248a..fb32b6d2e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -59,7 +59,6 @@ set(UMF_SOURCES memspaces/memspace_highest_bandwidth.c memspaces/memspace_lowest_latency.c memspaces/memspace_numa.c - provider/provider_coarse.c provider/provider_cuda.c provider/provider_devdax_memory.c provider/provider_file_memory.c diff --git a/src/libumf.def b/src/libumf.def index f2b24be6c..c0cd1c90c 100644 --- a/src/libumf.def +++ b/src/libumf.def @@ -14,8 +14,6 @@ EXPORTS umfTearDown umfGetCurrentVersion umfCloseIPCHandle - umfCoarseMemoryProviderGetStats - umfCoarseMemoryProviderOps umfCUDAMemoryProviderOps umfCUDAMemoryProviderParamsCreate umfCUDAMemoryProviderParamsDestroy diff --git a/src/libumf.map b/src/libumf.map index 067ec8838..8a7bdc81c 100644 --- a/src/libumf.map +++ b/src/libumf.map @@ -8,8 +8,6 @@ UMF_1.0 { umfTearDown; umfGetCurrentVersion; umfCloseIPCHandle; - umfCoarseMemoryProviderGetStats; - umfCoarseMemoryProviderOps; umfCUDAMemoryProviderOps; umfCUDAMemoryProviderParamsCreate; umfCUDAMemoryProviderParamsDestroy; diff --git a/src/provider/provider_coarse.c b/src/provider/provider_coarse.c deleted file mode 100644 index 72985faaf..000000000 --- a/src/provider/provider_coarse.c +++ /dev/null @@ -1,1693 +0,0 @@ -/* - * Copyright (C) 2023-2024 Intel Corporation - * - * Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -*/ - -#include -#include -#include -#include -#include -#include - -#include - -#include "base_alloc_global.h" -#include "memory_provider_internal.h" -#include "ravl.h" -#include "utils_common.h" -#include "utils_concurrency.h" -#include "utils_log.h" - -#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; - - // destroy upstream_memory_provider in finalize() - bool destroy_upstream_memory_provider; - - // memory allocation strategy - coarse_memory_provider_strategy_t allocation_strategy; - - void *init_buffer; - - 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; - - // free_blocks - tree of free blocks - sorted by a size of data, - // each node contains a pointer (ravl_free_blocks_head_t) - // to the head of the list of free blocks of the same size - struct ravl *free_blocks; - - struct utils_mutex_t lock; - - // Name of the provider with the upstream provider: - // "coarse ()" - // for example: "coarse (L0)" - char *name; -} coarse_memory_provider_t; - -typedef struct ravl_node ravl_node_t; - -typedef enum check_free_blocks_t { - CHECK_ONLY_THE_FIRST_BLOCK = 0, - CHECK_ALL_BLOCKS_OF_SIZE, -} check_free_blocks_t; - -typedef struct block_t { - size_t size; - unsigned char *data; - bool used; - - // Node in the list of free blocks of the same size pointing to this block. - // The list is located in the (coarse_provider->free_blocks) RAVL tree. - struct ravl_free_blocks_elem_t *free_list_ptr; -} block_t; - -// A general node in a RAVL tree. -// 1) coarse_provider->all_blocks RAVL tree (tree of all blocks - sorted by an address of data): -// key - pointer (block_t->data) to the beginning of the block data -// value - pointer (block_t) to the block of the allocation -// 2) coarse_provider->free_blocks RAVL tree (tree of free blocks - sorted by a size of data): -// key - size of the allocation (block_t->size) -// value - pointer (ravl_free_blocks_head_t) to the head of the list of free blocks of the same size -typedef struct ravl_data_t { - uintptr_t key; - void *value; -} ravl_data_t; - -// The head of the list of free blocks of the same size. -typedef struct ravl_free_blocks_head_t { - struct ravl_free_blocks_elem_t *head; -} ravl_free_blocks_head_t; - -// The node of the list of free blocks of the same size -typedef struct ravl_free_blocks_elem_t { - struct block_t *block; - struct ravl_free_blocks_elem_t *next; - struct ravl_free_blocks_elem_t *prev; -} ravl_free_blocks_elem_t; - -// The compare function of a RAVL tree -static int coarse_ravl_comp(const void *lhs, const void *rhs) { - const ravl_data_t *lhs_ravl = (const ravl_data_t *)lhs; - const ravl_data_t *rhs_ravl = (const ravl_data_t *)rhs; - - if (lhs_ravl->key < rhs_ravl->key) { - return -1; - } - - if (lhs_ravl->key > rhs_ravl->key) { - return 1; - } - - // lhs_ravl->key == rhs_ravl->key - return 0; -} - -static inline block_t *get_node_block(ravl_node_t *node) { - ravl_data_t *node_data = ravl_data(node); - assert(node_data); - assert(node_data->value); - return node_data->value; -} - -static inline ravl_node_t *get_node_prev(ravl_node_t *node) { - return ravl_node_predecessor(node); -} - -static inline ravl_node_t *get_node_next(ravl_node_t *node) { - return ravl_node_successor(node); -} - -#ifndef NDEBUG -static block_t *get_block_prev(ravl_node_t *node) { - ravl_node_t *ravl_prev = ravl_node_predecessor(node); - if (!ravl_prev) { - return NULL; - } - - return get_node_block(ravl_prev); -} - -static block_t *get_block_next(ravl_node_t *node) { - ravl_node_t *ravl_next = ravl_node_successor(node); - if (!ravl_next) { - return NULL; - } - - return get_node_block(ravl_next); -} -#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 -// 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 -// and link this block to the next and the previous one. -static block_t *coarse_ravl_add_new(struct ravl *rtree, unsigned char *data, - size_t size, ravl_node_t **node) { - assert(rtree); - assert(data); - assert(size); - - // TODO add valgrind annotations - block_t *block = umf_ba_global_alloc(sizeof(*block)); - if (block == NULL) { - return NULL; - } - - block->data = data; - block->size = size; - block->free_list_ptr = NULL; - - ravl_data_t rdata = {(uintptr_t)block->data, block}; - assert(NULL == ravl_find(rtree, &data, RAVL_PREDICATE_EQUAL)); - int ret = ravl_emplace_copy(rtree, &rdata); - if (ret) { - umf_ba_global_free(block); - return NULL; - } - - ravl_node_t *new_node = ravl_find(rtree, &rdata, RAVL_PREDICATE_EQUAL); - assert(NULL != new_node); - - if (node) { - *node = new_node; - } - - return block; -} - -// coarse_ravl_find_node - find the node in the tree -static ravl_node_t *coarse_ravl_find_node(struct ravl *rtree, void *ptr) { - ravl_data_t data = {(uintptr_t)ptr, NULL}; - return ravl_find(rtree, &data, RAVL_PREDICATE_EQUAL); -} - -// coarse_ravl_rm - remove the block from the tree -static block_t *coarse_ravl_rm(struct ravl *rtree, void *ptr) { - ravl_data_t data = {(uintptr_t)ptr, NULL}; - ravl_node_t *node; - node = ravl_find(rtree, &data, RAVL_PREDICATE_EQUAL); - if (node) { - ravl_data_t *node_data = ravl_data(node); - assert(node_data); - block_t *block = node_data->value; - assert(block); - ravl_remove(rtree, node); - assert(NULL == ravl_find(rtree, &data, RAVL_PREDICATE_EQUAL)); - return block; - } - return NULL; -} - -// The functions "node_list_*" handle lists of free blocks of the same size. -// The heads (ravl_free_blocks_head_t) of those lists are stored in nodes of -// the coarse_provider->free_blocks RAVL tree. -// -// node_list_add - add a free block to the list of free blocks of the same size -static ravl_free_blocks_elem_t * -node_list_add(ravl_free_blocks_head_t *head_node, struct block_t *block) { - assert(head_node); - assert(block); - - ravl_free_blocks_elem_t *node = umf_ba_global_alloc(sizeof(*node)); - if (node == NULL) { - return NULL; - } - - if (head_node->head) { - head_node->head->prev = node; - } - - node->block = block; - node->next = head_node->head; - node->prev = NULL; - head_node->head = node; - - return node; -} - -// node_list_rm - remove the given free block from the list of free blocks of the same size -static block_t *node_list_rm(ravl_free_blocks_head_t *head_node, - ravl_free_blocks_elem_t *node) { - assert(head_node); - assert(node); - - if (!head_node->head) { - return NULL; - } - - if (node == head_node->head) { - assert(node->prev == NULL); - head_node->head = node->next; - } - - ravl_free_blocks_elem_t *node_next = node->next; - ravl_free_blocks_elem_t *node_prev = node->prev; - if (node_next) { - node_next->prev = node_prev; - } - - if (node_prev) { - node_prev->next = node_next; - } - - struct block_t *block = node->block; - block->free_list_ptr = NULL; - umf_ba_global_free(node); - - return block; -} - -// node_list_rm_first - remove the first free block from the list of free blocks of the same size only if it can be properly aligned -static block_t *node_list_rm_first(ravl_free_blocks_head_t *head_node, - size_t alignment) { - assert(head_node); - - if (!head_node->head) { - return NULL; - } - - ravl_free_blocks_elem_t *node = head_node->head; - assert(node->prev == NULL); - struct block_t *block = node->block; - - if (IS_NOT_ALIGNED(block->size, alignment)) { - return NULL; - } - - if (node->next) { - node->next->prev = NULL; - } - - head_node->head = node->next; - block->free_list_ptr = NULL; - umf_ba_global_free(node); - - return block; -} - -// node_list_rm_with_alignment - remove the first free block with the correct alignment from the list of free blocks of the same size -static block_t *node_list_rm_with_alignment(ravl_free_blocks_head_t *head_node, - size_t alignment) { - assert(head_node); - - if (!head_node->head) { - return NULL; - } - - assert(((ravl_free_blocks_elem_t *)head_node->head)->prev == NULL); - - ravl_free_blocks_elem_t *node; - for (node = head_node->head; node != NULL; node = node->next) { - if (IS_ALIGNED(node->block->size, alignment)) { - return node_list_rm(head_node, node); - } - } - - return NULL; -} - -// The functions "free_blocks_*" handle the coarse_provider->free_blocks RAVL tree -// sorted by a size of the allocation (block_t->size). -// This is a tree of heads (ravl_free_blocks_head_t) of lists of free blocks of the same size. -// -// free_blocks_add - add a free block to the list of free blocks of the same size -static int free_blocks_add(struct ravl *free_blocks, block_t *block) { - ravl_free_blocks_head_t *head_node = NULL; - int rv; - - ravl_data_t head_node_data = {(uintptr_t)block->size, NULL}; - ravl_node_t *node; - node = ravl_find(free_blocks, &head_node_data, RAVL_PREDICATE_EQUAL); - if (node) { - ravl_data_t *node_data = ravl_data(node); - assert(node_data); - head_node = node_data->value; - assert(head_node); - } else { // no head_node - head_node = umf_ba_global_alloc(sizeof(*head_node)); - if (!head_node) { - return -1; - } - - head_node->head = NULL; - - ravl_data_t data = {(uintptr_t)block->size, head_node}; - rv = ravl_emplace_copy(free_blocks, &data); - if (rv) { - umf_ba_global_free(head_node); - return -1; - } - } - - block->free_list_ptr = node_list_add(head_node, block); - if (!block->free_list_ptr) { - return -1; - } - - assert(block->free_list_ptr->block->size == block->size); - - return 0; -} - -// free_blocks_rm_ge - remove the first free block of a size greater or equal to the given size only if it can be properly aligned -// If it was the last block, the head node is freed and removed from the tree. -// It is used during memory allocation (looking for a free block). -static block_t *free_blocks_rm_ge(struct ravl *free_blocks, size_t size, - size_t alignment, - check_free_blocks_t check_blocks) { - ravl_data_t data = {(uintptr_t)size, NULL}; - ravl_node_t *node; - node = ravl_find(free_blocks, &data, RAVL_PREDICATE_GREATER_EQUAL); - if (!node) { - return NULL; - } - - ravl_data_t *node_data = ravl_data(node); - assert(node_data); - assert(node_data->key >= size); - - ravl_free_blocks_head_t *head_node = node_data->value; - assert(head_node); - - block_t *block; - switch (check_blocks) { - case CHECK_ONLY_THE_FIRST_BLOCK: - block = node_list_rm_first(head_node, alignment); - break; - case CHECK_ALL_BLOCKS_OF_SIZE: - block = node_list_rm_with_alignment(head_node, alignment); - break; - // wrong value of check_blocks - default: - abort(); - } - - if (head_node->head == NULL) { - umf_ba_global_free(head_node); - ravl_remove(free_blocks, node); - } - - return block; -} - -// free_blocks_rm_node - remove the free block pointed by the given node. -// If it was the last block, the head node is freed and removed from the tree. -// It is used during merging free blocks and destroying the coarse_provider->free_blocks tree. -static block_t *free_blocks_rm_node(struct ravl *free_blocks, - ravl_free_blocks_elem_t *node) { - assert(free_blocks); - assert(node); - size_t size = node->block->size; - ravl_data_t data = {(uintptr_t)size, NULL}; - ravl_node_t *ravl_node; - ravl_node = ravl_find(free_blocks, &data, RAVL_PREDICATE_EQUAL); - assert(ravl_node); - - ravl_data_t *node_data = ravl_data(ravl_node); - assert(node_data); - assert(node_data->key == size); - - ravl_free_blocks_head_t *head_node = node_data->value; - assert(head_node); - - block_t *block = node_list_rm(head_node, node); - - if (head_node->head == NULL) { - umf_ba_global_free(head_node); - ravl_remove(free_blocks, ravl_node); - } - - return block; -} - -// user_block_merge - merge two blocks from one of two lists of user blocks: all_blocks or free_blocks -static umf_result_t user_block_merge(coarse_memory_provider_t *coarse_provider, - ravl_node_t *node1, ravl_node_t *node2, - bool used, ravl_node_t **merged_node) { - assert(node1); - assert(node2); - assert(node1 == get_node_prev(node2)); - assert(node2 == get_node_next(node1)); - assert(merged_node); - - *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; - - block_t *block1 = get_node_block(node1); - block_t *block2 = get_node_block(node2); - assert(block1->data < block2->data); - - 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) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - - if (block1->free_list_ptr) { - free_blocks_rm_node(free_blocks, block1->free_list_ptr); - block1->free_list_ptr = NULL; - } - - if (block2->free_list_ptr) { - free_blocks_rm_node(free_blocks, block2->free_list_ptr); - block2->free_list_ptr = NULL; - } - - // update the size - block1->size += block2->size; - - block_t *block_rm = coarse_ravl_rm(all_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; -} - -// free_block_merge_with_prev - merge the given free block -// with the previous one if both are unused and have continuous data. -// Remove the merged block from the tree of free blocks. -static ravl_node_t * -free_block_merge_with_prev(coarse_memory_provider_t *coarse_provider, - ravl_node_t *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 = - user_block_merge(coarse_provider, node_prev, node, false, &merged_node); - if (umf_result != UMF_RESULT_SUCCESS) { - return node; - } - - assert(merged_node != NULL); - - return merged_node; -} - -// free_block_merge_with_next - merge the given free block -// with the next one if both are unused and have continuous data. -// Remove the merged block from the tree of free blocks. -static ravl_node_t * -free_block_merge_with_next(coarse_memory_provider_t *coarse_provider, - ravl_node_t *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 = - user_block_merge(coarse_provider, node, node_next, false, &merged_node); - if (umf_result != UMF_RESULT_SUCCESS) { - return node; - } - - assert(merged_node != NULL); - - 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 { - coarse_memory_provider_t *provider; - size_t sum_used; - 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) { - assert(data); - assert(arg); - - ravl_data_t *node_data = data; - block_t *block = node_data->value; - assert(block); - - 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->all_blocks, data, RAVL_PREDICATE_EQUAL); - assert(node); - - block_t *block_next = get_block_next(node); - block_t *block_prev = get_block_prev(node); - - cb_args->num_all_blocks++; - if (!block->used) { - cb_args->num_free_blocks++; - } - - 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); - } - - if (block_next) { - assert(block->data < block_next->data); - } - - // two block's data should not overlap - if (block_next) { - assert((block->data + block->size) <= block_next->data); - } - - cb_args->sum_blocks_size += block->size; - if (block->used) { - cb_args->sum_used += block->size; - } -} - -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); - -static bool debug_check(coarse_memory_provider_t *provider) { - assert(provider); - - coarse_memory_provider_stats_t stats = {0}; - coarse_memory_provider_get_stats(provider, &stats); - - debug_cb_args_t cb_args = {0}; - cb_args.provider = provider; - - // verify the all_blocks list - ravl_foreach(provider->all_blocks, debug_verify_all_blocks_cb, &cb_args); - - assert(cb_args.num_all_blocks == stats.num_all_blocks); - assert(cb_args.num_free_blocks == stats.num_free_blocks); - assert(cb_args.sum_used == provider->used_size); - 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; - } - - 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; - - return UMF_RESULT_SUCCESS; -} - -static umf_result_t -coarse_memory_provider_set_name(coarse_memory_provider_t *coarse_provider) { - if (coarse_provider->upstream_memory_provider == NULL) { - // COARSE_BASE_NAME will be used - coarse_provider->name = NULL; - return UMF_RESULT_SUCCESS; - } - - const char *up_name = - umfMemoryProviderGetName(coarse_provider->upstream_memory_provider); - if (!up_name) { - return UMF_RESULT_ERROR_UNKNOWN; - } - - size_t length = - strlen(COARSE_BASE_NAME) + strlen(up_name) + 3; // + 3 for " ()" - - coarse_provider->name = umf_ba_global_alloc(length + 1); // + 1 for '\0' - if (coarse_provider->name == NULL) { - return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; - } - - sprintf(coarse_provider->name, "%s (%s)", COARSE_BASE_NAME, up_name); - - return UMF_RESULT_SUCCESS; -} - -// needed for coarse_memory_provider_initialize() -static umf_result_t coarse_memory_provider_alloc(void *provider, size_t size, - size_t alignment, - void **resultPtr); - -// needed for coarse_memory_provider_initialize() -static umf_result_t coarse_memory_provider_free(void *provider, void *ptr, - size_t bytes); - -static umf_result_t coarse_memory_provider_initialize(void *params, - void **provider) { - assert(provider); - - if (params == NULL) { - LOG_ERR("coarse provider parameters are missing"); - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - - coarse_memory_provider_params_t *coarse_params = - (coarse_memory_provider_params_t *)params; - - // check params - if (!coarse_params->upstream_memory_provider == - !coarse_params->init_buffer) { - LOG_ERR("either upstream provider or init buffer has to be provided in " - "the parameters (exactly one of them)"); - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - - if (coarse_params->init_buffer_size == 0 && - (coarse_params->immediate_init_from_upstream || - coarse_params->init_buffer != NULL)) { - LOG_ERR("init_buffer_size has to be greater than 0 if " - "immediate_init_from_upstream or init_buffer is set"); - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - - if (coarse_params->init_buffer_size != 0 && - (!coarse_params->immediate_init_from_upstream && - coarse_params->init_buffer == NULL)) { - LOG_ERR("init_buffer_size is greater than 0 but none of " - "immediate_init_from_upstream nor init_buffer is set"); - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - - if (coarse_params->destroy_upstream_memory_provider && - !coarse_params->upstream_memory_provider) { - LOG_ERR("destroy_upstream_memory_provider is true, but an upstream " - "provider is not provided"); - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - - coarse_memory_provider_t *coarse_provider = - umf_ba_global_alloc(sizeof(*coarse_provider)); - if (!coarse_provider) { - LOG_ERR("out of the host memory"); - return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; - } - - memset(coarse_provider, 0, sizeof(*coarse_provider)); - - coarse_provider->upstream_memory_provider = - coarse_params->upstream_memory_provider; - coarse_provider->destroy_upstream_memory_provider = - coarse_params->destroy_upstream_memory_provider; - coarse_provider->allocation_strategy = coarse_params->allocation_strategy; - coarse_provider->init_buffer = coarse_params->init_buffer; - - umf_result_t umf_result = coarse_memory_provider_set_name(coarse_provider); - if (umf_result != UMF_RESULT_SUCCESS) { - LOG_ERR("name initialization failed"); - goto err_free_coarse_provider; - } - - // 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; - } - - coarse_provider->all_blocks = - ravl_new_sized(coarse_ravl_comp, sizeof(ravl_data_t)); - if (coarse_provider->all_blocks == NULL) { - LOG_ERR("out of the host memory"); - goto err_delete_ravl_free_blocks; - } - - coarse_provider->alloc_size = 0; - coarse_provider->used_size = 0; - - if (utils_mutex_init(&coarse_provider->lock) == NULL) { - LOG_ERR("lock initialization failed"); - umf_result = UMF_RESULT_ERROR_UNKNOWN; - goto err_delete_ravl_all_blocks; - } - - if (coarse_params->upstream_memory_provider && - coarse_params->immediate_init_from_upstream) { - // allocate and immediately deallocate memory using the upstream provider - void *init_buffer = NULL; - coarse_memory_provider_alloc( - coarse_provider, coarse_params->init_buffer_size, 0, &init_buffer); - if (init_buffer == NULL) { - goto err_destroy_mutex; - } - - coarse_memory_provider_free(coarse_provider, init_buffer, - 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); - if (umf_result != UMF_RESULT_SUCCESS) { - goto err_destroy_mutex; - } - - LOG_DEBUG("coarse_ALLOC (init_buffer) %zu used %zu alloc %zu", - coarse_params->init_buffer_size, coarse_provider->used_size, - coarse_provider->alloc_size); - - coarse_memory_provider_free(coarse_provider, - coarse_provider->init_buffer, - coarse_params->init_buffer_size); - } - - assert(coarse_provider->used_size == 0); - assert(coarse_provider->alloc_size == coarse_params->init_buffer_size); - assert(debug_check(coarse_provider)); - - *provider = coarse_provider; - - return UMF_RESULT_SUCCESS; - -err_destroy_mutex: - utils_mutex_destroy_not_free(&coarse_provider->lock); -err_delete_ravl_all_blocks: - 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: - umf_ba_global_free(coarse_provider); - return umf_result; -} - -static void coarse_ravl_cb_rm_upstream_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); - - if (coarse_provider->upstream_memory_provider) { - // We continue to deallocate alloc blocks even if the upstream provider doesn't return success. - umfMemoryProviderFree(coarse_provider->upstream_memory_provider, - alloc->data, alloc->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); - - if (block->used) { - assert(coarse_provider->used_size >= block->size); - coarse_provider->used_size -= block->size; - } - - if (block->free_list_ptr) { - free_blocks_rm_node(coarse_provider->free_blocks, block->free_list_ptr); - } - - umf_ba_global_free(block); -} - -static void coarse_memory_provider_finalize(void *provider) { - coarse_memory_provider_t *coarse_provider = - (struct coarse_memory_provider_t *)provider; - - utils_mutex_destroy_not_free(&coarse_provider->lock); - - 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); - - umf_ba_global_free(coarse_provider->name); - - if (coarse_provider->destroy_upstream_memory_provider && - coarse_provider->upstream_memory_provider) { - umfMemoryProviderDestroy(coarse_provider->upstream_memory_provider); - } - - umf_ba_global_free(coarse_provider); -} - -static umf_result_t -create_aligned_block(coarse_memory_provider_t *coarse_provider, - size_t orig_size, size_t alignment, block_t **current) { - (void)orig_size; // unused in the Release version - int rv; - - block_t *curr = *current; - - // In case of non-zero alignment create an aligned block what would be further used. - uintptr_t orig_data = (uintptr_t)curr->data; - uintptr_t aligned_data = ALIGN_UP(orig_data, alignment); - size_t padding = aligned_data - orig_data; - if (alignment > 0 && padding > 0) { - block_t *aligned_block = coarse_ravl_add_new( - coarse_provider->all_blocks, curr->data + padding, - curr->size - padding, NULL); - if (aligned_block == NULL) { - return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; - } - - curr->used = false; - curr->size = padding; - - rv = free_blocks_add(coarse_provider->free_blocks, curr); - if (rv) { - return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; - } - - // use aligned block - *current = aligned_block; - assert((*current)->size >= orig_size); - } - - return UMF_RESULT_SUCCESS; -} - -// Split the current block and put the new block after the one that we use. -static umf_result_t -split_current_block(coarse_memory_provider_t *coarse_provider, block_t *curr, - size_t size) { - ravl_node_t *new_node = NULL; - - block_t *new_block = - coarse_ravl_add_new(coarse_provider->all_blocks, curr->data + size, - curr->size - size, &new_node); - if (new_block == NULL) { - return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; - } - - new_block->used = false; - - int rv = - free_blocks_add(coarse_provider->free_blocks, get_node_block(new_node)); - if (rv) { - return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; - } - - return UMF_RESULT_SUCCESS; -} - -static block_t * -find_free_block(struct ravl *free_blocks, size_t size, size_t alignment, - coarse_memory_provider_strategy_t allocation_strategy) { - block_t *block; - - switch (allocation_strategy) { - case UMF_COARSE_MEMORY_STRATEGY_FASTEST: - // Always allocate a free block of the (size + alignment) size - // and later cut out the properly aligned part leaving two remaining parts. - return free_blocks_rm_ge(free_blocks, size + alignment, 0, - CHECK_ONLY_THE_FIRST_BLOCK); - - case UMF_COARSE_MEMORY_STRATEGY_FASTEST_BUT_ONE: - // First check if the first free block of the 'size' size has the correct alignment. - block = free_blocks_rm_ge(free_blocks, size, alignment, - CHECK_ONLY_THE_FIRST_BLOCK); - if (block) { - return block; - } - - // If not, use the `UMF_COARSE_MEMORY_STRATEGY_FASTEST` strategy. - return free_blocks_rm_ge(free_blocks, size + alignment, 0, - CHECK_ONLY_THE_FIRST_BLOCK); - - case UMF_COARSE_MEMORY_STRATEGY_CHECK_ALL_SIZE: - // First look through all free blocks of the 'size' size - // and choose the first one with the correct alignment. - block = free_blocks_rm_ge(free_blocks, size, alignment, - CHECK_ALL_BLOCKS_OF_SIZE); - if (block) { - return block; - } - - // If none of them had the correct alignment, - // use the `UMF_COARSE_MEMORY_STRATEGY_FASTEST` strategy. - return free_blocks_rm_ge(free_blocks, size + alignment, 0, - CHECK_ONLY_THE_FIRST_BLOCK); - - // unknown memory allocation strategy - default: - abort(); - } -} - -static umf_result_t coarse_memory_provider_alloc(void *provider, size_t size, - size_t alignment, - void **resultPtr) { - umf_result_t umf_result = UMF_RESULT_ERROR_UNKNOWN; - - if (resultPtr == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - - coarse_memory_provider_t *coarse_provider = - (struct coarse_memory_provider_t *)provider; - - if (utils_mutex_lock(&coarse_provider->lock) != 0) { - LOG_ERR("locking the lock failed"); - return UMF_RESULT_ERROR_UNKNOWN; - } - - assert(debug_check(coarse_provider)); - - // Find a block with greater or equal size using the given memory allocation strategy - block_t *curr = - find_free_block(coarse_provider->free_blocks, size, alignment, - coarse_provider->allocation_strategy); - - // If the block that we want to reuse has a greater size, split it. - // Try to merge the split part with the successor if it is not used. - enum { ACTION_NONE = 0, ACTION_USE, ACTION_SPLIT } action = ACTION_NONE; - - if (curr && curr->size > size) { - action = ACTION_SPLIT; - } else if (curr && curr->size == size) { - action = ACTION_USE; - } - - if (action) { // ACTION_SPLIT or ACTION_USE - assert(curr->used == false); - - // In case of non-zero alignment create an aligned block what would be further used. - if (alignment > 0) { - 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; - } - } - - if (action == ACTION_SPLIT) { - // 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; - } - - curr->size = size; - - LOG_DEBUG("coarse_ALLOC (split_block) %zu used %zu alloc %zu", size, - coarse_provider->used_size, coarse_provider->alloc_size); - - } else { // action == ACTION_USE - LOG_DEBUG("coarse_ALLOC (same_block) %zu used %zu alloc %zu", size, - coarse_provider->used_size, coarse_provider->alloc_size); - } - - curr->used = true; - *resultPtr = curr->data; - coarse_provider->used_size += size; - - assert(debug_check(coarse_provider)); - utils_mutex_unlock(&coarse_provider->lock); - - return UMF_RESULT_SUCCESS; - } - - // no suitable block found - try to get more memory from the upstream provider - umf_result = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; - - if (coarse_provider->upstream_memory_provider == NULL) { - LOG_ERR("out of memory - no upstream memory provider given"); - goto err_unlock; - } - - umfMemoryProviderAlloc(coarse_provider->upstream_memory_provider, size, - alignment, resultPtr); - if (*resultPtr == NULL) { - LOG_ERR("out of memory - upstream memory provider allocation failed"); - goto err_unlock; - } - - ASSERT_IS_ALIGNED(((uintptr_t)(*resultPtr)), alignment); - - umf_result = coarse_add_upstream_block(coarse_provider, *resultPtr, size); - if (umf_result != UMF_RESULT_SUCCESS) { - umfMemoryProviderFree(coarse_provider->upstream_memory_provider, - *resultPtr, size); - goto err_unlock; - } - - LOG_DEBUG("coarse_ALLOC (upstream) %zu used %zu alloc %zu", size, - coarse_provider->used_size, coarse_provider->alloc_size); - - umf_result = UMF_RESULT_SUCCESS; - -err_unlock: - assert(debug_check(coarse_provider)); - utils_mutex_unlock(&coarse_provider->lock); - - return umf_result; -} - -static umf_result_t coarse_memory_provider_free(void *provider, void *ptr, - size_t bytes) { - coarse_memory_provider_t *coarse_provider = - (struct coarse_memory_provider_t *)provider; - - if (utils_mutex_lock(&coarse_provider->lock) != 0) { - LOG_ERR("locking the lock failed"); - return UMF_RESULT_ERROR_UNKNOWN; - } - - assert(debug_check(coarse_provider)); - - ravl_node_t *node = coarse_ravl_find_node(coarse_provider->all_blocks, ptr); - if (node == NULL) { - // the block was not found - utils_mutex_unlock(&coarse_provider->lock); - LOG_ERR("memory block not found (ptr = %p, size = %zu)", ptr, bytes); - return UMF_RESULT_ERROR_UNKNOWN; - } - - block_t *block = get_node_block(node); - if (!block->used) { - // the block is already free - utils_mutex_unlock(&coarse_provider->lock); - LOG_ERR("the block is already free"); - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - - if (bytes > 0 && bytes != block->size) { - // wrong size of allocation - utils_mutex_unlock(&coarse_provider->lock); - LOG_ERR("wrong size of allocation"); - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - - LOG_DEBUG("coarse_FREE (return_block_to_pool) %zu used %zu alloc %zu", - block->size, coarse_provider->used_size - block->size, - coarse_provider->alloc_size); - - assert(coarse_provider->used_size >= block->size); - coarse_provider->used_size -= block->size; - - block->used = false; - - // 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); - - int rv = - free_blocks_add(coarse_provider->free_blocks, get_node_block(node)); - if (rv) { - utils_mutex_unlock(&coarse_provider->lock); - return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; - } - - assert(debug_check(coarse_provider)); - utils_mutex_unlock(&coarse_provider->lock); - - return UMF_RESULT_SUCCESS; -} - -static void coarse_memory_provider_get_last_native_error(void *provider, - const char **ppMessage, - int32_t *pError) { - (void)provider; // unused - - if (ppMessage == NULL || pError == NULL) { - assert(0); - return; - } - - // Nothing more is needed here, since - // there is no UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC error used. -} - -static umf_result_t coarse_memory_provider_get_min_page_size(void *provider, - void *ptr, - size_t *pageSize) { - coarse_memory_provider_t *coarse_provider = - (struct coarse_memory_provider_t *)provider; - - if (!coarse_provider->upstream_memory_provider) { - *pageSize = utils_get_page_size(); - return UMF_RESULT_SUCCESS; - } - - return umfMemoryProviderGetMinPageSize( - coarse_provider->upstream_memory_provider, ptr, pageSize); -} - -static umf_result_t -coarse_memory_provider_get_recommended_page_size(void *provider, size_t size, - size_t *pageSize) { - coarse_memory_provider_t *coarse_provider = - (struct coarse_memory_provider_t *)provider; - - if (!coarse_provider->upstream_memory_provider) { - *pageSize = utils_get_page_size(); - return UMF_RESULT_SUCCESS; - } - - return umfMemoryProviderGetRecommendedPageSize( - coarse_provider->upstream_memory_provider, size, pageSize); -} - -static const char *coarse_memory_provider_get_name(void *provider) { - coarse_memory_provider_t *coarse_provider = - (struct coarse_memory_provider_t *)provider; - - if (!coarse_provider->name) { - return COARSE_BASE_NAME; - } - - return coarse_provider->name; -} - -static void ravl_cb_count(void *data, void *arg) { - assert(arg); - (void)data; /* unused */ - - size_t *num_all_blocks = arg; - (*num_all_blocks)++; -} - -static void ravl_cb_count_free(void *data, void *arg) { - assert(data); - assert(arg); - - ravl_data_t *node_data = data; - assert(node_data); - ravl_free_blocks_head_t *head_node = node_data->value; - assert(head_node); - struct ravl_free_blocks_elem_t *free_block = head_node->head; - assert(free_block); - - size_t *num_all_blocks = arg; - while (free_block) { - (*num_all_blocks)++; - free_block = free_block->next; - } -} - -static umf_result_t -coarse_memory_provider_get_stats(void *provider, - coarse_memory_provider_stats_t *stats) { - 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); - - size_t num_free_blocks = 0; - ravl_foreach(coarse_provider->free_blocks, ravl_cb_count_free, - &num_free_blocks); - - 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; - - return UMF_RESULT_SUCCESS; -} - -static umf_result_t coarse_memory_provider_purge_lazy(void *provider, void *ptr, - size_t size) { - coarse_memory_provider_t *coarse_provider = - (struct coarse_memory_provider_t *)provider; - if (coarse_provider->upstream_memory_provider == NULL) { - LOG_ERR("no upstream memory provider given"); - return UMF_RESULT_ERROR_NOT_SUPPORTED; - } - - return umfMemoryProviderPurgeLazy(coarse_provider->upstream_memory_provider, - ptr, size); -} - -static umf_result_t coarse_memory_provider_purge_force(void *provider, - void *ptr, size_t size) { - coarse_memory_provider_t *coarse_provider = - (struct coarse_memory_provider_t *)provider; - if (coarse_provider->upstream_memory_provider == NULL) { - LOG_ERR("no upstream memory provider given"); - return UMF_RESULT_ERROR_NOT_SUPPORTED; - } - - return umfMemoryProviderPurgeForce( - coarse_provider->upstream_memory_provider, ptr, size); -} - -static umf_result_t coarse_memory_provider_allocation_split(void *provider, - void *ptr, - size_t totalSize, - size_t firstSize) { - umf_result_t umf_result; - - coarse_memory_provider_t *coarse_provider = - (struct coarse_memory_provider_t *)provider; - - if (utils_mutex_lock(&coarse_provider->lock) != 0) { - LOG_ERR("locking the lock failed"); - return UMF_RESULT_ERROR_UNKNOWN; - } - - assert(debug_check(coarse_provider)); - - ravl_node_t *node = coarse_ravl_find_node(coarse_provider->all_blocks, ptr); - if (node == NULL) { - LOG_ERR("memory block not found"); - umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT; - goto err_mutex_unlock; - } - - block_t *block = get_node_block(node); - - if (block->size != totalSize) { - LOG_ERR("wrong totalSize"); - umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT; - goto err_mutex_unlock; - } - - if (!block->used) { - LOG_ERR("block is not allocated"); - umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT; - goto err_mutex_unlock; - } - - block_t *new_block = coarse_ravl_add_new(coarse_provider->all_blocks, - block->data + firstSize, - block->size - firstSize, NULL); - if (new_block == NULL) { - umf_result = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; - goto err_mutex_unlock; - } - - block->size = firstSize; - new_block->used = true; - - assert(new_block->size == (totalSize - firstSize)); - - umf_result = UMF_RESULT_SUCCESS; - -err_mutex_unlock: - assert(debug_check(coarse_provider)); - utils_mutex_unlock(&coarse_provider->lock); - - return umf_result; -} - -static umf_result_t coarse_memory_provider_allocation_merge(void *provider, - void *lowPtr, - void *highPtr, - size_t totalSize) { - umf_result_t umf_result; - - coarse_memory_provider_t *coarse_provider = - (struct coarse_memory_provider_t *)provider; - - if (utils_mutex_lock(&coarse_provider->lock) != 0) { - LOG_ERR("locking the lock failed"); - return UMF_RESULT_ERROR_UNKNOWN; - } - - assert(debug_check(coarse_provider)); - - ravl_node_t *low_node = - coarse_ravl_find_node(coarse_provider->all_blocks, lowPtr); - if (low_node == NULL) { - LOG_ERR("the lowPtr memory block not found"); - umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT; - goto err_mutex_unlock; - } - - block_t *low_block = get_node_block(low_node); - if (!low_block->used) { - LOG_ERR("the lowPtr block is not allocated"); - umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT; - goto err_mutex_unlock; - } - - ravl_node_t *high_node = - coarse_ravl_find_node(coarse_provider->all_blocks, highPtr); - if (high_node == NULL) { - LOG_ERR("the highPtr memory block not found"); - umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT; - goto err_mutex_unlock; - } - - block_t *high_block = get_node_block(high_node); - if (!high_block->used) { - LOG_ERR("the highPtr block is not allocated"); - umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT; - goto err_mutex_unlock; - } - - if (get_node_next(low_node) != high_node) { - LOG_ERR("given pointers cannot be merged"); - umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT; - goto err_mutex_unlock; - } - - if (get_node_prev(high_node) != low_node) { - LOG_ERR("given pointers cannot be merged"); - umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT; - goto err_mutex_unlock; - } - - if (low_block->size + high_block->size != totalSize) { - LOG_ERR("wrong totalSize"); - umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT; - goto err_mutex_unlock; - } - - if ((uintptr_t)highPtr != ((uintptr_t)lowPtr + low_block->size)) { - LOG_ERR("given pointers cannot be merged"); - umf_result = UMF_RESULT_ERROR_INVALID_ARGUMENT; - goto err_mutex_unlock; - } - - ravl_node_t *merged_node = NULL; - - umf_result = user_block_merge(coarse_provider, low_node, high_node, true, - &merged_node); - if (umf_result != UMF_RESULT_SUCCESS) { - LOG_ERR("merging failed"); - goto err_mutex_unlock; - } - - assert(merged_node == low_node); - assert(low_block->size == totalSize); - - umf_result = UMF_RESULT_SUCCESS; - -err_mutex_unlock: - assert(debug_check(coarse_provider)); - utils_mutex_unlock(&coarse_provider->lock); - - return umf_result; -} - -umf_memory_provider_ops_t UMF_COARSE_MEMORY_PROVIDER_OPS = { - .version = UMF_VERSION_CURRENT, - .initialize = coarse_memory_provider_initialize, - .finalize = coarse_memory_provider_finalize, - .alloc = coarse_memory_provider_alloc, - .free = coarse_memory_provider_free, - .get_last_native_error = coarse_memory_provider_get_last_native_error, - .get_recommended_page_size = - coarse_memory_provider_get_recommended_page_size, - .get_min_page_size = coarse_memory_provider_get_min_page_size, - .get_name = coarse_memory_provider_get_name, - .ext.purge_lazy = coarse_memory_provider_purge_lazy, - .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) { - return &UMF_COARSE_MEMORY_PROVIDER_OPS; -} - -coarse_memory_provider_stats_t -umfCoarseMemoryProviderGetStats(umf_memory_provider_handle_t provider) { - coarse_memory_provider_stats_t stats = {0}; - - if (provider == NULL) { - return stats; - } - - void *priv = umfMemoryProviderGetPriv(provider); - - coarse_memory_provider_t *coarse_provider = - (struct coarse_memory_provider_t *)priv; - - if (utils_mutex_lock(&coarse_provider->lock) != 0) { - LOG_ERR("locking the lock failed"); - return stats; - } - - coarse_memory_provider_get_stats(priv, &stats); - - utils_mutex_unlock(&coarse_provider->lock); - - return stats; -} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b56478970..593268a52 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -199,11 +199,6 @@ if(LINUX) LIBS ${UMF_UTILS_FOR_TEST}) endif() -add_umf_test( - NAME provider_coarse - SRCS provider_coarse.cpp ${BA_SOURCES_FOR_TEST} - LIBS ${UMF_UTILS_FOR_TEST}) - add_umf_test( NAME coarse_lib SRCS coarse_lib.cpp ${BA_SOURCES_FOR_TEST} @@ -218,10 +213,12 @@ if(UMF_BUILD_LIBUMF_POOL_DISJOINT) NAME c_api_disjoint_pool SRCS c_api/disjoint_pool.c LIBS disjoint_pool) - add_umf_test( - NAME disjointCoarseMallocPool - SRCS disjointCoarseMallocPool.cpp - LIBS disjoint_pool) + if(LINUX AND (NOT UMF_DISABLE_HWLOC)) + add_umf_test( + NAME disjointCoarseMallocPool + SRCS disjointCoarseMallocPool.cpp + LIBS disjoint_pool) + endif() endif() if(UMF_BUILD_LIBUMF_POOL_DISJOINT diff --git a/test/disjointCoarseMallocPool.cpp b/test/disjointCoarseMallocPool.cpp index 32e1d24f3..45502b192 100644 --- a/test/disjointCoarseMallocPool.cpp +++ b/test/disjointCoarseMallocPool.cpp @@ -7,39 +7,40 @@ #include -#include "provider.hpp" - #include -#include +#include + +#include "coarse.h" +#include "provider.hpp" using umf_test::KB; using umf_test::MB; using umf_test::test; -#define GetStats umfCoarseMemoryProviderGetStats +#define FILE_PATH ((char *)"tmp_file") umf_memory_provider_ops_t UMF_MALLOC_MEMORY_PROVIDER_OPS = umf::providerMakeCOps(); -struct CoarseWithMemoryStrategyTest +struct FileWithMemoryStrategyTest : umf_test::test, - ::testing::WithParamInterface { + ::testing::WithParamInterface { void SetUp() override { test::SetUp(); allocation_strategy = this->GetParam(); } - coarse_memory_provider_strategy_t allocation_strategy; + coarse_strategy_t allocation_strategy; }; INSTANTIATE_TEST_SUITE_P( - CoarseWithMemoryStrategyTest, CoarseWithMemoryStrategyTest, + FileWithMemoryStrategyTest, FileWithMemoryStrategyTest, ::testing::Values(UMF_COARSE_MEMORY_STRATEGY_FASTEST, UMF_COARSE_MEMORY_STRATEGY_FASTEST_BUT_ONE, UMF_COARSE_MEMORY_STRATEGY_CHECK_ALL_SIZE)); -TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_basic) { - umf_memory_provider_handle_t malloc_memory_provider; +TEST_P(FileWithMemoryStrategyTest, disjointFileMallocPool_simple1) { + umf_memory_provider_handle_t malloc_memory_provider = nullptr; umf_result_t umf_result; umf_result = umfMemoryProviderCreate(&UMF_MALLOC_MEMORY_PROVIDER_OPS, NULL, @@ -47,217 +48,19 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_basic) { ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(malloc_memory_provider, nullptr); - const size_t init_buffer_size = 20 * MB; - - 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.destroy_upstream_memory_provider = true; - coarse_memory_provider_params.immediate_init_from_upstream = true; - coarse_memory_provider_params.init_buffer = nullptr; - 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_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_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; - umf_result = umfPoolGetMemoryProvider(pool, &prov); + umf_file_memory_provider_params_handle_t file_params = nullptr; + umf_result = umfFileMemoryProviderParamsCreate(&file_params, FILE_PATH); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_NE(prov, nullptr); - - // alloc 2x 2MB - void *p1 = umfPoolMalloc(pool, 2 * MB); - ASSERT_NE(p1, nullptr); - ASSERT_EQ(GetStats(prov).used_size, 2 * MB); - ASSERT_EQ(GetStats(prov).alloc_size, init_buffer_size); - ASSERT_EQ(GetStats(prov).num_all_blocks, 2); - - void *p2 = umfPoolMalloc(pool, 2 * MB); - ASSERT_NE(p2, nullptr); - ASSERT_EQ(GetStats(prov).used_size, 4 * MB); - ASSERT_EQ(GetStats(prov).alloc_size, init_buffer_size); - ASSERT_EQ(GetStats(prov).num_all_blocks, 3); - ASSERT_NE(p1, p2); - - // swap pointers to get p1 < p2 - if (p1 > p2) { - std::swap(p1, p2); - } - - // free + alloc first block - // the block should be reused - // currently there is no purging, so the alloc size shouldn't change - // there should be no block merging between used and not-used blocks - umf_result = umfPoolFree(pool, p1); - ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_EQ(GetStats(prov).used_size, 2 * MB); - ASSERT_EQ(GetStats(prov).alloc_size, init_buffer_size); - ASSERT_EQ(GetStats(prov).num_all_blocks, 3); - - p1 = umfPoolMalloc(pool, 2 * MB); - ASSERT_EQ(GetStats(prov).used_size, 4 * MB); - ASSERT_EQ(GetStats(prov).alloc_size, init_buffer_size); - ASSERT_EQ(GetStats(prov).num_all_blocks, 3); - - // free all allocs - // overall alloc size shouldn't change - // block p2 should merge with the prev free block p1 - // and the remaining init block - umf_result = umfPoolFree(pool, p1); - ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_EQ(GetStats(prov).num_all_blocks, 3); - umf_result = umfPoolFree(pool, p2); - ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_EQ(GetStats(prov).used_size, 0 * MB); - ASSERT_EQ(GetStats(prov).alloc_size, init_buffer_size); - ASSERT_EQ(GetStats(prov).num_all_blocks, 1); - - // test allocations with alignment - // TODO: what about holes? - p1 = umfPoolAlignedMalloc(pool, 1 * MB - 4, 128); - ASSERT_NE(p1, nullptr); - ASSERT_EQ((uintptr_t)p1 & 127, 0); - p2 = umfPoolAlignedMalloc(pool, 1 * MB - 4, 128); - ASSERT_NE(p2, nullptr); - ASSERT_EQ((uintptr_t)p1 & 127, 0); - umf_result = umfPoolFree(pool, p1); - ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - umf_result = umfPoolFree(pool, p2); - ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - - // alloc whole buffer - // after this, there should be one single block - p1 = umfPoolMalloc(pool, init_buffer_size); - ASSERT_EQ(GetStats(prov).used_size, init_buffer_size); - ASSERT_EQ(GetStats(prov).alloc_size, init_buffer_size); - ASSERT_EQ(GetStats(prov).num_all_blocks, 1); - - // free all memory - // alloc 2 MB block - the init block should be split - umf_result = umfPoolFree(pool, p1); - p1 = umfPoolMalloc(pool, 2 * MB); - ASSERT_EQ(GetStats(prov).used_size, 2 * MB); - ASSERT_EQ(GetStats(prov).alloc_size, init_buffer_size); - ASSERT_EQ(GetStats(prov).num_all_blocks, 2); - - // alloc additional 2 MB - // the non-used block should be used - p2 = umfPoolMalloc(pool, 2 * MB); - ASSERT_EQ(GetStats(prov).used_size, 4 * MB); - ASSERT_EQ(GetStats(prov).alloc_size, init_buffer_size); - ASSERT_EQ(GetStats(prov).num_all_blocks, 3); - ASSERT_NE(p1, p2); - - // make sure that p1 < p2 - if (p1 > p2) { - std::swap(p1, p2); - } - - // free blocks in order: p2, p1 - // block p1 should merge with the next block p2 - // swap pointers to get p1 < p2 - umfPoolFree(pool, p2); - umfPoolFree(pool, p1); - ASSERT_EQ(GetStats(prov).used_size, 0 * MB); - ASSERT_EQ(GetStats(prov).alloc_size, init_buffer_size); - ASSERT_EQ(GetStats(prov).num_all_blocks, 1); - - // alloc 10x 2 MB - this should occupy all allocated memory - constexpr int allocs_size = 10; - void *allocs[allocs_size] = {0}; - for (int i = 0; i < allocs_size; i++) { - ASSERT_EQ(GetStats(prov).used_size, i * 2 * MB); - allocs[i] = umfPoolMalloc(pool, 2 * MB); - ASSERT_NE(allocs[i], nullptr); - } - ASSERT_EQ(GetStats(prov).used_size, 20 * MB); - ASSERT_EQ(GetStats(prov).alloc_size, init_buffer_size); - // there should be no block with the free memory - ASSERT_EQ(GetStats(prov).num_all_blocks, allocs_size); - - // free all memory - for (int i = 0; i < allocs_size; i++) { - umf_result = umfPoolFree(pool, allocs[i]); - ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - } - - ASSERT_EQ(GetStats(prov).num_all_blocks, 1); - ASSERT_EQ(GetStats(prov).used_size, 0 * MB); - ASSERT_EQ(GetStats(prov).alloc_size, init_buffer_size); - - umfPoolDestroy(pool); - // Both coarse_memory_provider and malloc_memory_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_result_t umf_result; + ASSERT_NE(file_params, nullptr); - umf_result = umfMemoryProviderCreate(&UMF_MALLOC_MEMORY_PROVIDER_OPS, NULL, - &malloc_memory_provider); + umf_memory_provider_handle_t file_memory_provider; + umf_result = umfMemoryProviderCreate(umfFileMemoryProviderOps(), + file_params, &file_memory_provider); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_NE(malloc_memory_provider, nullptr); - - const size_t init_buffer_size = 20 * MB; + ASSERT_NE(file_memory_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.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); + umf_result = umfFileMemoryProviderParamsDestroy(file_params); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_NE(coarse_memory_provider, nullptr); umf_disjoint_pool_params_handle_t disjoint_pool_params = NULL; umf_result = umfDisjointPoolParamsCreate(&disjoint_pool_params); @@ -279,7 +82,7 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_simple1) { umf_memory_pool_handle_t pool; umf_result = - umfPoolCreate(umfDisjointPoolOps(), coarse_memory_provider, + umfPoolCreate(umfDisjointPoolOps(), file_memory_provider, disjoint_pool_params, UMF_POOL_CREATE_FLAG_NONE, &pool); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(pool, nullptr); @@ -295,8 +98,6 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_simple1) { size_t s1 = 74659 * KB; size_t s2 = 8206 * KB; - size_t max_alloc_size = 0; - const int nreps = 2; const int nptrs = 6; @@ -308,10 +109,6 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_simple1) { ASSERT_NE(t[i], nullptr); } - if (max_alloc_size == 0) { - max_alloc_size = GetStats(prov).alloc_size; - } - for (int i = 0; i < nptrs; i++) { umf_result = umfPoolFree(pool, t[i]); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); @@ -326,9 +123,6 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_simple1) { ASSERT_NE(t[i], nullptr); } - // all s2 should fit into single block leaved after freeing s1 - ASSERT_LE(GetStats(prov).alloc_size, max_alloc_size); - for (int i = 0; i < nptrs; i++) { umf_result = umfPoolFree(pool, t[i]); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); @@ -336,12 +130,12 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_simple1) { } umfPoolDestroy(pool); - umfMemoryProviderDestroy(coarse_memory_provider); + umfMemoryProviderDestroy(file_memory_provider); umfMemoryProviderDestroy(malloc_memory_provider); } -TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_simple2) { - umf_memory_provider_handle_t malloc_memory_provider; +TEST_P(FileWithMemoryStrategyTest, disjointFileMallocPool_simple2) { + umf_memory_provider_handle_t malloc_memory_provider = nullptr; umf_result_t umf_result; umf_result = umfMemoryProviderCreate(&UMF_MALLOC_MEMORY_PROVIDER_OPS, NULL, @@ -349,25 +143,19 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_simple2) { ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(malloc_memory_provider, nullptr); - const size_t init_buffer_size = 20 * MB; + umf_file_memory_provider_params_handle_t file_params = nullptr; + umf_result = umfFileMemoryProviderParamsCreate(&file_params, FILE_PATH); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(file_params, 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.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 file_memory_provider; + umf_result = umfMemoryProviderCreate(umfFileMemoryProviderOps(), + file_params, &file_memory_provider); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(file_memory_provider, nullptr); - umf_memory_provider_handle_t coarse_memory_provider; - umf_result = umfMemoryProviderCreate(umfCoarseMemoryProviderOps(), - &coarse_memory_provider_params, - &coarse_memory_provider); + umf_result = umfFileMemoryProviderParamsDestroy(file_params); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_NE(coarse_memory_provider, nullptr); umf_disjoint_pool_params_handle_t disjoint_pool_params = NULL; umf_result = umfDisjointPoolParamsCreate(&disjoint_pool_params); @@ -389,7 +177,7 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_simple2) { umf_memory_pool_handle_t pool; umf_result = - umfPoolCreate(umfDisjointPoolOps(), coarse_memory_provider, + umfPoolCreate(umfDisjointPoolOps(), file_memory_provider, disjoint_pool_params, UMF_POOL_CREATE_FLAG_NONE, &pool); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(pool, nullptr); @@ -415,7 +203,7 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_simple2) { } umfPoolDestroy(pool); - umfMemoryProviderDestroy(coarse_memory_provider); + umfMemoryProviderDestroy(file_memory_provider); umfMemoryProviderDestroy(malloc_memory_provider); } @@ -431,7 +219,7 @@ struct alloc_ptr_size { } }; -TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMMapPool_random) { +TEST_P(FileWithMemoryStrategyTest, disjointFileMMapPool_random) { umf_result_t umf_result; const size_t init_buffer_size = 200 * MB; @@ -443,22 +231,19 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMMapPool_random) { const unsigned char alloc_check_val = 11; - 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 = NULL; - coarse_memory_provider_params.immediate_init_from_upstream = false; - coarse_memory_provider_params.init_buffer = buf; - coarse_memory_provider_params.init_buffer_size = init_buffer_size; + umf_file_memory_provider_params_handle_t file_params = nullptr; + umf_result = umfFileMemoryProviderParamsCreate(&file_params, FILE_PATH); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(file_params, nullptr); + + umf_memory_provider_handle_t file_memory_provider; + umf_result = umfMemoryProviderCreate(umfFileMemoryProviderOps(), + file_params, &file_memory_provider); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(file_memory_provider, nullptr); - umf_memory_provider_handle_t coarse_memory_provider; - umf_result = umfMemoryProviderCreate(umfCoarseMemoryProviderOps(), - &coarse_memory_provider_params, - &coarse_memory_provider); + umf_result = umfFileMemoryProviderParamsDestroy(file_params); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_NE(coarse_memory_provider, nullptr); umf_disjoint_pool_params_handle_t disjoint_pool_params = NULL; umf_result = umfDisjointPoolParamsCreate(&disjoint_pool_params); @@ -480,7 +265,7 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMMapPool_random) { umf_memory_pool_handle_t pool; umf_result = - umfPoolCreate(umfDisjointPoolOps(), coarse_memory_provider, + umfPoolCreate(umfDisjointPoolOps(), file_memory_provider, disjoint_pool_params, UMF_POOL_CREATE_FLAG_NONE, &pool); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(pool, nullptr); @@ -520,9 +305,7 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMMapPool_random) { // alloc for (size_t j = 0; j < count; j++) { - void *ptr = umfPoolMalloc(pool, size); - ASSERT_NE(ptr, nullptr); - + void *ptr = umfPoolCalloc(pool, 1, size); if (ptr == nullptr) { break; } @@ -576,5 +359,5 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMMapPool_random) { } umfPoolDestroy(pool); - umfMemoryProviderDestroy(coarse_memory_provider); + umfMemoryProviderDestroy(file_memory_provider); } diff --git a/test/memoryPoolAPI.cpp b/test/memoryPoolAPI.cpp index 1c6d83f2a..95dcfabb2 100644 --- a/test/memoryPoolAPI.cpp +++ b/test/memoryPoolAPI.cpp @@ -181,16 +181,14 @@ TEST_F(test, BasicPoolByPtrTest) { INSTANTIATE_TEST_SUITE_P( mallocPoolTest, umfPoolTest, ::testing::Values(poolCreateExtParams{&MALLOC_POOL_OPS, nullptr, - &UMF_NULL_PROVIDER_OPS, nullptr, - nullptr}, + &UMF_NULL_PROVIDER_OPS, nullptr}, poolCreateExtParams{umfProxyPoolOps(), nullptr, - &BA_GLOBAL_PROVIDER_OPS, nullptr, - nullptr})); + &BA_GLOBAL_PROVIDER_OPS, nullptr})); INSTANTIATE_TEST_SUITE_P(mallocMultiPoolTest, umfMultiPoolTest, ::testing::Values(poolCreateExtParams{ umfProxyPoolOps(), nullptr, - &BA_GLOBAL_PROVIDER_OPS, nullptr, nullptr})); + &BA_GLOBAL_PROVIDER_OPS, nullptr})); INSTANTIATE_TEST_SUITE_P(umfPoolWithCreateFlagsTest, umfPoolWithCreateFlagsTest, ::testing::Values(0, diff --git a/test/poolFixtures.hpp b/test/poolFixtures.hpp index e5ec85012..6f54fe114 100644 --- a/test/poolFixtures.hpp +++ b/test/poolFixtures.hpp @@ -7,7 +7,6 @@ #include "pool.hpp" #include "provider.hpp" -#include "umf/providers/provider_coarse.h" #include "umf/providers/provider_devdax_memory.h" #include "utils/utils_sanitizers.h" @@ -20,13 +19,11 @@ #include "../malloc_compliance_tests.hpp" -using poolCreateExtParams = - std::tuple; +using poolCreateExtParams = std::tuple; umf::pool_unique_handle_t poolCreateExtUnique(poolCreateExtParams params) { - auto [pool_ops, pool_params, provider_ops, provider_params, coarse_params] = - params; + auto [pool_ops, pool_params, provider_ops, provider_params] = params; umf_memory_provider_handle_t upstream_provider = nullptr; umf_memory_provider_handle_t provider = nullptr; @@ -40,22 +37,6 @@ umf::pool_unique_handle_t poolCreateExtUnique(poolCreateExtParams params) { provider = upstream_provider; - if (coarse_params) { - coarse_memory_provider_params_t *coarse_memory_provider_params = - (coarse_memory_provider_params_t *)coarse_params; - coarse_memory_provider_params->upstream_memory_provider = - upstream_provider; - coarse_memory_provider_params->destroy_upstream_memory_provider = true; - - umf_memory_provider_handle_t coarse_provider = nullptr; - ret = umfMemoryProviderCreate(umfCoarseMemoryProviderOps(), - coarse_params, &coarse_provider); - EXPECT_EQ(ret, UMF_RESULT_SUCCESS); - EXPECT_NE(coarse_provider, nullptr); - - provider = coarse_provider; - } - ret = umfPoolCreate(pool_ops, provider, pool_params, UMF_POOL_CREATE_FLAG_OWN_PROVIDER, &hPool); EXPECT_EQ(ret, UMF_RESULT_SUCCESS); diff --git a/test/pools/disjoint_pool.cpp b/test/pools/disjoint_pool.cpp index 471e53dc2..c254400db 100644 --- a/test/pools/disjoint_pool.cpp +++ b/test/pools/disjoint_pool.cpp @@ -248,19 +248,18 @@ INSTANTIATE_TEST_SUITE_P(disjointPoolTests, umfPoolTest, ::testing::Values(poolCreateExtParams{ umfDisjointPoolOps(), (void *)defaultPoolConfig.get(), - &BA_GLOBAL_PROVIDER_OPS, nullptr, nullptr})); + &BA_GLOBAL_PROVIDER_OPS, nullptr})); -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( + disjointPoolTests, umfMemTest, + ::testing::Values(std::make_tuple( + poolCreateExtParams{ + umfDisjointPoolOps(), (void *)defaultPoolConfig.get(), + &MOCK_OUT_OF_MEM_PROVIDER_OPS, (void *)&DEFAULT_DISJOINT_CAPACITY}, + static_cast(DEFAULT_DISJOINT_CAPACITY) / 2))); INSTANTIATE_TEST_SUITE_P(disjointMultiPoolTests, umfMultiPoolTest, ::testing::Values(poolCreateExtParams{ umfDisjointPoolOps(), (void *)defaultPoolConfig.get(), - &BA_GLOBAL_PROVIDER_OPS, nullptr, nullptr})); + &BA_GLOBAL_PROVIDER_OPS, nullptr})); diff --git a/test/pools/jemalloc_coarse_devdax.cpp b/test/pools/jemalloc_coarse_devdax.cpp index 350e053ab..72906e625 100644 --- a/test/pools/jemalloc_coarse_devdax.cpp +++ b/test/pools/jemalloc_coarse_devdax.cpp @@ -31,15 +31,13 @@ devdax_params_unique_handle_t create_devdax_params() { &umfDevDaxMemoryProviderParamsDestroy); } -auto coarseParams = umfCoarseMemoryProviderParamsDefault(); auto devdaxParams = create_devdax_params(); static std::vector poolParamsList = - devdaxParams.get() - ? std::vector{poolCreateExtParams{ - umfJemallocPoolOps(), nullptr, umfDevDaxMemoryProviderOps(), - devdaxParams.get(), &coarseParams}} - : std::vector{}; + devdaxParams.get() ? std::vector{poolCreateExtParams{ + umfJemallocPoolOps(), nullptr, + umfDevDaxMemoryProviderOps(), devdaxParams.get()}} + : std::vector{}; INSTANTIATE_TEST_SUITE_P(jemallocCoarseDevDaxTest, umfPoolTest, ::testing::ValuesIn(poolParamsList)); diff --git a/test/pools/jemalloc_coarse_file.cpp b/test/pools/jemalloc_coarse_file.cpp index 74ad36d56..68a602df6 100644 --- a/test/pools/jemalloc_coarse_file.cpp +++ b/test/pools/jemalloc_coarse_file.cpp @@ -23,11 +23,9 @@ file_params_unique_handle_t get_file_params_default(char *path) { &umfFileMemoryProviderParamsDestroy); } -auto coarseParams = umfCoarseMemoryProviderParamsDefault(); file_params_unique_handle_t fileParams = get_file_params_default(FILE_PATH); INSTANTIATE_TEST_SUITE_P(jemallocCoarseFileTest, umfPoolTest, ::testing::Values(poolCreateExtParams{ umfJemallocPoolOps(), nullptr, - umfFileMemoryProviderOps(), fileParams.get(), - &coarseParams})); + umfFileMemoryProviderOps(), fileParams.get()})); diff --git a/test/pools/jemalloc_pool.cpp b/test/pools/jemalloc_pool.cpp index 4dddbcd32..bcc9623c7 100644 --- a/test/pools/jemalloc_pool.cpp +++ b/test/pools/jemalloc_pool.cpp @@ -29,8 +29,7 @@ auto defaultParams = createOsMemoryProviderParams(); INSTANTIATE_TEST_SUITE_P(jemallocPoolTest, umfPoolTest, ::testing::Values(poolCreateExtParams{ umfJemallocPoolOps(), nullptr, - umfOsMemoryProviderOps(), defaultParams.get(), - nullptr})); + umfOsMemoryProviderOps(), defaultParams.get()})); // this test makes sure that jemalloc does not use // memory provider to allocate metadata (and hence @@ -48,9 +47,8 @@ TEST_F(test, metadataNotAllocatedUsingProvider) { res = umfOsMemoryProviderParamsSetProtection(params, UMF_PROTECTION_NONE); ASSERT_EQ(res, UMF_RESULT_SUCCESS); - auto pool = - poolCreateExtUnique({umfJemallocPoolOps(), nullptr, - umfOsMemoryProviderOps(), params, nullptr}); + auto pool = poolCreateExtUnique( + {umfJemallocPoolOps(), nullptr, umfOsMemoryProviderOps(), params}); res = umfOsMemoryProviderParamsDestroy(params); ASSERT_EQ(res, UMF_RESULT_SUCCESS); diff --git a/test/pools/pool_base_alloc.cpp b/test/pools/pool_base_alloc.cpp index 7c9a3701a..ec07a7c2f 100644 --- a/test/pools/pool_base_alloc.cpp +++ b/test/pools/pool_base_alloc.cpp @@ -48,4 +48,4 @@ umf_memory_pool_ops_t BA_POOL_OPS = umf::poolMakeCOps(); INSTANTIATE_TEST_SUITE_P(baPool, umfPoolTest, ::testing::Values(poolCreateExtParams{ &BA_POOL_OPS, nullptr, - &umf_test::BASE_PROVIDER_OPS, nullptr, nullptr})); + &umf_test::BASE_PROVIDER_OPS, nullptr})); diff --git a/test/pools/pool_coarse.hpp b/test/pools/pool_coarse.hpp index 7baa612f1..b1efb4fee 100644 --- a/test/pools/pool_coarse.hpp +++ b/test/pools/pool_coarse.hpp @@ -5,8 +5,6 @@ #ifndef UMF_TEST_POOL_COARSE_HPP #define UMF_TEST_POOL_COARSE_HPP 1 -#include "umf/providers/provider_coarse.h" - #include "pool.hpp" #include "poolFixtures.hpp" diff --git a/test/pools/scalable_coarse_devdax.cpp b/test/pools/scalable_coarse_devdax.cpp index 1bf77c61c..970f45ef9 100644 --- a/test/pools/scalable_coarse_devdax.cpp +++ b/test/pools/scalable_coarse_devdax.cpp @@ -31,15 +31,13 @@ devdax_params_unique_handle_t create_devdax_params() { &umfDevDaxMemoryProviderParamsDestroy); } -auto coarseParams = umfCoarseMemoryProviderParamsDefault(); auto devdaxParams = create_devdax_params(); static std::vector poolParamsList = - devdaxParams.get() - ? std::vector{poolCreateExtParams{ - umfScalablePoolOps(), nullptr, umfDevDaxMemoryProviderOps(), - devdaxParams.get(), &coarseParams}} - : std::vector{}; + devdaxParams.get() ? std::vector{poolCreateExtParams{ + umfScalablePoolOps(), nullptr, + umfDevDaxMemoryProviderOps(), devdaxParams.get()}} + : std::vector{}; INSTANTIATE_TEST_SUITE_P(scalableCoarseDevDaxTest, umfPoolTest, ::testing::ValuesIn(poolParamsList)); diff --git a/test/pools/scalable_coarse_file.cpp b/test/pools/scalable_coarse_file.cpp index b45c112be..30134f5eb 100644 --- a/test/pools/scalable_coarse_file.cpp +++ b/test/pools/scalable_coarse_file.cpp @@ -23,11 +23,9 @@ file_params_unique_handle_t get_file_params_default(char *path) { &umfFileMemoryProviderParamsDestroy); } -auto coarseParams = umfCoarseMemoryProviderParamsDefault(); file_params_unique_handle_t fileParams = get_file_params_default(FILE_PATH); INSTANTIATE_TEST_SUITE_P(scalableCoarseFileTest, umfPoolTest, ::testing::Values(poolCreateExtParams{ umfScalablePoolOps(), nullptr, - umfFileMemoryProviderOps(), fileParams.get(), - &coarseParams})); + umfFileMemoryProviderOps(), fileParams.get()})); diff --git a/test/pools/scalable_pool.cpp b/test/pools/scalable_pool.cpp index 3edacd965..51cc02030 100644 --- a/test/pools/scalable_pool.cpp +++ b/test/pools/scalable_pool.cpp @@ -27,8 +27,7 @@ auto defaultParams = createOsMemoryProviderParams(); INSTANTIATE_TEST_SUITE_P(scalablePoolTest, umfPoolTest, ::testing::Values(poolCreateExtParams{ umfScalablePoolOps(), nullptr, - umfOsMemoryProviderOps(), defaultParams.get(), - nullptr})); + umfOsMemoryProviderOps(), defaultParams.get()})); using scalablePoolParams = std::tuple; struct umfScalablePoolParamsTest diff --git a/test/provider_coarse.cpp b/test/provider_coarse.cpp deleted file mode 100644 index c2de4c06a..000000000 --- a/test/provider_coarse.cpp +++ /dev/null @@ -1,668 +0,0 @@ -/* - * Copyright (C) 2023-2024 Intel Corporation - * - * Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -*/ - -#include - -#include "provider.hpp" - -#include - -using umf_test::KB; -using umf_test::MB; -using umf_test::test; - -#define GetStats umfCoarseMemoryProviderGetStats - -#define UPSTREAM_NAME "umf_ba_global" -#define BASE_NAME "coarse" -#define COARSE_NAME BASE_NAME " (" UPSTREAM_NAME ")" - -umf_memory_provider_ops_t UMF_MALLOC_MEMORY_PROVIDER_OPS = - umf::providerMakeCOps(); - -struct CoarseWithMemoryStrategyTest - : umf_test::test, - ::testing::WithParamInterface { - void SetUp() override { - test::SetUp(); - allocation_strategy = this->GetParam(); - } - - coarse_memory_provider_strategy_t allocation_strategy; -}; - -INSTANTIATE_TEST_SUITE_P( - CoarseWithMemoryStrategyTest, CoarseWithMemoryStrategyTest, - ::testing::Values(UMF_COARSE_MEMORY_STRATEGY_FASTEST, - UMF_COARSE_MEMORY_STRATEGY_FASTEST_BUT_ONE, - UMF_COARSE_MEMORY_STRATEGY_CHECK_ALL_SIZE)); - -TEST_F(test, coarseProvider_name_upstream) { - umf_memory_provider_handle_t malloc_memory_provider; - umf_result_t umf_result; - - umf_result = umfMemoryProviderCreate(&UMF_MALLOC_MEMORY_PROVIDER_OPS, NULL, - &malloc_memory_provider); - ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_NE(malloc_memory_provider, nullptr); - - const size_t init_buffer_size = 20 * MB; - - 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 = - malloc_memory_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; - 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); - - size_t minPageSize = 0; - umf_result = umfMemoryProviderGetMinPageSize(coarse_memory_provider, - nullptr, &minPageSize); - ASSERT_EQ(umf_result, UMF_RESULT_ERROR_UNKNOWN); - ASSERT_EQ(minPageSize, 0); - - size_t pageSize = 0; - umf_result = umfMemoryProviderGetRecommendedPageSize( - coarse_memory_provider, minPageSize, &pageSize); - ASSERT_EQ(umf_result, UMF_RESULT_ERROR_UNKNOWN); - ASSERT_EQ(pageSize, minPageSize); - - ASSERT_EQ( - strcmp(umfMemoryProviderGetName(coarse_memory_provider), COARSE_NAME), - 0); - - umfMemoryProviderDestroy(coarse_memory_provider); - // malloc_memory_provider has already been destroyed - // by umfMemoryProviderDestroy(coarse_memory_provider), because: - // coarse_memory_provider_params.destroy_upstream_memory_provider = true; -} - -TEST_F(test, coarseProvider_name_no_upstream) { - umf_result_t umf_result; - - const size_t init_buffer_size = 20 * MB; - - // preallocate some memory and initialize the vector with zeros - std::vector buffer(init_buffer_size, 0); - void *buf = (void *)buffer.data(); - ASSERT_NE(buf, 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.upstream_memory_provider = nullptr; - coarse_memory_provider_params.immediate_init_from_upstream = false; - coarse_memory_provider_params.init_buffer = buf; - 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); - - size_t minPageSize = 0; - umf_result = umfMemoryProviderGetMinPageSize(coarse_memory_provider, - nullptr, &minPageSize); - ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_GT(minPageSize, 0); - - size_t pageSize = 0; - umf_result = umfMemoryProviderGetRecommendedPageSize( - coarse_memory_provider, minPageSize, &pageSize); - ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_GE(pageSize, minPageSize); - - ASSERT_EQ( - strcmp(umfMemoryProviderGetName(coarse_memory_provider), BASE_NAME), 0); - - umfMemoryProviderDestroy(coarse_memory_provider); -} - -// negative tests - -TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_null_stats) { - ASSERT_EQ(GetStats(nullptr).alloc_size, 0); - ASSERT_EQ(GetStats(nullptr).used_size, 0); - ASSERT_EQ(GetStats(nullptr).num_upstream_blocks, 0); - ASSERT_EQ(GetStats(nullptr).num_all_blocks, 0); - ASSERT_EQ(GetStats(nullptr).num_free_blocks, 0); -} - -// wrong NULL parameters -TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_NULL_params) { - umf_result_t umf_result; - - umf_memory_provider_handle_t coarse_memory_provider = nullptr; - umf_result = umfMemoryProviderCreate(umfCoarseMemoryProviderOps(), nullptr, - &coarse_memory_provider); - ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); - ASSERT_EQ(coarse_memory_provider, nullptr); -} - -// wrong parameters: given no upstream_memory_provider -// nor init_buffer while exactly one of them must be set -TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_wrong_params_0) { - umf_result_t umf_result; - - 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 = nullptr; - coarse_memory_provider_params.immediate_init_from_upstream = false; - coarse_memory_provider_params.init_buffer = nullptr; - coarse_memory_provider_params.init_buffer_size = 0; - - umf_memory_provider_handle_t coarse_memory_provider = nullptr; - umf_result = umfMemoryProviderCreate(umfCoarseMemoryProviderOps(), - &coarse_memory_provider_params, - &coarse_memory_provider); - ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); - ASSERT_EQ(coarse_memory_provider, nullptr); -} - -// 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_result_t umf_result; - - umf_result = umfMemoryProviderCreate(&UMF_MALLOC_MEMORY_PROVIDER_OPS, NULL, - &malloc_memory_provider); - ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_NE(malloc_memory_provider, nullptr); - - const size_t init_buffer_size = 20 * MB; - - // preallocate some memory and initialize the vector with zeros - std::vector buffer(init_buffer_size, 0); - void *buf = (void *)buffer.data(); - ASSERT_NE(buf, 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.immediate_init_from_upstream = true; - coarse_memory_provider_params.init_buffer = buf; - coarse_memory_provider_params.init_buffer_size = init_buffer_size; - - umf_memory_provider_handle_t coarse_memory_provider = nullptr; - umf_result = umfMemoryProviderCreate(umfCoarseMemoryProviderOps(), - &coarse_memory_provider_params, - &coarse_memory_provider); - ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); - ASSERT_EQ(coarse_memory_provider, nullptr); - - umfMemoryProviderDestroy(malloc_memory_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_result_t umf_result; - - umf_result = umfMemoryProviderCreate(&UMF_MALLOC_MEMORY_PROVIDER_OPS, NULL, - &malloc_memory_provider); - ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_NE(malloc_memory_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.immediate_init_from_upstream = true; - coarse_memory_provider_params.init_buffer = nullptr; - coarse_memory_provider_params.init_buffer_size = 0; - - umf_memory_provider_handle_t coarse_memory_provider = nullptr; - umf_result = umfMemoryProviderCreate(umfCoarseMemoryProviderOps(), - &coarse_memory_provider_params, - &coarse_memory_provider); - ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); - ASSERT_EQ(coarse_memory_provider, nullptr); - - umfMemoryProviderDestroy(malloc_memory_provider); -} - -// wrong parameters: init_buffer_size must not equal 0 when init_buffer is not NULL -TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_wrong_params_3) { - umf_result_t umf_result; - - const size_t init_buffer_size = 20 * MB; - - // preallocate some memory and initialize the vector with zeros - std::vector buffer(init_buffer_size, 0); - void *buf = (void *)buffer.data(); - ASSERT_NE(buf, 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 = nullptr; - coarse_memory_provider_params.immediate_init_from_upstream = false; - coarse_memory_provider_params.init_buffer = buf; - coarse_memory_provider_params.init_buffer_size = 0; - - umf_memory_provider_handle_t coarse_memory_provider = nullptr; - umf_result = umfMemoryProviderCreate(umfCoarseMemoryProviderOps(), - &coarse_memory_provider_params, - &coarse_memory_provider); - ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); - ASSERT_EQ(coarse_memory_provider, nullptr); -} - -// 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_result_t umf_result; - - umf_result = umfMemoryProviderCreate(&UMF_MALLOC_MEMORY_PROVIDER_OPS, NULL, - &malloc_memory_provider); - ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_NE(malloc_memory_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.immediate_init_from_upstream = false; - coarse_memory_provider_params.init_buffer = NULL; - coarse_memory_provider_params.init_buffer_size = 20 * MB; - - umf_memory_provider_handle_t coarse_memory_provider = nullptr; - umf_result = umfMemoryProviderCreate(umfCoarseMemoryProviderOps(), - &coarse_memory_provider_params, - &coarse_memory_provider); - ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); - ASSERT_EQ(coarse_memory_provider, nullptr); - - umfMemoryProviderDestroy(malloc_memory_provider); -} - -// wrong parameters: destroy_upstream_memory_provider is true, but an upstream provider is not provided -TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_wrong_params_5) { - umf_result_t umf_result; - - const size_t init_buffer_size = 20 * MB; - - // preallocate some memory and initialize the vector with zeros - std::vector buffer(init_buffer_size, 0); - void *buf = (void *)buffer.data(); - ASSERT_NE(buf, 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 = nullptr; - coarse_memory_provider_params.destroy_upstream_memory_provider = true; - coarse_memory_provider_params.immediate_init_from_upstream = false; - coarse_memory_provider_params.init_buffer = buf; - coarse_memory_provider_params.init_buffer_size = init_buffer_size; - - umf_memory_provider_handle_t coarse_memory_provider = nullptr; - umf_result = umfMemoryProviderCreate(umfCoarseMemoryProviderOps(), - &coarse_memory_provider_params, - &coarse_memory_provider); - ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); - ASSERT_EQ(coarse_memory_provider, nullptr); -} - -TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_split_merge) { - umf_memory_provider_handle_t malloc_memory_provider; - umf_result_t umf_result; - - umf_result = umfMemoryProviderCreate(&UMF_MALLOC_MEMORY_PROVIDER_OPS, NULL, - &malloc_memory_provider); - ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_NE(malloc_memory_provider, nullptr); - - const size_t init_buffer_size = 20 * MB; - - 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 = - malloc_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 *ptr = 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 umfMemoryProviderAllocationSplit */ - umf_result = umfMemoryProviderAlloc(cp, 2 * MB, 0, (void **)&ptr); - ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_NE(ptr, nullptr); - ASSERT_EQ(GetStats(cp).used_size, 2 * MB); - ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size); - ASSERT_EQ(GetStats(cp).num_all_blocks, 2); - - umf_result = umfMemoryProviderAllocationSplit(cp, ptr, 2 * MB, 1 * MB); - ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_EQ(GetStats(cp).used_size, 2 * MB); - ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size); - ASSERT_EQ(GetStats(cp).num_all_blocks, 3); - - umf_result = umfMemoryProviderFree(cp, (ptr + 1 * MB), 1 * MB); - ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_EQ(GetStats(cp).used_size, 1 * MB); - ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size); - ASSERT_EQ(GetStats(cp).num_all_blocks, 2); - - umf_result = umfMemoryProviderFree(cp, ptr, 1 * MB); - 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); - - /* test umfMemoryProviderAllocationMerge */ - umf_result = umfMemoryProviderAlloc(cp, 2 * MB, 0, (void **)&ptr); - ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_NE(ptr, nullptr); - ASSERT_EQ(GetStats(cp).used_size, 2 * MB); - ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size); - ASSERT_EQ(GetStats(cp).num_all_blocks, 2); - - umf_result = umfMemoryProviderAllocationSplit(cp, ptr, 2 * MB, 1 * MB); - ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_EQ(GetStats(cp).used_size, 2 * MB); - ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size); - ASSERT_EQ(GetStats(cp).num_all_blocks, 3); - - umf_result = - umfMemoryProviderAllocationMerge(cp, ptr, (ptr + 1 * MB), 2 * MB); - ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_EQ(GetStats(cp).used_size, 2 * MB); - ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size); - ASSERT_EQ(GetStats(cp).num_all_blocks, 2); - - umf_result = umfMemoryProviderFree(cp, ptr, 2 * MB); - 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); - - umfMemoryProviderDestroy(coarse_memory_provider); - umfMemoryProviderDestroy(malloc_memory_provider); -} - -TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_split_merge_negative) { - umf_memory_provider_handle_t malloc_memory_provider; - umf_result_t umf_result; - - umf_result = umfMemoryProviderCreate(&UMF_MALLOC_MEMORY_PROVIDER_OPS, NULL, - &malloc_memory_provider); - ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_NE(malloc_memory_provider, nullptr); - - const size_t init_buffer_size = 20 * MB; - - 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 = - malloc_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 *ptr = 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 umfMemoryProviderAllocationSplit */ - umf_result = umfMemoryProviderAlloc(cp, 6 * MB, 0, (void **)&ptr); - ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_NE(ptr, nullptr); - ASSERT_EQ(GetStats(cp).used_size, 6 * MB); - ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size); - ASSERT_EQ(GetStats(cp).num_all_blocks, 2); - - // firstSize >= totalSize - umf_result = umfMemoryProviderAllocationSplit(cp, ptr, 6 * MB, 6 * MB); - ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); - - // firstSize == 0 - umf_result = umfMemoryProviderAllocationSplit(cp, ptr, 6 * MB, 0); - ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); - - // wrong totalSize - umf_result = umfMemoryProviderAllocationSplit(cp, ptr, 5 * MB, 1 * KB); - ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); - - /* test umfMemoryProviderAllocationMerge */ - // split (6 * MB) block into (1 * MB) + (5 * MB) - umf_result = umfMemoryProviderAllocationSplit(cp, ptr, 6 * MB, 1 * MB); - ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_EQ(GetStats(cp).used_size, 6 * MB); - ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size); - ASSERT_EQ(GetStats(cp).num_all_blocks, 3); - - // split (5 * MB) block into (2 * MB) + (3 * MB) - umf_result = - umfMemoryProviderAllocationSplit(cp, (ptr + 1 * MB), 5 * MB, 2 * MB); - ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_EQ(GetStats(cp).used_size, 6 * MB); - ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size); - ASSERT_EQ(GetStats(cp).num_all_blocks, 4); - - // now we have 3 blocks: (1 * MB) + (2 * MB) + (3 * MB) - - // highPtr <= lowPtr - umf_result = - umfMemoryProviderAllocationMerge(cp, (ptr + 1 * MB), ptr, 2 * MB); - ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); - - // highPtr - lowPtr >= totalSize - umf_result = - umfMemoryProviderAllocationMerge(cp, ptr, (ptr + 1 * MB), 1 * MB); - ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); - - // low_block->size + high_block->size != totalSize - umf_result = - umfMemoryProviderAllocationMerge(cp, ptr, (ptr + 1 * MB), 5 * MB); - ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); - - // not adjacent blocks - umf_result = - umfMemoryProviderAllocationMerge(cp, ptr, (ptr + 3 * MB), 4 * MB); - ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); - - umf_result = umfMemoryProviderFree(cp, ptr, 1 * MB); - ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_EQ(GetStats(cp).used_size, 5 * MB); - ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size); - ASSERT_EQ(GetStats(cp).num_all_blocks, 4); - - umf_result = umfMemoryProviderFree(cp, (ptr + 1 * MB), 2 * MB); - ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_EQ(GetStats(cp).used_size, 3 * MB); - ASSERT_EQ(GetStats(cp).alloc_size, init_buffer_size); - ASSERT_EQ(GetStats(cp).num_all_blocks, 3); - - umf_result = umfMemoryProviderFree(cp, (ptr + 3 * MB), 3 * MB); - 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); - - umfMemoryProviderDestroy(coarse_memory_provider); - umfMemoryProviderDestroy(malloc_memory_provider); -} - -TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_purge_no_upstream) { - umf_result_t umf_result; - - const size_t init_buffer_size = 20 * MB; - - // preallocate some memory and initialize the vector with zeros - std::vector buffer(init_buffer_size, 0); - void *buf = (void *)buffer.data(); - ASSERT_NE(buf, 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 = nullptr; - coarse_memory_provider_params.immediate_init_from_upstream = false; - coarse_memory_provider_params.init_buffer = buf; - coarse_memory_provider_params.init_buffer_size = init_buffer_size; - - umf_memory_provider_handle_t coarse_memory_provider = nullptr; - umf_result = umfMemoryProviderCreate(umfCoarseMemoryProviderOps(), - &coarse_memory_provider_params, - &coarse_memory_provider); - ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_NE(coarse_memory_provider, nullptr); - - // umfMemoryProviderPurgeLazy - // provider == NULL - umf_result = umfMemoryProviderPurgeLazy(nullptr, (void *)0x01, 1); - ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); - - // ptr == NULL - umf_result = umfMemoryProviderPurgeLazy(coarse_memory_provider, nullptr, 1); - ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); - - // no upstream_memory_provider - umf_result = - umfMemoryProviderPurgeLazy(coarse_memory_provider, (void *)0x01, 1); - ASSERT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); - - // umfMemoryProviderPurgeForce - // provider == NULL - umf_result = umfMemoryProviderPurgeForce(nullptr, (void *)0x01, 1); - ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); - - // ptr == NULL - umf_result = - umfMemoryProviderPurgeForce(coarse_memory_provider, nullptr, 1); - ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); - - // no upstream_memory_provider - umf_result = - umfMemoryProviderPurgeForce(coarse_memory_provider, (void *)0x01, 1); - ASSERT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); - - umfMemoryProviderDestroy(coarse_memory_provider); -} - -TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_purge_with_upstream) { - umf_memory_provider_handle_t malloc_memory_provider; - umf_result_t umf_result; - - umf_result = umfMemoryProviderCreate(&UMF_MALLOC_MEMORY_PROVIDER_OPS, NULL, - &malloc_memory_provider); - ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - ASSERT_NE(malloc_memory_provider, nullptr); - - const size_t init_buffer_size = 20 * MB; - - 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 = - malloc_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); - - // umfMemoryProviderPurgeLazy - // provider == NULL - umf_result = umfMemoryProviderPurgeLazy(nullptr, (void *)0x01, 1); - ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); - - // ptr == NULL - 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 - umf_result = - umfMemoryProviderPurgeLazy(coarse_memory_provider, (void *)0x01, 1); - ASSERT_EQ(umf_result, UMF_RESULT_ERROR_UNKNOWN); - - // umfMemoryProviderPurgeForce - // provider == NULL - umf_result = umfMemoryProviderPurgeForce(nullptr, (void *)0x01, 1); - ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); - - // ptr == NULL - umf_result = - umfMemoryProviderPurgeForce(coarse_memory_provider, nullptr, 1); - ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); - - // malloc_memory_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); -} From 450c5a96d7cc52e29d7c411b0e09b27df0f879f8 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Thu, 5 Dec 2024 11:55:03 +0100 Subject: [PATCH 2/3] Replace all NULL with nullptr in disjointCoarseMallocPool.cpp Signed-off-by: Lukasz Dorau --- test/disjointCoarseMallocPool.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/disjointCoarseMallocPool.cpp b/test/disjointCoarseMallocPool.cpp index 45502b192..383487a87 100644 --- a/test/disjointCoarseMallocPool.cpp +++ b/test/disjointCoarseMallocPool.cpp @@ -43,8 +43,8 @@ TEST_P(FileWithMemoryStrategyTest, disjointFileMallocPool_simple1) { umf_memory_provider_handle_t malloc_memory_provider = nullptr; umf_result_t umf_result; - umf_result = umfMemoryProviderCreate(&UMF_MALLOC_MEMORY_PROVIDER_OPS, NULL, - &malloc_memory_provider); + umf_result = umfMemoryProviderCreate(&UMF_MALLOC_MEMORY_PROVIDER_OPS, + nullptr, &malloc_memory_provider); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(malloc_memory_provider, nullptr); @@ -62,7 +62,7 @@ TEST_P(FileWithMemoryStrategyTest, disjointFileMallocPool_simple1) { umf_result = umfFileMemoryProviderParamsDestroy(file_params); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - umf_disjoint_pool_params_handle_t disjoint_pool_params = NULL; + umf_disjoint_pool_params_handle_t disjoint_pool_params = nullptr; umf_result = umfDisjointPoolParamsCreate(&disjoint_pool_params); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(disjoint_pool_params, nullptr); @@ -89,7 +89,7 @@ TEST_P(FileWithMemoryStrategyTest, disjointFileMallocPool_simple1) { umf_result = umfDisjointPoolParamsDestroy(disjoint_pool_params); - umf_memory_provider_handle_t prov = NULL; + umf_memory_provider_handle_t prov = nullptr; umfPoolGetMemoryProvider(pool, &prov); ASSERT_NE(prov, nullptr); @@ -138,8 +138,8 @@ TEST_P(FileWithMemoryStrategyTest, disjointFileMallocPool_simple2) { umf_memory_provider_handle_t malloc_memory_provider = nullptr; umf_result_t umf_result; - umf_result = umfMemoryProviderCreate(&UMF_MALLOC_MEMORY_PROVIDER_OPS, NULL, - &malloc_memory_provider); + umf_result = umfMemoryProviderCreate(&UMF_MALLOC_MEMORY_PROVIDER_OPS, + nullptr, &malloc_memory_provider); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(malloc_memory_provider, nullptr); @@ -157,7 +157,7 @@ TEST_P(FileWithMemoryStrategyTest, disjointFileMallocPool_simple2) { umf_result = umfFileMemoryProviderParamsDestroy(file_params); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - umf_disjoint_pool_params_handle_t disjoint_pool_params = NULL; + umf_disjoint_pool_params_handle_t disjoint_pool_params = nullptr; umf_result = umfDisjointPoolParamsCreate(&disjoint_pool_params); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(disjoint_pool_params, nullptr); @@ -245,7 +245,7 @@ TEST_P(FileWithMemoryStrategyTest, disjointFileMMapPool_random) { umf_result = umfFileMemoryProviderParamsDestroy(file_params); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - umf_disjoint_pool_params_handle_t disjoint_pool_params = NULL; + umf_disjoint_pool_params_handle_t disjoint_pool_params = nullptr; umf_result = umfDisjointPoolParamsCreate(&disjoint_pool_params); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(disjoint_pool_params, nullptr); From 7fec989edd71dd7cc2a4dc26bccd3d12423e0daf Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Thu, 5 Dec 2024 15:55:48 +0100 Subject: [PATCH 3/3] Rename disjointCoarseMallocPool test to disjointPoolFileProv Signed-off-by: Lukasz Dorau --- test/CMakeLists.txt | 5 +++-- ...disjointCoarseMallocPool.cpp => disjointPoolFileProv.cpp} | 0 2 files changed, 3 insertions(+), 2 deletions(-) rename test/{disjointCoarseMallocPool.cpp => disjointPoolFileProv.cpp} (100%) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 593268a52..d5a07bfbb 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -214,9 +214,10 @@ if(UMF_BUILD_LIBUMF_POOL_DISJOINT) SRCS c_api/disjoint_pool.c LIBS disjoint_pool) if(LINUX AND (NOT UMF_DISABLE_HWLOC)) + # this test uses the file provider add_umf_test( - NAME disjointCoarseMallocPool - SRCS disjointCoarseMallocPool.cpp + NAME disjointPoolFileProv + SRCS disjointPoolFileProv.cpp LIBS disjoint_pool) endif() endif() diff --git a/test/disjointCoarseMallocPool.cpp b/test/disjointPoolFileProv.cpp similarity index 100% rename from test/disjointCoarseMallocPool.cpp rename to test/disjointPoolFileProv.cpp