From c6b30f52e03ba921b9128985bcf73de820397b20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Plewa?= Date: Fri, 5 Jul 2024 17:52:34 +0200 Subject: [PATCH 001/352] add examples --- examples/CMakeLists.txt | 63 ++++ examples/custom_provider/file_provider.c | 359 +++++++++++++++++++++++ examples/memspace/memspace_hmat.c | 136 +++++++++ examples/memspace/memspace_numa.c | 106 +++++++ scripts/docs_config/examples.rst | 18 ++ 5 files changed, 682 insertions(+) create mode 100644 examples/custom_provider/file_provider.c create mode 100644 examples/memspace/memspace_hmat.c create mode 100644 examples/memspace/memspace_numa.c diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index ac0b3168c..7656a9246 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -165,3 +165,66 @@ else() "IPC examples with UMF pool API are supported on Linux only - skipping" ) endif() + +if(LINUX) + set(EXAMPLE_NAME umf_example_memspace_numa) + + add_umf_executable( + NAME ${EXAMPLE_NAME} + SRCS memspace/memspace_numa.c + LIBS umf hwloc numa) + + target_include_directories( + ${EXAMPLE_NAME} PRIVATE ${UMF_CMAKE_SOURCE_DIR}/src/utils + ${UMF_CMAKE_SOURCE_DIR}/include) + + target_link_directories(${EXAMPLE_NAME} PRIVATE ${LIBHWLOC_LIBRARY_DIRS}) + + add_test( + NAME ${EXAMPLE_NAME} + COMMAND ${EXAMPLE_NAME} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + + set(EXAMPLE_NAME umf_example_memspace_hmat) + + add_umf_executable( + NAME ${EXAMPLE_NAME} + SRCS memspace/memspace_hmat.c + LIBS umf hwloc numa) + + target_include_directories( + ${EXAMPLE_NAME} PRIVATE ${UMF_CMAKE_SOURCE_DIR}/src/utils + ${UMF_CMAKE_SOURCE_DIR}/include) + + target_link_directories(${EXAMPLE_NAME} PRIVATE ${LIBHWLOC_LIBRARY_DIRS}) + + add_test( + NAME ${EXAMPLE_NAME} + COMMAND ${EXAMPLE_NAME} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + + set_tests_properties(${EXAMPLE_NAME} PROPERTIES SKIP_RETURN_CODE 125) + set(EXAMPLE_NAME umf_example_file_provider) + + add_umf_executable( + NAME ${EXAMPLE_NAME} + SRCS custom_provider/file_provider.c + LIBS umf hwloc) + + target_include_directories( + ${EXAMPLE_NAME} PRIVATE ${UMF_CMAKE_SOURCE_DIR}/src/utils + ${UMF_CMAKE_SOURCE_DIR}/include) + + target_link_directories(${EXAMPLE_NAME} PRIVATE ${LIBHWLOC_LIBRARY_DIRS}) + + add_test( + NAME ${EXAMPLE_NAME} + COMMAND ${EXAMPLE_NAME} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + +else() + message( + STATUS "Memspace examples API are supported on Linux only - skipping") + message( + STATUS "File provider example is supported on Linux only - skipping") +endif() diff --git a/examples/custom_provider/file_provider.c b/examples/custom_provider/file_provider.c new file mode 100644 index 000000000..38247acf0 --- /dev/null +++ b/examples/custom_provider/file_provider.c @@ -0,0 +1,359 @@ +/* + * + * Copyright (C) 2024 Intel Corporation + * + * Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + * + */ +#define _GNU_SOURCE 1 + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +// Define the size for address reservation +#define ADDRESS_RESERVATION ((size_t)16 * 1024 * 1024 * 1024) + +// Macro to align a value up to the nearest multiple of align +#define ALIGN_UP(value, align) (((value) + (align)-1) & ~((align)-1)) + +// Struct to represent the file provider +typedef struct file_provider_t { + void *ptr; // Pointer to the reserved memory + size_t poffset; // Offset for the next allocation + int fd; // File descriptor for the backing file + size_t foffset; // Offset within the file for the next allocation + size_t page_size; // System page size +} file_provider_t; + +// Struct to represent the file parameters +typedef struct file_params_t { + const char *filename; // Filename for the backing file +} file_params_t; + +// Function to initialize the file provider +static umf_result_t file_init(void *params, void **provider) { + file_provider_t *file_provider = NULL; + + if (params == NULL || provider == NULL) { + fprintf(stderr, "Params or provider cannot be null\n"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + file_params_t *file_params = (file_params_t *)params; + int page_size = 0; + umf_result_t ret = UMF_RESULT_SUCCESS; + + // Allocate memory for the file provider + file_provider = malloc(sizeof(*file_provider)); + if (!file_provider) { + fprintf(stderr, "Failed to allocate memory for file provider\n"); + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + // Open the file + file_provider->fd = open(file_params->filename, O_RDWR | O_CREAT, 0666); + if (file_provider->fd < 0) { + perror("Failed to open file"); + ret = UMF_RESULT_ERROR_INVALID_ARGUMENT; + goto cleanup_malloc; + } + + // Reserve address space for subsequent allocations. + // This simplifies translation between addresses and offset in the file. + file_provider->ptr = mmap(NULL, ADDRESS_RESERVATION, PROT_NONE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (file_provider->ptr == MAP_FAILED) { + perror("Failed to memory map anonymous memory"); + ret = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + goto cleanup_fd; + } + + // Get the page size + page_size = sysconf(_SC_PAGESIZE); + if (page_size < 0) { + perror("Failed to get system page size"); + ret = UMF_RESULT_ERROR_UNKNOWN; + goto cleanup_mmap; + } + + // Initialize the file provider fields + file_provider->poffset = 0; + file_provider->foffset = 0; + file_provider->page_size = (size_t)page_size; + *provider = file_provider; + + return UMF_RESULT_SUCCESS; + +cleanup_mmap: + munmap(file_provider->ptr, ADDRESS_RESERVATION); +cleanup_fd: + close(file_provider->fd); +cleanup_malloc: + free(file_provider); + return ret; +} + +// Function to deinitialize the file provider +static void file_deinit(void *provider) { + file_provider_t *file_provider = (file_provider_t *)provider; + munmap(file_provider->ptr, ADDRESS_RESERVATION); + close(file_provider->fd); + free(file_provider); +} + +// Function to allocate memory from the file provider +static umf_result_t file_alloc(void *provider, size_t size, size_t alignment, + void **ptr) { + if (provider == NULL || ptr == NULL) { + fprintf(stderr, "Provider or ptr cannot be null\n"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + file_provider_t *file_provider = (file_provider_t *)provider; + size_t page_size = file_provider->page_size; + + if (alignment && (alignment % page_size) && (page_size % alignment)) { + fprintf(stderr, + "Wrong alignment: %zu (not a multiple or a divider of the " + "minimum page size (%zu))", + alignment, page_size); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + size = ALIGN_UP(size, page_size); + + // calculate address for new allocation. All allocation are page aligned so + // if alignment is bigger than page size we have to adjust the address + uintptr_t ptr_offset = + (uintptr_t)file_provider->ptr + file_provider->poffset; + uintptr_t aligned_ptr = + alignment > page_size ? ALIGN_UP(ptr_offset, alignment) : ptr_offset; + + size_t new_offset = aligned_ptr + size - (uintptr_t)file_provider->ptr; + if (new_offset + size > ADDRESS_RESERVATION) { + fprintf(stderr, "This example limits allocation up to 10GB\n"); + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + // Ensure the file is large enough to hold the new allocation + if (fallocate(file_provider->fd, 0, file_provider->foffset, size)) { + perror("Fallocate failed"); + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + // Map the file in place of the reservation + void *ret = mmap((void *)aligned_ptr, size, PROT_READ | PROT_WRITE, + MAP_FIXED | MAP_PRIVATE, file_provider->fd, + file_provider->foffset); + if (ret == MAP_FAILED) { + perror("Memory map failed"); + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + file_provider->poffset = new_offset; + file_provider->foffset += size; + *ptr = ret; + return UMF_RESULT_SUCCESS; +} + +// Function to free allocated memory from the file provider +static umf_result_t file_free(void *provider, void *ptr, size_t size) { + if (provider == NULL || ptr == NULL) { + fprintf(stderr, "Provider or ptr cannot be null\n"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + file_provider_t *file_provider = (file_provider_t *)provider; + if (size == 0) { + fprintf(stderr, "Size cannot be 0\n"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + if (ptr < file_provider->ptr || + (uintptr_t)ptr >= + (uintptr_t)file_provider->ptr + file_provider->poffset) { + fprintf(stderr, "Ptr is not within the provider's memory\n"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + size = ALIGN_UP(size, file_provider->page_size); + + // Replace allocation with a reservation to free memory + void *ptr2 = mmap(ptr, size, PROT_NONE, + MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + if (ptr2 == MAP_FAILED) { + perror("Failed to free memory"); + return UMF_RESULT_ERROR_UNKNOWN; + } + + // Free allocated blocks to the filesystem + if (fallocate(file_provider->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, + (uintptr_t)ptr - (uintptr_t)file_provider->ptr, size)) { + perror("Fallocate failed"); + return UMF_RESULT_ERROR_UNKNOWN; + } + + return UMF_RESULT_SUCCESS; +} + +// Function to get the name of the file provider +static const char *file_get_name(void *provider) { + (void)provider; // Unused parameter + return "File Provider"; +} + +// Function to get the last native error of the file provider +// This function is needed only if the provider returns UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC +static void file_get_last_native_error(void *provider, const char **ppMessage, + int32_t *pError) { + (void)provider; // Unused parameter + *ppMessage = ""; + *pError = 0; +} + +// Function to get the recommended page size of the file provider +static umf_result_t file_get_recommended_page_size(void *provider, size_t size, + size_t *pageSize) { + (void)size; // Unused parameter + if (provider == NULL || pageSize == NULL) { + fprintf(stderr, "Provider or pageSize cannot be null\n"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + file_provider_t *file_provider = (file_provider_t *)provider; + *pageSize = file_provider->page_size; + return UMF_RESULT_SUCCESS; +} + +// Function to get the minimum page size of the file provider +static umf_result_t file_get_min_page_size(void *provider, void *ptr, + size_t *pageSize) { + (void)ptr; // Unused parameter + if (provider == NULL || pageSize == NULL) { + fprintf(stderr, "Provider or pageSize cannot be null\n"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + file_provider_t *file_provider = (file_provider_t *)provider; + *pageSize = file_provider->page_size; + return UMF_RESULT_SUCCESS; +} + +// File provider operations +static umf_memory_provider_ops_t file_ops = { + .version = UMF_VERSION_CURRENT, + .initialize = file_init, + .finalize = file_deinit, + .alloc = file_alloc, + .free = file_free, + .get_name = file_get_name, + .get_last_native_error = file_get_last_native_error, + .get_recommended_page_size = file_get_recommended_page_size, + .get_min_page_size = file_get_min_page_size, +}; + +// Main function +int main(void) { + // A result object for storing UMF API result status + umf_result_t res; + umf_memory_provider_handle_t provider; + file_params_t params; + params.filename = "/tmp/file_provider_example"; + + // Create a memory provider + res = umfMemoryProviderCreate(&file_ops, ¶ms, &provider); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to create a memory provider!\n"); + return -1; + } + printf("OS memory provider created at %p\n", (void *)provider); + + // Allocate memory from the memory provider + size_t alloc_size = 5000; + size_t alignment = 0; + void *ptr_provider = NULL; + + res = + umfMemoryProviderAlloc(provider, alloc_size, alignment, &ptr_provider); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, + "Failed to allocate memory from the memory provider!\n"); + goto memory_provider_destroy; + } + + const char *strSource = "Allocated memory at"; + + // Write to the allocated memory + memset(ptr_provider, '\0', alloc_size); + strncpy(ptr_provider, strSource, alloc_size); + printf("%s %p with the memory provider at %p\n", (char *)ptr_provider, + (void *)ptr_provider, (void *)provider); + + // Free the allocated memory + res = umfMemoryProviderFree(provider, ptr_provider, alloc_size); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to free memory to the provider!\n"); + goto memory_provider_destroy; + } + printf("Freed memory at %p\n", ptr_provider); + + // Create a memory pool + umf_memory_pool_ops_t *pool_ops = umfScalablePoolOps(); + void *pool_params = NULL; + umf_pool_create_flags_t flags = 0; + umf_memory_pool_handle_t pool; + + res = umfPoolCreate(pool_ops, provider, pool_params, flags, &pool); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to create a pool!\n"); + goto memory_provider_destroy; + } + printf("Scalable memory pool created at %p\n", (void *)pool); + + // Allocate some memory in the pool + size_t num = 1; + alloc_size = 128; + + char *ptr = umfPoolCalloc(pool, num, alloc_size); + if (!ptr) { + fprintf(stderr, "Failed to allocate memory in the pool!\n"); + goto memory_pool_destroy; + } + + // Write a string to the allocated memory + strncpy(ptr, strSource, alloc_size); + printf("%s %p\n", ptr, (void *)ptr); + + // Retrieve a memory pool from a pointer, available with memory tracking + umf_memory_pool_handle_t check_pool = umfPoolByPtr(ptr); + printf("Memory at %p has been allocated from the pool at %p\n", (void *)ptr, + (void *)check_pool); + + // Retrieve a memory provider from a pool + umf_memory_provider_handle_t check_provider; + res = umfPoolGetMemoryProvider(pool, &check_provider); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to retrieve a memory provider for the pool!\n"); + goto memory_pool_destroy; + } + printf("Pool at %p has been allocated from the provider at %p\n", + (void *)pool, (void *)check_provider); + + // Clean up + umfFree(ptr); + umfPoolDestroy(pool); + umfMemoryProviderDestroy(provider); + return 0; + +memory_pool_destroy: + umfPoolDestroy(pool); +memory_provider_destroy: + umfMemoryProviderDestroy(provider); + return -1; +} diff --git a/examples/memspace/memspace_hmat.c b/examples/memspace/memspace_hmat.c new file mode 100644 index 000000000..64d869e73 --- /dev/null +++ b/examples/memspace/memspace_hmat.c @@ -0,0 +1,136 @@ +/* + * + * Copyright (C) 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 + +// Needed for CI +#define test_skip_error_code 125 + +// Function to create a memory provider which allocates memory from the specified NUMA node +int createMemoryProvider(umf_memory_provider_handle_t *hProvider, + umf_const_memspace_handle_t hMemspace) { + int ret = 0; + umf_result_t result; + umf_mempolicy_handle_t hPolicy = NULL; + if (hMemspace == NULL) { + fprintf(stderr, "Memspace is NULL - do you have HMAT enabled?\n"); + return 1; + } + // Create a mempolicy - mempolicy defines how we want to use memory from memspace. + // In this example, we want to bind memory to the best node in the memspace, + // for the thread that allocates memory. + result = umfMempolicyCreate(UMF_MEMPOLICY_BIND, &hPolicy); + if (result != UMF_RESULT_SUCCESS) { + ret = -1; + fprintf(stderr, "umfMempolicyCreate failed.\n"); + goto error_mempolicy; + } + + // Create a memory provider using the memory space and memory policy + result = umfMemoryProviderCreateFromMemspace(hMemspace, hPolicy, hProvider); + if (result != UMF_RESULT_SUCCESS) { + ret = -1; + fprintf(stderr, "umfMemoryProviderCreateFromMemspace failed.\n"); + goto error_provider; + } + + // After creating the memory provider, we can destroy the mempolicy +error_provider: + umfMempolicyDestroy(hPolicy); +error_mempolicy: + return ret; +} + +int main(void) { + umf_memory_provider_handle_t hProvider = NULL; + umf_result_t ret; + void *ptr = NULL; + size_t size = 1024; + size_t alignment = 64; + + // Check if NUMA is available + if (numa_available() < 0) { + fprintf(stderr, "NUMA is not available on this system.\n"); + return -1; + } + + // Create the memory provider that allocates memory from the highest bandwidth numa nodes + ret = createMemoryProvider(&hProvider, umfMemspaceHighestBandwidthGet()); + if (ret != UMF_RESULT_SUCCESS) { + return ret == 1 ? test_skip_error_code : -1; + } + + // Allocate memory from the memory provider + ret = umfMemoryProviderAlloc(hProvider, size, alignment, &ptr); + if (ret != UMF_RESULT_SUCCESS) { + fprintf(stderr, "umfMemoryProviderAlloc failed.\n"); + umfMemoryProviderDestroy(hProvider); + return -1; + } + + // Use the allocated memory (ptr) here + memset(ptr, 1, size); + + // Lets check the NUMA node of the allocated memory + int nodeId; + int retm = get_mempolicy(&nodeId, NULL, 0, ptr, MPOL_F_ADDR | MPOL_F_NODE); + if (retm != 0) { + fprintf(stderr, "get_mempolicy failed.\n"); + umfMemoryProviderFree(hProvider, ptr, size); + umfMemoryProviderDestroy(hProvider); + return -1; + } + + printf("Allocated memory at %p from the highest bandwidth node: %d\n", ptr, + nodeId); + + // Free the allocated memory + umfMemoryProviderFree(hProvider, ptr, size); + + umfMemoryProviderDestroy(hProvider); + + // Lets now allocate memory from the lowest latency node + ret = createMemoryProvider(&hProvider, umfMemspaceLowestLatencyGet()); + if (ret != UMF_RESULT_SUCCESS) { + return -1; + } + + ret = umfMemoryProviderAlloc(hProvider, size, alignment, &ptr); + + if (ret != UMF_RESULT_SUCCESS) { + fprintf(stderr, "umfMemoryProviderAlloc failed.\n"); + umfMemoryProviderDestroy(hProvider); + return -1; + } + + memset(ptr, 1, size); + + retm = get_mempolicy(&nodeId, NULL, 0, ptr, MPOL_F_ADDR | MPOL_F_NODE); + if (retm != 0) { + fprintf(stderr, "get_mempolicy failed.\n"); + umfMemoryProviderFree(hProvider, ptr, size); + umfMemoryProviderDestroy(hProvider); + return -1; + } + printf("Allocated memory at %p from the lowest latency node: %d\n", ptr, + nodeId); + + // Free the allocated memory + umfMemoryProviderFree(hProvider, ptr, size); + + umfMemoryProviderDestroy(hProvider); + + return 0; +} diff --git a/examples/memspace/memspace_numa.c b/examples/memspace/memspace_numa.c new file mode 100644 index 000000000..7d328d4a0 --- /dev/null +++ b/examples/memspace/memspace_numa.c @@ -0,0 +1,106 @@ +/* + * + * Copyright (C) 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 + +// Function to create a memory provider which allocates memory from the specified NUMA node +int createMemoryProvider(umf_memory_provider_handle_t *hProvider, + unsigned numa) { + int ret = 0; + umf_result_t result; + umf_memspace_handle_t hMemspace = NULL; + umf_mempolicy_handle_t hPolicy = NULL; + + // Create a memspace - memspace is a list of memory sources. + // In this example, we create a memspace that contains single numa node; + result = umfMemspaceCreateFromNumaArray(&numa, 1, &hMemspace); + if (result != UMF_RESULT_SUCCESS) { + ret = -1; + fprintf(stderr, "umfMemspaceCreateFromNumaArray failed.\n"); + goto error_memspace; + } + + // Create a mempolicy - mempolicy defines how we want to use memory from memspace. + // In this example, we want to bind memory to the specified numa node. + result = umfMempolicyCreate(UMF_MEMPOLICY_BIND, &hPolicy); + if (result != UMF_RESULT_SUCCESS) { + ret = -1; + fprintf(stderr, "umfMempolicyCreate failed.\n"); + goto error_mempolicy; + } + + // Create a memory provider using the memory space and memory policy + result = umfMemoryProviderCreateFromMemspace(hMemspace, hPolicy, hProvider); + if (result != UMF_RESULT_SUCCESS) { + ret = -1; + fprintf(stderr, "umfMemoryProviderCreateFromMemspace failed.\n"); + goto error_provider; + } + + // After creating the memory provider, we can destroy the memspace and mempolicy +error_provider: + umfMempolicyDestroy(hPolicy); +error_mempolicy: + umfMemspaceDestroy(hMemspace); +error_memspace: + return ret; +} + +int main(void) { + umf_memory_provider_handle_t hProvider = NULL; + umf_result_t ret; + + // Check if NUMA is available + if (numa_available() < 0) { + fprintf(stderr, "NUMA is not available on this system.\n"); + return -1; + } + + // Create the memory provider that allocates memory from the specified NUMA node + // In this example, we allocate memory from the NUMA node 0 + ret = createMemoryProvider(&hProvider, 0); + if (ret != UMF_RESULT_SUCCESS) { + return -1; + } + + // Allocate memory from the memory provider + void *ptr = NULL; + size_t size = 1024; + size_t alignment = 64; + + ret = umfMemoryProviderAlloc(hProvider, size, alignment, &ptr); + if (ret != UMF_RESULT_SUCCESS) { + fprintf(stderr, "umfMemoryProviderAlloc failed.\n"); + goto error_alloc; + } + + // Use the allocated memory (ptr) here + memset(ptr, 1, size); + + // Lets check the NUMA node of the allocated memory + int nodeId; + int retm = get_mempolicy(&nodeId, NULL, 0, ptr, MPOL_F_ADDR | MPOL_F_NODE); + if (retm != 0) { + fprintf(stderr, "get_mempolicy failed.\n"); + goto error_alloc; + } + printf("Allocated memory at %p from numa_node %d\n", ptr, nodeId); + // Free the allocated memory + umfMemoryProviderFree(hProvider, ptr, size); +error_alloc: + umfMemoryProviderDestroy(hProvider); + + return ret == UMF_RESULT_SUCCESS ? 0 : 1; +} diff --git a/scripts/docs_config/examples.rst b/scripts/docs_config/examples.rst index 4098583a6..1a76eea2a 100644 --- a/scripts/docs_config/examples.rst +++ b/scripts/docs_config/examples.rst @@ -116,6 +116,22 @@ in the UMF repository. TODO +Memspace +============================================================================== + +You can find the full examples code in the `examples/memspace`_ directory +in the UMF repository. + +TODO + +Custom memory provider +============================================================================== + +You can find the full examples code in the `examples/custom_provider/file_provider.c`_ file +in the UMF repository. + +TODO + IPC example with Level Zero Memory Provider ============================================================================== The full code of the example is in the `examples/ipc_level_zero/ipc_level_zero.c`_ file in the UMF repository. @@ -195,6 +211,8 @@ the :any:`umfCloseIPCHandle` function is called. .. _examples/basic/basic.c: https://github.com/oneapi-src/unified-memory-framework/blob/main/examples/basic/basic.c .. _examples/gpu_shared_memory/gpu_shared_memory.c: https://github.com/oneapi-src/unified-memory-framework/blob/main/examples/gpu_shared_memory/gpu_shared_memory.c .. _examples/ipc_level_zero/ipc_level_zero.c: https://github.com/oneapi-src/unified-memory-framework/blob/main/examples/ipc_level_zero/ipc_level_zero.c +.. _examples/custom_provider/file_provider.c: https://github.com/oneapi-src/unified-memory-framework/blob/main/examples/custom_provider/file_provider.c +.. _examples/memspace: https://github.com/oneapi-src/unified-memory-framework/blob/main/examples/memspace/ .. _README: https://github.com/oneapi-src/unified-memory-framework/blob/main/README.md#memory-pool-managers .. _umf/ipc.h: https://github.com/oneapi-src/unified-memory-framework/blob/main/include/umf/ipc.h .. _provider_os_memory.h: https://github.com/oneapi-src/unified-memory-framework/blob/main/include/umf/providers/provider_os_memory.h From e5fcc5b9b7b69214805e4672a9279661bb0df861 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Fri, 19 Jul 2024 09:25:49 +0200 Subject: [PATCH 002/352] Fix warnings RC4005: 'UMF_VERSION' : redefinition Fix the warnings: umf\build\src\libumf.rc(12): warning RC4005: 'UMF_VERSION' : redefinition umf\build\src\proxy_lib\proxy_lib.rc(12): warning RC4005: 'UMF_VERSION' : redefinition Signed-off-by: Lukasz Dorau --- src/libumf.rc.in | 6 +++--- src/proxy_lib/proxy_lib.rc.in | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libumf.rc.in b/src/libumf.rc.in index 9d0677f6d..3915e0a10 100644 --- a/src/libumf.rc.in +++ b/src/libumf.rc.in @@ -9,7 +9,7 @@ #include "umf/base.h" #define UMF_VERNUMBERS @CMAKE_PROJECT_VERSION_MAJOR@,@CMAKE_PROJECT_VERSION_MINOR@,@CMAKE_PROJECT_VERSION_PATCH@,@UMF_VERSION_REVISION@ -#define UMF_VERSION "@UMF_VERSION@" +#define _UMF_VERSION "@UMF_VERSION@" #ifdef _DEBUG #define VERSION_DEBUG VS_FF_DEBUG @@ -50,12 +50,12 @@ BEGIN BEGIN VALUE "CompanyName", "Intel Corporation\0" VALUE "FileDescription", "Unified Memory Framework (UMF) library\0" - VALUE "FileVersion", UMF_VERSION "\0" + VALUE "FileVersion", _UMF_VERSION "\0" VALUE "LegalCopyright", "Copyright 2024, Intel Corporation. All rights reserved.\0" VALUE "LegalTrademarks", "\0" VALUE "OriginalFilename", "umf.dll\0" VALUE "ProductName", "Unified Memory Framework (UMF)\0" - VALUE "ProductVersion", UMF_VERSION "\0" + VALUE "ProductVersion", _UMF_VERSION "\0" VALUE "PrivateBuild", "\0" VALUE "SpecialBuild", "\0" END diff --git a/src/proxy_lib/proxy_lib.rc.in b/src/proxy_lib/proxy_lib.rc.in index 66910afc4..29c8b0482 100644 --- a/src/proxy_lib/proxy_lib.rc.in +++ b/src/proxy_lib/proxy_lib.rc.in @@ -9,7 +9,7 @@ #include "umf/base.h" #define UMF_VERNUMBERS @CMAKE_PROJECT_VERSION_MAJOR@,@CMAKE_PROJECT_VERSION_MINOR@,@CMAKE_PROJECT_VERSION_PATCH@,@UMF_VERSION_REVISION@ -#define UMF_VERSION "@UMF_VERSION@" +#define _UMF_VERSION "@UMF_VERSION@" #ifdef _DEBUG #define VERSION_DEBUG VS_FF_DEBUG @@ -50,12 +50,12 @@ BEGIN BEGIN VALUE "CompanyName", "Intel Corporation\0" VALUE "FileDescription", "Unified Memory Framework (UMF) proxy library\0" - VALUE "FileVersion", UMF_VERSION "\0" + VALUE "FileVersion", _UMF_VERSION "\0" VALUE "LegalCopyright", "Copyright 2024, Intel Corporation. All rights reserved.\0" VALUE "LegalTrademarks", "\0" VALUE "OriginalFilename", "umf_proxy.dll\0" VALUE "ProductName", "Unified Memory Framework (UMF)\0" - VALUE "ProductVersion", UMF_VERSION "\0" + VALUE "ProductVersion", _UMF_VERSION "\0" VALUE "PrivateBuild", "\0" VALUE "SpecialBuild", "\0" END From 79dd7091ec1ef5821c347c5f4a9ee6e30ef0bc48 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Fri, 19 Jul 2024 13:23:51 +0200 Subject: [PATCH 003/352] Add lock for updating file size in OS memory provider Add lock for updating file size in OS memory provider, because umfMemoryProviderAlloc() has to be MT-safe. Signed-off-by: Lukasz Dorau --- src/provider/provider_os_memory.c | 31 +++++++++++++++++----- src/provider/provider_os_memory_internal.h | 3 +++ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/provider/provider_os_memory.c b/src/provider/provider_os_memory.c index 4bec6d5fd..38cb3ff4a 100644 --- a/src/provider/provider_os_memory.c +++ b/src/provider/provider_os_memory.c @@ -525,6 +525,14 @@ static umf_result_t os_initialize(void *params, void **provider) { goto err_destroy_bitmaps; } + if (os_provider->fd > 0) { + if (util_mutex_init(&os_provider->lock_fd) == NULL) { + LOG_ERR("initializing the file size lock failed"); + ret = UMF_RESULT_ERROR_UNKNOWN; + goto err_destroy_bitmaps; + } + } + os_provider->nodeset_str_buf = umf_ba_global_alloc(NODESET_STR_BUF_LEN); if (!os_provider->nodeset_str_buf) { LOG_INFO("allocating memory for printing NUMA nodes failed"); @@ -562,6 +570,10 @@ static void os_finalize(void *provider) { os_memory_provider_t *os_provider = provider; + if (os_provider->fd > 0) { + util_mutex_destroy_not_free(&os_provider->lock_fd); + } + critnib_delete(os_provider->fd_offset_map); free_bitmaps(os_provider); @@ -624,8 +636,8 @@ static inline void assert_is_page_aligned(uintptr_t ptr, size_t page_size) { static int os_mmap_aligned(void *hint_addr, size_t length, size_t alignment, size_t page_size, int prot, int flag, int fd, - size_t max_fd_size, void **out_addr, - size_t *fd_size) { + size_t max_fd_size, os_mutex_t *lock_fd, + void **out_addr, size_t *fd_size) { assert(out_addr); size_t extended_length = length; @@ -641,13 +653,20 @@ static int os_mmap_aligned(void *hint_addr, size_t length, size_t alignment, size_t fd_offset = 0; if (fd > 0) { + if (util_mutex_lock(lock_fd)) { + LOG_ERR("locking file size failed"); + return -1; + } + if (*fd_size + extended_length > max_fd_size) { + util_mutex_unlock(lock_fd); LOG_ERR("cannot grow a file size beyond %zu", max_fd_size); return -1; } fd_offset = *fd_size; *fd_size += extended_length; + util_mutex_unlock(lock_fd); } void *ptr = os_mmap(hint_addr, extended_length, prot, flag, fd, fd_offset); @@ -899,11 +918,11 @@ static umf_result_t os_alloc(void *provider, size_t size, size_t alignment, errno = 0; ret = os_mmap_aligned(NULL, size, alignment, page_size, os_provider->protection, os_provider->visibility, - os_provider->fd, os_provider->max_size_fd, &addr, - &os_provider->size_fd); + os_provider->fd, os_provider->max_size_fd, + &os_provider->lock_fd, &addr, &os_provider->size_fd); if (ret) { - os_store_last_native_error(UMF_OS_RESULT_ERROR_ALLOC_FAILED, errno); - LOG_PERR("memory allocation failed"); + os_store_last_native_error(UMF_OS_RESULT_ERROR_ALLOC_FAILED, 0); + LOG_ERR("memory allocation failed"); return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; } diff --git a/src/provider/provider_os_memory_internal.h b/src/provider/provider_os_memory_internal.h index 68750c6d1..81d729d27 100644 --- a/src/provider/provider_os_memory_internal.h +++ b/src/provider/provider_os_memory_internal.h @@ -13,6 +13,7 @@ #include "critnib.h" #include "umf_hwloc.h" #include "utils_common.h" +#include "utils_concurrency.h" #ifdef __cplusplus extern "C" { @@ -33,6 +34,8 @@ typedef struct os_memory_provider_t { int fd; // file descriptor for memory mapping size_t size_fd; // size of file used for memory mapping size_t max_size_fd; // maximum size of file used for memory mapping + os_mutex_t lock_fd; // lock for updating file size + // A critnib map storing (ptr, fd_offset + 1) pairs. We add 1 to fd_offset // in order to be able to store fd_offset equal 0, because // critnib_get() returns value or NULL, so a value cannot equal 0. From 97d608b2c5082944fe1eb7cf49733c6b0dff2d2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Plewa?= Date: Fri, 19 Jul 2024 16:55:57 +0200 Subject: [PATCH 004/352] rename mem_target to memtarget As we want to export memtarget api, it's name should be consistent with other api (memspace, mempolicy) --- src/CMakeLists.txt | 6 +-- src/memory_target.h | 51 ------------------- src/memspace.c | 32 ++++++------ src/memspace_internal.h | 13 +++-- src/memspaces/memspace_highest_bandwidth.c | 8 +-- src/memspaces/memspace_highest_capacity.c | 2 +- src/memspaces/memspace_host_all.c | 2 +- src/memspaces/memspace_lowest_latency.c | 8 +-- src/memspaces/memspace_numa.c | 10 ++-- src/{memory_target.c => memtarget.c} | 37 +++++++------- src/memtarget.h | 47 +++++++++++++++++ src/{memory_target_ops.h => memtarget_ops.h} | 12 ++--- .../memtarget_numa.c} | 39 +++++++------- .../memtarget_numa.h} | 14 ++--- test/memspaces/memspace_highest_capacity.cpp | 2 +- test/memspaces/memspace_host_all.cpp | 6 +-- 16 files changed, 140 insertions(+), 149 deletions(-) delete mode 100644 src/memory_target.h rename src/{memory_target.c => memtarget.c} (65%) create mode 100644 src/memtarget.h rename src/{memory_target_ops.h => memtarget_ops.h} (85%) rename src/{memory_targets/memory_target_numa.c => memtargets/memtarget_numa.c} (89%) rename src/{memory_targets/memory_target_numa.h => memtargets/memtarget_numa.h} (54%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 751792db4..7c19133f1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -58,7 +58,7 @@ set(UMF_SOURCES memory_pool.c memory_provider.c memory_provider_get_last_failed.c - memory_target.c + memtarget.c mempolicy.c memspace.c provider/provider_tracking.c @@ -81,7 +81,7 @@ set(UMF_PRIVATE_COMPILE_DEFINITIONS "-DUMF_SRC_VERSION=${UMF_SRC_VERSION}") set(UMF_SOURCES_COMMON_LINUX_MACOSX provider/provider_os_memory.c provider/provider_os_memory_posix.c - memory_targets/memory_target_numa.c + memtargets/memtarget_numa.c memspaces/memspace_numa.c memspaces/memspace_host_all.c memspaces/memspace_highest_capacity.c @@ -178,7 +178,7 @@ target_include_directories( $ $ $ - $ + $ $) install(TARGETS umf EXPORT ${PROJECT_NAME}-targets) diff --git a/src/memory_target.h b/src/memory_target.h deleted file mode 100644 index c522cce24..000000000 --- a/src/memory_target.h +++ /dev/null @@ -1,51 +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_MEMORY_TARGET_H -#define UMF_MEMORY_TARGET_H 1 - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct umf_memory_target_ops_t; -typedef struct umf_memory_target_ops_t umf_memory_target_ops_t; - -typedef struct umf_memory_target_t { - const umf_memory_target_ops_t *ops; - void *priv; -} umf_memory_target_t; - -typedef umf_memory_target_t *umf_memory_target_handle_t; - -umf_result_t umfMemoryTargetCreate(const umf_memory_target_ops_t *ops, - void *params, - umf_memory_target_handle_t *memoryTarget); -void umfMemoryTargetDestroy(umf_memory_target_handle_t memoryTarget); - -umf_result_t umfMemoryTargetClone(umf_memory_target_handle_t memoryTarget, - umf_memory_target_handle_t *outHandle); -umf_result_t umfMemoryTargetGetCapacity(umf_memory_target_handle_t memoryTarget, - size_t *capacity); -umf_result_t -umfMemoryTargetGetBandwidth(umf_memory_target_handle_t srcMemoryTarget, - umf_memory_target_handle_t dstMemoryTarget, - size_t *bandwidth); -umf_result_t -umfMemoryTargetGetLatency(umf_memory_target_handle_t srcMemoryTarget, - umf_memory_target_handle_t dstMemoryTarget, - size_t *latency); - -#ifdef __cplusplus -} -#endif - -#endif /* UMF_MEMORY_TARGET_H */ diff --git a/src/memspace.c b/src/memspace.c index 03e716c84..ea4fe1775 100644 --- a/src/memspace.c +++ b/src/memspace.c @@ -13,9 +13,9 @@ #include #include "base_alloc_global.h" -#include "memory_target.h" -#include "memory_target_ops.h" #include "memspace_internal.h" +#include "memtarget.h" +#include "memtarget_ops.h" #ifndef NDEBUG static umf_result_t @@ -25,7 +25,7 @@ verifyMemTargetsTypes(umf_const_memspace_handle_t memspace) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - const struct umf_memory_target_ops_t *ops = memspace->nodes[0]->ops; + const struct umf_memtarget_ops_t *ops = memspace->nodes[0]->ops; for (size_t i = 1; i < memspace->size; i++) { if (memspace->nodes[i]->ops != ops) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; @@ -66,7 +66,7 @@ umf_result_t umfPoolCreateFromMemspace(umf_const_memspace_handle_t memspace, return ret; } - // TODO: for now, we only support memspaces that consist of memory_targets + // TODO: for now, we only support memspaces that consist of memtargets // of the same type. Fix this. assert(verifyMemTargetsTypes(memspace) == UMF_RESULT_SUCCESS); ret = memspace->nodes[0]->ops->pool_create_from_memspace( @@ -91,7 +91,7 @@ umfMemoryProviderCreateFromMemspace(umf_const_memspace_handle_t memspace, return ret; } - // TODO: for now, we only support memspaces that consist of memory_targets + // TODO: for now, we only support memspaces that consist of memtargets // of the same type. Fix this. assert(verifyMemTargetsTypes(memspace) == UMF_RESULT_SUCCESS); ret = memspace->nodes[0]->ops->memory_provider_create_from_memspace( @@ -126,7 +126,7 @@ umf_result_t umfMemspaceClone(umf_const_memspace_handle_t hMemspace, clone->size = hMemspace->size; clone->nodes = - umf_ba_global_alloc(sizeof(umf_memory_target_handle_t) * clone->size); + umf_ba_global_alloc(sizeof(umf_memtarget_handle_t) * clone->size); if (!clone->nodes) { umf_ba_global_free(clone); return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; @@ -155,14 +155,14 @@ umf_result_t umfMemspaceClone(umf_const_memspace_handle_t hMemspace, return ret; } -struct memory_target_sort_entry { +struct memtarget_sort_entry { uint64_t property; - umf_memory_target_handle_t node; + umf_memtarget_handle_t node; }; static int propertyCmp(const void *a, const void *b) { - const struct memory_target_sort_entry *entryA = a; - const struct memory_target_sort_entry *entryB = b; + const struct memtarget_sort_entry *entryA = a; + const struct memtarget_sort_entry *entryB = b; if (entryA->property < entryB->property) { return 1; @@ -175,14 +175,14 @@ static int propertyCmp(const void *a, const void *b) { umf_result_t umfMemspaceSortDesc(umf_memspace_handle_t hMemspace, - umf_result_t (*getProperty)(umf_memory_target_handle_t node, + umf_result_t (*getProperty)(umf_memtarget_handle_t node, uint64_t *property)) { if (!hMemspace || !getProperty) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - struct memory_target_sort_entry *entries = umf_ba_global_alloc( - sizeof(struct memory_target_sort_entry) * hMemspace->size); + struct memtarget_sort_entry *entries = umf_ba_global_alloc( + sizeof(struct memtarget_sort_entry) * hMemspace->size); if (!entries) { return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; } @@ -198,7 +198,7 @@ umfMemspaceSortDesc(umf_memspace_handle_t hMemspace, } } - qsort(entries, hMemspace->size, sizeof(struct memory_target_sort_entry), + qsort(entries, hMemspace->size, sizeof(struct memtarget_sort_entry), propertyCmp); // apply the order to the original array @@ -218,7 +218,7 @@ umf_result_t umfMemspaceFilter(umf_const_memspace_handle_t hMemspace, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - umf_memory_target_handle_t *uniqueBestNodes = + umf_memtarget_handle_t *uniqueBestNodes = umf_ba_global_alloc(hMemspace->size * sizeof(*uniqueBestNodes)); if (!uniqueBestNodes) { return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; @@ -228,7 +228,7 @@ umf_result_t umfMemspaceFilter(umf_const_memspace_handle_t hMemspace, size_t numUniqueBestNodes = 0; for (size_t nodeIdx = 0; nodeIdx < hMemspace->size; nodeIdx++) { - umf_memory_target_handle_t target = NULL; + umf_memtarget_handle_t target = NULL; ret = getTarget(hMemspace->nodes[nodeIdx], hMemspace->nodes, hMemspace->size, &target); if (ret != UMF_RESULT_SUCCESS) { diff --git a/src/memspace_internal.h b/src/memspace_internal.h index b570a7472..7cc62fac2 100644 --- a/src/memspace_internal.h +++ b/src/memspace_internal.h @@ -13,7 +13,7 @@ #include #include "base_alloc.h" -#include "memory_target.h" +#include "memtarget.h" #ifdef __cplusplus extern "C" { @@ -21,7 +21,7 @@ extern "C" { struct umf_memspace_t { size_t size; - umf_memory_target_handle_t *nodes; + umf_memtarget_handle_t *nodes; }; /// @@ -30,8 +30,7 @@ struct umf_memspace_t { umf_result_t umfMemspaceClone(umf_const_memspace_handle_t hMemspace, umf_memspace_handle_t *outHandle); -typedef umf_result_t (*umfGetPropertyFn)(umf_memory_target_handle_t, - uint64_t *); +typedef umf_result_t (*umfGetPropertyFn)(umf_memtarget_handle_t, uint64_t *); /// /// \brief Sorts memspace by getProperty() in descending order @@ -39,10 +38,10 @@ typedef umf_result_t (*umfGetPropertyFn)(umf_memory_target_handle_t, umf_result_t umfMemspaceSortDesc(umf_memspace_handle_t hMemspace, umfGetPropertyFn getProperty); -typedef umf_result_t (*umfGetTargetFn)(umf_memory_target_handle_t initiator, - umf_memory_target_handle_t *nodes, +typedef umf_result_t (*umfGetTargetFn)(umf_memtarget_handle_t initiator, + umf_memtarget_handle_t *nodes, size_t numNodes, - umf_memory_target_handle_t *target); + umf_memtarget_handle_t *target); /// /// \brief Filters the targets using getTarget() to create a new memspace diff --git a/src/memspaces/memspace_highest_bandwidth.c b/src/memspaces/memspace_highest_bandwidth.c index d82e5f4f1..9790dbe8b 100644 --- a/src/memspaces/memspace_highest_bandwidth.c +++ b/src/memspaces/memspace_highest_bandwidth.c @@ -12,17 +12,17 @@ #include #include "base_alloc_global.h" -#include "memory_target_numa.h" #include "memspace_internal.h" +#include "memtarget_numa.h" #include "topology.h" #include "utils_common.h" #include "utils_concurrency.h" #include "utils_log.h" -static umf_result_t getBestBandwidthTarget(umf_memory_target_handle_t initiator, - umf_memory_target_handle_t *nodes, +static umf_result_t getBestBandwidthTarget(umf_memtarget_handle_t initiator, + umf_memtarget_handle_t *nodes, size_t numNodes, - umf_memory_target_handle_t *target) { + umf_memtarget_handle_t *target) { size_t bestNodeIdx = 0; size_t bestBandwidth = 0; for (size_t nodeIdx = 0; nodeIdx < numNodes; nodeIdx++) { diff --git a/src/memspaces/memspace_highest_capacity.c b/src/memspaces/memspace_highest_capacity.c index 0b8f3522e..862ae5a8e 100644 --- a/src/memspaces/memspace_highest_capacity.c +++ b/src/memspaces/memspace_highest_capacity.c @@ -11,8 +11,8 @@ #include #include "base_alloc_global.h" -#include "memory_target_numa.h" #include "memspace_internal.h" +#include "memtarget_numa.h" #include "topology.h" #include "utils_concurrency.h" diff --git a/src/memspaces/memspace_host_all.c b/src/memspaces/memspace_host_all.c index 62c968743..63d4611a8 100644 --- a/src/memspaces/memspace_host_all.c +++ b/src/memspaces/memspace_host_all.c @@ -11,8 +11,8 @@ #include #include "base_alloc_global.h" -#include "memory_target_numa.h" #include "memspace_internal.h" +#include "memtarget_numa.h" #include "topology.h" #include "utils_concurrency.h" diff --git a/src/memspaces/memspace_lowest_latency.c b/src/memspaces/memspace_lowest_latency.c index 2c6656ab2..d9c918712 100644 --- a/src/memspaces/memspace_lowest_latency.c +++ b/src/memspaces/memspace_lowest_latency.c @@ -12,17 +12,17 @@ #include #include "base_alloc_global.h" -#include "memory_target_numa.h" #include "memspace_internal.h" +#include "memtarget_numa.h" #include "topology.h" #include "utils_common.h" #include "utils_concurrency.h" #include "utils_log.h" -static umf_result_t getBestLatencyTarget(umf_memory_target_handle_t initiator, - umf_memory_target_handle_t *nodes, +static umf_result_t getBestLatencyTarget(umf_memtarget_handle_t initiator, + umf_memtarget_handle_t *nodes, size_t numNodes, - umf_memory_target_handle_t *target) { + umf_memtarget_handle_t *target) { size_t bestNodeIdx = 0; size_t bestLatency = SIZE_MAX; for (size_t nodeIdx = 0; nodeIdx < numNodes; nodeIdx++) { diff --git a/src/memspaces/memspace_numa.c b/src/memspaces/memspace_numa.c index 52dc85b64..e4346a4db 100644 --- a/src/memspaces/memspace_numa.c +++ b/src/memspaces/memspace_numa.c @@ -9,8 +9,8 @@ #include -#include "../memory_targets/memory_target_numa.h" #include "../memspace_internal.h" +#include "../memtargets/memtarget_numa.h" #include "base_alloc_global.h" umf_result_t umfMemspaceCreateFromNumaArray(unsigned *nodeIds, size_t numIds, @@ -27,8 +27,8 @@ umf_result_t umfMemspaceCreateFromNumaArray(unsigned *nodeIds, size_t numIds, } memspace->size = numIds; - memspace->nodes = umf_ba_global_alloc(memspace->size * - sizeof(umf_memory_target_handle_t)); + memspace->nodes = + umf_ba_global_alloc(memspace->size * sizeof(umf_memtarget_handle_t)); if (!memspace->nodes) { ret = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; goto err_nodes_alloc; @@ -36,8 +36,8 @@ umf_result_t umfMemspaceCreateFromNumaArray(unsigned *nodeIds, size_t numIds, size_t nodeIdx; for (nodeIdx = 0; nodeIdx < numIds; nodeIdx++) { - struct umf_numa_memory_target_config_t config = {nodeIds[nodeIdx]}; - ret = umfMemoryTargetCreate(&UMF_MEMORY_TARGET_NUMA_OPS, &config, + struct umf_numa_memtarget_config_t config = {nodeIds[nodeIdx]}; + ret = umfMemoryTargetCreate(&UMF_MEMTARGET_NUMA_OPS, &config, &memspace->nodes[nodeIdx]); if (ret) { goto err_target_create; diff --git a/src/memory_target.c b/src/memtarget.c similarity index 65% rename from src/memory_target.c rename to src/memtarget.c index 3cbdb09d9..cf9b30818 100644 --- a/src/memory_target.c +++ b/src/memtarget.c @@ -12,20 +12,19 @@ #include "base_alloc_global.h" #include "libumf.h" -#include "memory_target.h" -#include "memory_target_ops.h" +#include "memtarget.h" +#include "memtarget_ops.h" #include "utils_concurrency.h" -umf_result_t umfMemoryTargetCreate(const umf_memory_target_ops_t *ops, - void *params, - umf_memory_target_handle_t *memoryTarget) { +umf_result_t umfMemoryTargetCreate(const umf_memtarget_ops_t *ops, void *params, + umf_memtarget_handle_t *memoryTarget) { libumfInit(); if (!ops || !memoryTarget) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - umf_memory_target_handle_t target = - umf_ba_global_alloc(sizeof(umf_memory_target_t)); + umf_memtarget_handle_t target = + umf_ba_global_alloc(sizeof(umf_memtarget_t)); if (!target) { return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; } @@ -48,18 +47,18 @@ umf_result_t umfMemoryTargetCreate(const umf_memory_target_ops_t *ops, return UMF_RESULT_SUCCESS; } -void umfMemoryTargetDestroy(umf_memory_target_handle_t memoryTarget) { +void umfMemoryTargetDestroy(umf_memtarget_handle_t memoryTarget) { assert(memoryTarget); memoryTarget->ops->finalize(memoryTarget->priv); umf_ba_global_free(memoryTarget); } -umf_result_t umfMemoryTargetClone(umf_memory_target_handle_t memoryTarget, - umf_memory_target_handle_t *outHandle) { +umf_result_t umfMemoryTargetClone(umf_memtarget_handle_t memoryTarget, + umf_memtarget_handle_t *outHandle) { assert(memoryTarget); assert(outHandle); - *outHandle = umf_ba_global_alloc(sizeof(umf_memory_target_t)); + *outHandle = umf_ba_global_alloc(sizeof(umf_memtarget_t)); if (!*outHandle) { return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; } @@ -77,7 +76,7 @@ umf_result_t umfMemoryTargetClone(umf_memory_target_handle_t memoryTarget, return UMF_RESULT_SUCCESS; } -umf_result_t umfMemoryTargetGetCapacity(umf_memory_target_handle_t memoryTarget, +umf_result_t umfMemoryTargetGetCapacity(umf_memtarget_handle_t memoryTarget, size_t *capacity) { if (!memoryTarget || !capacity) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; @@ -86,10 +85,9 @@ umf_result_t umfMemoryTargetGetCapacity(umf_memory_target_handle_t memoryTarget, return memoryTarget->ops->get_capacity(memoryTarget->priv, capacity); } -umf_result_t -umfMemoryTargetGetBandwidth(umf_memory_target_handle_t srcMemoryTarget, - umf_memory_target_handle_t dstMemoryTarget, - size_t *bandwidth) { +umf_result_t umfMemoryTargetGetBandwidth(umf_memtarget_handle_t srcMemoryTarget, + umf_memtarget_handle_t dstMemoryTarget, + size_t *bandwidth) { if (!srcMemoryTarget || !dstMemoryTarget || !bandwidth) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; } @@ -98,10 +96,9 @@ umfMemoryTargetGetBandwidth(umf_memory_target_handle_t srcMemoryTarget, srcMemoryTarget->priv, dstMemoryTarget->priv, bandwidth); } -umf_result_t -umfMemoryTargetGetLatency(umf_memory_target_handle_t srcMemoryTarget, - umf_memory_target_handle_t dstMemoryTarget, - size_t *latency) { +umf_result_t umfMemoryTargetGetLatency(umf_memtarget_handle_t srcMemoryTarget, + umf_memtarget_handle_t dstMemoryTarget, + size_t *latency) { if (!srcMemoryTarget || !dstMemoryTarget || !latency) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; } diff --git a/src/memtarget.h b/src/memtarget.h new file mode 100644 index 000000000..69125c21f --- /dev/null +++ b/src/memtarget.h @@ -0,0 +1,47 @@ +/* + * + * 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_MEMTARGET_H +#define UMF_MEMTARGET_H 1 + +#include +#ifdef __cplusplus +extern "C" { +#endif + +struct umf_memtarget_ops_t; +typedef struct umf_memtarget_ops_t umf_memtarget_ops_t; + +typedef struct umf_memtarget_t { + const umf_memtarget_ops_t *ops; + void *priv; +} umf_memtarget_t; + +typedef umf_memtarget_t *umf_memtarget_handle_t; + +umf_result_t umfMemoryTargetCreate(const umf_memtarget_ops_t *ops, void *params, + umf_memtarget_handle_t *memoryTarget); +void umfMemoryTargetDestroy(umf_memtarget_handle_t memoryTarget); + +umf_result_t umfMemoryTargetClone(umf_memtarget_handle_t memoryTarget, + umf_memtarget_handle_t *outHandle); +umf_result_t umfMemoryTargetGetCapacity(umf_memtarget_handle_t memoryTarget, + size_t *capacity); +umf_result_t umfMemoryTargetGetBandwidth(umf_memtarget_handle_t srcMemoryTarget, + umf_memtarget_handle_t dstMemoryTarget, + size_t *bandwidth); +umf_result_t umfMemoryTargetGetLatency(umf_memtarget_handle_t srcMemoryTarget, + umf_memtarget_handle_t dstMemoryTarget, + size_t *latency); + +#ifdef __cplusplus +} +#endif + +#endif /* UMF_MEMTARGET_H */ diff --git a/src/memory_target_ops.h b/src/memtarget_ops.h similarity index 85% rename from src/memory_target_ops.h rename to src/memtarget_ops.h index 24e4e8108..f53b80524 100644 --- a/src/memory_target_ops.h +++ b/src/memtarget_ops.h @@ -7,8 +7,8 @@ * */ -#ifndef UMF_MEMORY_TARGET_OPS_H -#define UMF_MEMORY_TARGET_OPS_H 1 +#ifndef UMF_MEMTARGET_OPS_H +#define UMF_MEMTARGET_OPS_H 1 #include #include @@ -17,9 +17,9 @@ extern "C" { #endif -typedef struct umf_memory_target_t *umf_memory_target_handle_t; +typedef struct umf_memtarget_t *umf_memtarget_handle_t; -typedef struct umf_memory_target_ops_t { +typedef struct umf_memtarget_ops_t { /// Version of the ops structure. /// Should be initialized using UMF_VERSION_CURRENT uint32_t version; @@ -44,10 +44,10 @@ typedef struct umf_memory_target_ops_t { size_t *bandwidth); umf_result_t (*get_latency)(void *srcMemoryTarget, void *dstMemoryTarget, size_t *latency); -} umf_memory_target_ops_t; +} umf_memtarget_ops_t; #ifdef __cplusplus } #endif -#endif /* #ifndef UMF_MEMORY_TARGET_OPS_H */ +#endif /* #ifndef UMF_MEMTARGET_OPS_H */ diff --git a/src/memory_targets/memory_target_numa.c b/src/memtargets/memtarget_numa.c similarity index 89% rename from src/memory_targets/memory_target_numa.c rename to src/memtargets/memtarget_numa.c index aa33a1853..553c780bc 100644 --- a/src/memory_targets/memory_target_numa.c +++ b/src/memtargets/memtarget_numa.c @@ -16,13 +16,13 @@ #include "../memory_pool_internal.h" #include "base_alloc.h" #include "base_alloc_global.h" -#include "memory_target_numa.h" #include "mempolicy_internal.h" +#include "memtarget_numa.h" #include "topology.h" #include "utils_assert.h" #include "utils_log.h" -struct numa_memory_target_t { +struct numa_memtarget_t { unsigned physical_id; }; @@ -31,11 +31,11 @@ static umf_result_t numa_initialize(void *params, void **memTarget) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - struct umf_numa_memory_target_config_t *config = - (struct umf_numa_memory_target_config_t *)params; + struct umf_numa_memtarget_config_t *config = + (struct umf_numa_memtarget_config_t *)params; - struct numa_memory_target_t *numaTarget = - umf_ba_global_alloc(sizeof(struct numa_memory_target_t)); + struct numa_memtarget_t *numaTarget = + umf_ba_global_alloc(sizeof(struct numa_memtarget_t)); if (!numaTarget) { return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; } @@ -52,8 +52,8 @@ static umf_result_t numa_memory_provider_create_from_memspace( umf_const_mempolicy_handle_t policy, umf_memory_provider_handle_t *provider) { - struct numa_memory_target_t **numaTargets = - (struct numa_memory_target_t **)memTargets; + struct numa_memtarget_t **numaTargets = + (struct numa_memtarget_t **)memTargets; size_t numNodesProvider; @@ -161,10 +161,9 @@ static umf_result_t numa_pool_create_from_memspace( } static umf_result_t numa_clone(void *memTarget, void **outMemTarget) { - struct numa_memory_target_t *numaTarget = - (struct numa_memory_target_t *)memTarget; - struct numa_memory_target_t *newNumaTarget = - umf_ba_global_alloc(sizeof(struct numa_memory_target_t)); + struct numa_memtarget_t *numaTarget = (struct numa_memtarget_t *)memTarget; + struct numa_memtarget_t *newNumaTarget = + umf_ba_global_alloc(sizeof(struct numa_memtarget_t)); if (!newNumaTarget) { return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; } @@ -185,7 +184,7 @@ static umf_result_t numa_get_capacity(void *memTarget, size_t *capacity) { } hwloc_obj_t numaNode = hwloc_get_numanode_obj_by_os_index( - topology, ((struct numa_memory_target_t *)memTarget)->physical_id); + topology, ((struct numa_memtarget_t *)memTarget)->physical_id); if (!numaNode) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; } @@ -226,7 +225,7 @@ static umf_result_t query_attribute_value(void *srcMemoryTarget, hwloc_obj_t srcNumaNode = hwloc_get_obj_by_type( topology, HWLOC_OBJ_NUMANODE, - ((struct numa_memory_target_t *)srcMemoryTarget)->physical_id); + ((struct numa_memtarget_t *)srcMemoryTarget)->physical_id); if (!srcNumaNode) { LOG_PERR("Getting HWLOC object by type failed"); return UMF_RESULT_ERROR_INVALID_ARGUMENT; @@ -234,7 +233,7 @@ static umf_result_t query_attribute_value(void *srcMemoryTarget, hwloc_obj_t dstNumaNode = hwloc_get_obj_by_type( topology, HWLOC_OBJ_NUMANODE, - ((struct numa_memory_target_t *)dstMemoryTarget)->physical_id); + ((struct numa_memtarget_t *)dstMemoryTarget)->physical_id); if (!dstNumaNode) { LOG_PERR("Getting HWLOC object by type failed"); return UMF_RESULT_ERROR_INVALID_ARGUMENT; @@ -292,8 +291,8 @@ static umf_result_t numa_get_bandwidth(void *srcMemoryTarget, bandwidth, MEMATTR_TYPE_BANDWIDTH); if (ret) { LOG_ERR("Retrieving bandwidth for initiator node %u to node %u failed.", - ((struct numa_memory_target_t *)srcMemoryTarget)->physical_id, - ((struct numa_memory_target_t *)dstMemoryTarget)->physical_id); + ((struct numa_memtarget_t *)srcMemoryTarget)->physical_id, + ((struct numa_memtarget_t *)dstMemoryTarget)->physical_id); return ret; } @@ -310,15 +309,15 @@ static umf_result_t numa_get_latency(void *srcMemoryTarget, latency, MEMATTR_TYPE_LATENCY); if (ret) { LOG_ERR("Retrieving latency for initiator node %u to node %u failed.", - ((struct numa_memory_target_t *)srcMemoryTarget)->physical_id, - ((struct numa_memory_target_t *)dstMemoryTarget)->physical_id); + ((struct numa_memtarget_t *)srcMemoryTarget)->physical_id, + ((struct numa_memtarget_t *)dstMemoryTarget)->physical_id); return ret; } return UMF_RESULT_SUCCESS; } -struct umf_memory_target_ops_t UMF_MEMORY_TARGET_NUMA_OPS = { +struct umf_memtarget_ops_t UMF_MEMTARGET_NUMA_OPS = { .version = UMF_VERSION_CURRENT, .initialize = numa_initialize, .finalize = numa_finalize, diff --git a/src/memory_targets/memory_target_numa.h b/src/memtargets/memtarget_numa.h similarity index 54% rename from src/memory_targets/memory_target_numa.h rename to src/memtargets/memtarget_numa.h index 843610a2a..c4902d23e 100644 --- a/src/memory_targets/memory_target_numa.h +++ b/src/memtargets/memtarget_numa.h @@ -7,27 +7,27 @@ * */ -#ifndef UMF_MEMORY_TARGET_NUMA_H -#define UMF_MEMORY_TARGET_NUMA_H 1 +#ifndef UMF_MEMTARGET_NUMA_H +#define UMF_MEMTARGET_NUMA_H 1 #include #include -#include "../memory_target.h" -#include "../memory_target_ops.h" +#include "../memtarget.h" +#include "../memtarget_ops.h" #ifdef __cplusplus extern "C" { #endif -struct umf_numa_memory_target_config_t { +struct umf_numa_memtarget_config_t { size_t physical_id; }; -extern struct umf_memory_target_ops_t UMF_MEMORY_TARGET_NUMA_OPS; +extern struct umf_memtarget_ops_t UMF_MEMTARGET_NUMA_OPS; #ifdef __cplusplus } #endif -#endif /* UMF_MEMORY_TARGET_NUMA_H */ +#endif /* UMF_MEMTARGET_NUMA_H */ diff --git a/test/memspaces/memspace_highest_capacity.cpp b/test/memspaces/memspace_highest_capacity.cpp index 3f3e99c76..fdfed91ec 100644 --- a/test/memspaces/memspace_highest_capacity.cpp +++ b/test/memspaces/memspace_highest_capacity.cpp @@ -2,10 +2,10 @@ // Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#include "memory_target_numa.h" #include "memspace_fixtures.hpp" #include "memspace_helpers.hpp" #include "memspace_internal.h" +#include "memtarget_numa.h" #include "numa_helpers.h" #include "test_helpers.h" diff --git a/test/memspaces/memspace_host_all.cpp b/test/memspaces/memspace_host_all.cpp index 8d11aca0b..bf7dbbe8b 100644 --- a/test/memspaces/memspace_host_all.cpp +++ b/test/memspaces/memspace_host_all.cpp @@ -9,10 +9,10 @@ #include -#include "memory_target_numa.h" #include "memspace_fixtures.hpp" #include "memspace_helpers.hpp" #include "memspace_internal.h" +#include "memtarget_numa.h" #include "numa_helpers.h" #include "test_helpers.h" #include "utils_sanitizers.h" @@ -58,8 +58,8 @@ TEST_F(numaNodesTest, memspaceGet) { for (size_t i = 0; i < hMemspace->size; i++) { // NUMA memory target internally casts the config directly into priv. // TODO: Use the memory target API when it becomes available. - struct umf_numa_memory_target_config_t *numaTargetCfg = - (struct umf_numa_memory_target_config_t *)hMemspace->nodes[i]->priv; + struct umf_numa_memtarget_config_t *numaTargetCfg = + (struct umf_numa_memtarget_config_t *)hMemspace->nodes[i]->priv; UT_ASSERT(std::find(nodeIds.begin(), nodeIds.end(), numaTargetCfg->physical_id) != nodeIds.end()); } From dcfc94f5e43540807b5ddd5483deb275a15a2258 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Plewa?= Date: Fri, 19 Jul 2024 17:03:41 +0200 Subject: [PATCH 005/352] Create public header with memtarget declaration Also rename internal header to memtarget_internal.h --- include/umf/memtarget.h | 24 +++++++++++++++++++++++ src/memspace.c | 2 +- src/memspace_internal.h | 2 +- src/memtarget.c | 2 +- src/{memtarget.h => memtarget_internal.h} | 9 ++++----- src/memtarget_ops.h | 3 +-- src/memtargets/memtarget_numa.h | 2 +- 7 files changed, 33 insertions(+), 11 deletions(-) create mode 100644 include/umf/memtarget.h rename src/{memtarget.h => memtarget_internal.h} (91%) diff --git a/include/umf/memtarget.h b/include/umf/memtarget.h new file mode 100644 index 000000000..47f938691 --- /dev/null +++ b/include/umf/memtarget.h @@ -0,0 +1,24 @@ +/* + * + * Copyright (C) 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_MEMTARGET_H +#define UMF_MEMTARGET_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct umf_memtarget_t *umf_memtarget_handle_t; +typedef const struct umf_memtarget_t *umf_const_memtarget_handle_t; + +#ifdef __cplusplus +} +#endif + +#endif /* UMF_MEMTARGET_H */ diff --git a/src/memspace.c b/src/memspace.c index ea4fe1775..e56a69c33 100644 --- a/src/memspace.c +++ b/src/memspace.c @@ -14,7 +14,7 @@ #include "base_alloc_global.h" #include "memspace_internal.h" -#include "memtarget.h" +#include "memtarget_internal.h" #include "memtarget_ops.h" #ifndef NDEBUG diff --git a/src/memspace_internal.h b/src/memspace_internal.h index 7cc62fac2..0cb28b92f 100644 --- a/src/memspace_internal.h +++ b/src/memspace_internal.h @@ -13,7 +13,7 @@ #include #include "base_alloc.h" -#include "memtarget.h" +#include "memtarget_internal.h" #ifdef __cplusplus extern "C" { diff --git a/src/memtarget.c b/src/memtarget.c index cf9b30818..d11e14e2f 100644 --- a/src/memtarget.c +++ b/src/memtarget.c @@ -12,7 +12,7 @@ #include "base_alloc_global.h" #include "libumf.h" -#include "memtarget.h" +#include "memtarget_internal.h" #include "memtarget_ops.h" #include "utils_concurrency.h" diff --git a/src/memtarget.h b/src/memtarget_internal.h similarity index 91% rename from src/memtarget.h rename to src/memtarget_internal.h index 69125c21f..45d547bf7 100644 --- a/src/memtarget.h +++ b/src/memtarget_internal.h @@ -7,10 +7,11 @@ * */ -#ifndef UMF_MEMTARGET_H -#define UMF_MEMTARGET_H 1 +#ifndef UMF_MEMTARGET_INTERNAL_H +#define UMF_MEMTARGET_INTERNAL_H 1 #include +#include #ifdef __cplusplus extern "C" { #endif @@ -23,8 +24,6 @@ typedef struct umf_memtarget_t { void *priv; } umf_memtarget_t; -typedef umf_memtarget_t *umf_memtarget_handle_t; - umf_result_t umfMemoryTargetCreate(const umf_memtarget_ops_t *ops, void *params, umf_memtarget_handle_t *memoryTarget); void umfMemoryTargetDestroy(umf_memtarget_handle_t memoryTarget); @@ -44,4 +43,4 @@ umf_result_t umfMemoryTargetGetLatency(umf_memtarget_handle_t srcMemoryTarget, } #endif -#endif /* UMF_MEMTARGET_H */ +#endif /* UMF_MEMTARGET_INTERNAL_H */ diff --git a/src/memtarget_ops.h b/src/memtarget_ops.h index f53b80524..85555f0ce 100644 --- a/src/memtarget_ops.h +++ b/src/memtarget_ops.h @@ -12,13 +12,12 @@ #include #include +#include #ifdef __cplusplus extern "C" { #endif -typedef struct umf_memtarget_t *umf_memtarget_handle_t; - typedef struct umf_memtarget_ops_t { /// Version of the ops structure. /// Should be initialized using UMF_VERSION_CURRENT diff --git a/src/memtargets/memtarget_numa.h b/src/memtargets/memtarget_numa.h index c4902d23e..2d3e3fd70 100644 --- a/src/memtargets/memtarget_numa.h +++ b/src/memtargets/memtarget_numa.h @@ -13,7 +13,7 @@ #include #include -#include "../memtarget.h" +#include "../memtarget_internal.h" #include "../memtarget_ops.h" #ifdef __cplusplus From 5fe73c0956eb1da4b2427c47806ab551f5c44e22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Mon, 22 Jul 2024 12:09:53 +0200 Subject: [PATCH 006/352] [CMake] Fix helpers module include use full path, to omit potential conflicts in names with other modules, e.g. in other projects, which can use the same module name. --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e84a45097..f3ae1292b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,8 @@ cmake_minimum_required(VERSION 3.14.0 FATAL_ERROR) set(UMF_CMAKE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) list(APPEND CMAKE_MODULE_PATH "${UMF_CMAKE_SOURCE_DIR}/cmake") -include(helpers) +# Use full path of the helpers module (to omit potential conflicts with others) +include(${UMF_CMAKE_SOURCE_DIR}/cmake/helpers.cmake) # We use semver aligned version, set via git tags. We parse git output to # establih the version of UMF to be used in CMake, Win dll's, and within the From a4b0766e7f3e6550a3e62b7c0e060c3f26a7ad4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Plewa?= Date: Mon, 22 Jul 2024 15:12:49 +0200 Subject: [PATCH 007/352] Rename umfMemoryTarget functions --- src/memspace.c | 12 +++++----- src/memspaces/memspace_highest_bandwidth.c | 2 +- src/memspaces/memspace_highest_capacity.c | 2 +- src/memspaces/memspace_lowest_latency.c | 2 +- src/memspaces/memspace_numa.c | 6 ++--- src/memtarget.c | 26 ++++++++++---------- src/memtarget_internal.h | 28 +++++++++++----------- 7 files changed, 39 insertions(+), 39 deletions(-) diff --git a/src/memspace.c b/src/memspace.c index e56a69c33..0dfbfeae3 100644 --- a/src/memspace.c +++ b/src/memspace.c @@ -105,7 +105,7 @@ umfMemoryProviderCreateFromMemspace(umf_const_memspace_handle_t memspace, void umfMemspaceDestroy(umf_memspace_handle_t memspace) { assert(memspace); for (size_t i = 0; i < memspace->size; i++) { - umfMemoryTargetDestroy(memspace->nodes[i]); + umfMemtargetDestroy(memspace->nodes[i]); } umf_ba_global_free(memspace->nodes); @@ -136,7 +136,7 @@ umf_result_t umfMemspaceClone(umf_const_memspace_handle_t hMemspace, umf_result_t ret; for (i = 0; i < clone->size; i++) { - ret = umfMemoryTargetClone(hMemspace->nodes[i], &clone->nodes[i]); + ret = umfMemtargetClone(hMemspace->nodes[i], &clone->nodes[i]); if (ret != UMF_RESULT_SUCCESS) { goto err; } @@ -148,7 +148,7 @@ umf_result_t umfMemspaceClone(umf_const_memspace_handle_t hMemspace, err: while (i != 0) { i--; - umfMemoryTargetDestroy(clone->nodes[i]); + umfMemtargetDestroy(clone->nodes[i]); } umf_ba_global_free(clone->nodes); umf_ba_global_free(clone); @@ -268,8 +268,8 @@ umf_result_t umfMemspaceFilter(umf_const_memspace_handle_t hMemspace, size_t cloneIdx = 0; for (cloneIdx = 0; cloneIdx < newMemspace->size; cloneIdx++) { - ret = umfMemoryTargetClone(uniqueBestNodes[cloneIdx], - &newMemspace->nodes[cloneIdx]); + ret = umfMemtargetClone(uniqueBestNodes[cloneIdx], + &newMemspace->nodes[cloneIdx]); if (ret != UMF_RESULT_SUCCESS) { goto err_free_cloned_nodes; } @@ -283,7 +283,7 @@ umf_result_t umfMemspaceFilter(umf_const_memspace_handle_t hMemspace, err_free_cloned_nodes: while (cloneIdx != 0) { cloneIdx--; - umfMemoryTargetDestroy(newMemspace->nodes[cloneIdx]); + umfMemtargetDestroy(newMemspace->nodes[cloneIdx]); } umf_ba_global_free(newMemspace->nodes); err_free_new_memspace: diff --git a/src/memspaces/memspace_highest_bandwidth.c b/src/memspaces/memspace_highest_bandwidth.c index 9790dbe8b..3fb721717 100644 --- a/src/memspaces/memspace_highest_bandwidth.c +++ b/src/memspaces/memspace_highest_bandwidth.c @@ -28,7 +28,7 @@ static umf_result_t getBestBandwidthTarget(umf_memtarget_handle_t initiator, for (size_t nodeIdx = 0; nodeIdx < numNodes; nodeIdx++) { size_t bandwidth = 0; umf_result_t ret = - umfMemoryTargetGetBandwidth(initiator, nodes[nodeIdx], &bandwidth); + umfMemtargetGetBandwidth(initiator, nodes[nodeIdx], &bandwidth); if (ret) { return ret; } diff --git a/src/memspaces/memspace_highest_capacity.c b/src/memspaces/memspace_highest_capacity.c index 862ae5a8e..2469ba496 100644 --- a/src/memspaces/memspace_highest_capacity.c +++ b/src/memspaces/memspace_highest_capacity.c @@ -34,7 +34,7 @@ umfMemspaceHighestCapacityCreate(umf_memspace_handle_t *hMemspace) { } ret = umfMemspaceSortDesc(highCapacityMemspace, - (umfGetPropertyFn)&umfMemoryTargetGetCapacity); + (umfGetPropertyFn)&umfMemtargetGetCapacity); if (ret != UMF_RESULT_SUCCESS) { return ret; } diff --git a/src/memspaces/memspace_lowest_latency.c b/src/memspaces/memspace_lowest_latency.c index d9c918712..9a34e3f83 100644 --- a/src/memspaces/memspace_lowest_latency.c +++ b/src/memspaces/memspace_lowest_latency.c @@ -28,7 +28,7 @@ static umf_result_t getBestLatencyTarget(umf_memtarget_handle_t initiator, for (size_t nodeIdx = 0; nodeIdx < numNodes; nodeIdx++) { size_t latency = SIZE_MAX; umf_result_t ret = - umfMemoryTargetGetLatency(initiator, nodes[nodeIdx], &latency); + umfMemtargetGetLatency(initiator, nodes[nodeIdx], &latency); if (ret) { return ret; } diff --git a/src/memspaces/memspace_numa.c b/src/memspaces/memspace_numa.c index e4346a4db..306851d7c 100644 --- a/src/memspaces/memspace_numa.c +++ b/src/memspaces/memspace_numa.c @@ -37,8 +37,8 @@ umf_result_t umfMemspaceCreateFromNumaArray(unsigned *nodeIds, size_t numIds, size_t nodeIdx; for (nodeIdx = 0; nodeIdx < numIds; nodeIdx++) { struct umf_numa_memtarget_config_t config = {nodeIds[nodeIdx]}; - ret = umfMemoryTargetCreate(&UMF_MEMTARGET_NUMA_OPS, &config, - &memspace->nodes[nodeIdx]); + ret = umfMemtargetCreate(&UMF_MEMTARGET_NUMA_OPS, &config, + &memspace->nodes[nodeIdx]); if (ret) { goto err_target_create; } @@ -51,7 +51,7 @@ umf_result_t umfMemspaceCreateFromNumaArray(unsigned *nodeIds, size_t numIds, err_target_create: umf_ba_global_free(memspace->nodes); for (size_t i = 0; i < nodeIdx; i++) { - umfMemoryTargetDestroy(memspace->nodes[i]); + umfMemtargetDestroy(memspace->nodes[i]); } err_nodes_alloc: umf_ba_global_free(memspace); diff --git a/src/memtarget.c b/src/memtarget.c index d11e14e2f..33c737ae0 100644 --- a/src/memtarget.c +++ b/src/memtarget.c @@ -16,8 +16,8 @@ #include "memtarget_ops.h" #include "utils_concurrency.h" -umf_result_t umfMemoryTargetCreate(const umf_memtarget_ops_t *ops, void *params, - umf_memtarget_handle_t *memoryTarget) { +umf_result_t umfMemtargetCreate(const umf_memtarget_ops_t *ops, void *params, + umf_memtarget_handle_t *memoryTarget) { libumfInit(); if (!ops || !memoryTarget) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; @@ -47,14 +47,14 @@ umf_result_t umfMemoryTargetCreate(const umf_memtarget_ops_t *ops, void *params, return UMF_RESULT_SUCCESS; } -void umfMemoryTargetDestroy(umf_memtarget_handle_t memoryTarget) { +void umfMemtargetDestroy(umf_memtarget_handle_t memoryTarget) { assert(memoryTarget); memoryTarget->ops->finalize(memoryTarget->priv); umf_ba_global_free(memoryTarget); } -umf_result_t umfMemoryTargetClone(umf_memtarget_handle_t memoryTarget, - umf_memtarget_handle_t *outHandle) { +umf_result_t umfMemtargetClone(umf_memtarget_handle_t memoryTarget, + umf_memtarget_handle_t *outHandle) { assert(memoryTarget); assert(outHandle); @@ -76,8 +76,8 @@ umf_result_t umfMemoryTargetClone(umf_memtarget_handle_t memoryTarget, return UMF_RESULT_SUCCESS; } -umf_result_t umfMemoryTargetGetCapacity(umf_memtarget_handle_t memoryTarget, - size_t *capacity) { +umf_result_t umfMemtargetGetCapacity(umf_memtarget_handle_t memoryTarget, + size_t *capacity) { if (!memoryTarget || !capacity) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; } @@ -85,9 +85,9 @@ umf_result_t umfMemoryTargetGetCapacity(umf_memtarget_handle_t memoryTarget, return memoryTarget->ops->get_capacity(memoryTarget->priv, capacity); } -umf_result_t umfMemoryTargetGetBandwidth(umf_memtarget_handle_t srcMemoryTarget, - umf_memtarget_handle_t dstMemoryTarget, - size_t *bandwidth) { +umf_result_t umfMemtargetGetBandwidth(umf_memtarget_handle_t srcMemoryTarget, + umf_memtarget_handle_t dstMemoryTarget, + size_t *bandwidth) { if (!srcMemoryTarget || !dstMemoryTarget || !bandwidth) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; } @@ -96,9 +96,9 @@ umf_result_t umfMemoryTargetGetBandwidth(umf_memtarget_handle_t srcMemoryTarget, srcMemoryTarget->priv, dstMemoryTarget->priv, bandwidth); } -umf_result_t umfMemoryTargetGetLatency(umf_memtarget_handle_t srcMemoryTarget, - umf_memtarget_handle_t dstMemoryTarget, - size_t *latency) { +umf_result_t umfMemtargetGetLatency(umf_memtarget_handle_t srcMemoryTarget, + umf_memtarget_handle_t dstMemoryTarget, + size_t *latency) { if (!srcMemoryTarget || !dstMemoryTarget || !latency) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; } diff --git a/src/memtarget_internal.h b/src/memtarget_internal.h index 45d547bf7..bad309723 100644 --- a/src/memtarget_internal.h +++ b/src/memtarget_internal.h @@ -24,20 +24,20 @@ typedef struct umf_memtarget_t { void *priv; } umf_memtarget_t; -umf_result_t umfMemoryTargetCreate(const umf_memtarget_ops_t *ops, void *params, - umf_memtarget_handle_t *memoryTarget); -void umfMemoryTargetDestroy(umf_memtarget_handle_t memoryTarget); - -umf_result_t umfMemoryTargetClone(umf_memtarget_handle_t memoryTarget, - umf_memtarget_handle_t *outHandle); -umf_result_t umfMemoryTargetGetCapacity(umf_memtarget_handle_t memoryTarget, - size_t *capacity); -umf_result_t umfMemoryTargetGetBandwidth(umf_memtarget_handle_t srcMemoryTarget, - umf_memtarget_handle_t dstMemoryTarget, - size_t *bandwidth); -umf_result_t umfMemoryTargetGetLatency(umf_memtarget_handle_t srcMemoryTarget, - umf_memtarget_handle_t dstMemoryTarget, - size_t *latency); +umf_result_t umfMemtargetCreate(const umf_memtarget_ops_t *ops, void *params, + umf_memtarget_handle_t *memoryTarget); +void umfMemtargetDestroy(umf_memtarget_handle_t memoryTarget); + +umf_result_t umfMemtargetClone(umf_memtarget_handle_t memoryTarget, + umf_memtarget_handle_t *outHandle); +umf_result_t umfMemtargetGetCapacity(umf_memtarget_handle_t memoryTarget, + size_t *capacity); +umf_result_t umfMemtargetGetBandwidth(umf_memtarget_handle_t srcMemoryTarget, + umf_memtarget_handle_t dstMemoryTarget, + size_t *bandwidth); +umf_result_t umfMemtargetGetLatency(umf_memtarget_handle_t srcMemoryTarget, + umf_memtarget_handle_t dstMemoryTarget, + size_t *latency); #ifdef __cplusplus } From 14c51986f8afe899526a6a521d745df8bfb6d263 Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 11 Jul 2024 16:04:49 +0200 Subject: [PATCH 008/352] Fix asan's user-poisoning flags bug It add utils_annotate_memory_defined() (which does unpoison on memory region) after all mmap(). This should be unnecessary change but pairs of mmap/munmap do not reset asan's user-poisoning flags, leading to invalid error reports. This bug is describe here - 81619: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81619 --- .github/workflows/sanitizers.yml | 4 +--- src/base_alloc/base_alloc_global.c | 2 -- src/base_alloc/base_alloc_linux.c | 9 +++++++-- src/provider/provider_os_memory_posix.c | 14 ++++++++++++-- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/.github/workflows/sanitizers.yml b/.github/workflows/sanitizers.yml index 06ad492eb..4b4b37aaf 100644 --- a/.github/workflows/sanitizers.yml +++ b/.github/workflows/sanitizers.yml @@ -72,9 +72,7 @@ jobs: working-directory: ${{env.BUILD_DIR}} run: > ${{ matrix.compiler.cxx == 'icpx' && '. /opt/intel/oneapi/setvars.sh &&' || ''}} - GTEST_FILTER="-*umfProviderTest.alloc_page64_align_0*" ctest --output-on-failure - # TO DO: fix umf-provider_os_memory test for sanitizers - # issue 581: https://github.com/oneapi-src/unified-memory-framework/issues/581 + ctest --output-on-failure windows-build: name: cl and clang-cl on Windows diff --git a/src/base_alloc/base_alloc_global.c b/src/base_alloc/base_alloc_global.c index 003e43a03..b5660d440 100644 --- a/src/base_alloc/base_alloc_global.c +++ b/src/base_alloc/base_alloc_global.c @@ -195,14 +195,12 @@ void umf_ba_global_free(void *ptr) { int ac_index = size_to_idx(total_size); if (ac_index >= NUM_ALLOCATION_CLASSES) { - utils_annotate_memory_inaccessible(ptr, total_size); ba_os_free(ptr, total_size); return; } if (!BASE_ALLOC.ac[ac_index]) { // if creating ac failed, memory must have been allocated by os - utils_annotate_memory_inaccessible(ptr, total_size); ba_os_free(ptr, total_size); return; } diff --git a/src/base_alloc/base_alloc_linux.c b/src/base_alloc/base_alloc_linux.c index 8d07d5ab6..3e5456b2c 100644 --- a/src/base_alloc/base_alloc_linux.c +++ b/src/base_alloc/base_alloc_linux.c @@ -19,8 +19,13 @@ static UTIL_ONCE_FLAG Page_size_is_initialized = UTIL_ONCE_FLAG_INIT; static size_t Page_size; void *ba_os_alloc(size_t size) { - return mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, - -1, 0); + void *ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + // this should be unnecessary but pairs of mmap/munmap do not reset + // asan's user-poisoning flags, leading to invalid error reports + // Bug 81619: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81619 + utils_annotate_memory_defined(ptr, size); + return ptr; } void ba_os_free(void *ptr, size_t size) { diff --git a/src/provider/provider_os_memory_posix.c b/src/provider/provider_os_memory_posix.c index f7040c3f0..9308f6a18 100644 --- a/src/provider/provider_os_memory_posix.c +++ b/src/provider/provider_os_memory_posix.c @@ -16,6 +16,7 @@ #include "provider_os_memory_internal.h" #include "utils_log.h" +#include "utils_sanitizers.h" // maximum value of the off_t type #define OFF_T_MAX \ @@ -74,11 +75,20 @@ void *os_mmap(void *hint_addr, size_t length, int prot, int flag, int fd, if (ptr == MAP_FAILED) { return NULL; } - + // this should be unnecessary but pairs of mmap/munmap do not reset + // asan's user-poisoning flags, leading to invalid error reports + // Bug 81619: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81619 + utils_annotate_memory_defined(ptr, length); return ptr; } -int os_munmap(void *addr, size_t length) { return munmap(addr, length); } +int os_munmap(void *addr, size_t length) { + // this should be unnecessary but pairs of mmap/munmap do not reset + // asan's user-poisoning flags, leading to invalid error reports + // Bug 81619: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81619 + utils_annotate_memory_defined(addr, length); + return munmap(addr, length); +} size_t os_get_page_size(void) { return sysconf(_SC_PAGE_SIZE); } From 6395af532d3f5582a4c0d238512a955b15ee709c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Plewa?= Date: Tue, 23 Jul 2024 17:56:43 +0200 Subject: [PATCH 009/352] add test file and docs for memtarget --- scripts/docs_config/api.rst | 9 +++++++++ test/CMakeLists.txt | 4 ++++ test/memspaces/memtarget.cpp | 9 +++++++++ 3 files changed, 22 insertions(+) create mode 100644 test/memspaces/memtarget.cpp diff --git a/scripts/docs_config/api.rst b/scripts/docs_config/api.rst index 1233f59f7..ea0912785 100644 --- a/scripts/docs_config/api.rst +++ b/scripts/docs_config/api.rst @@ -116,6 +116,15 @@ Mempolicy .. doxygenfile:: mempolicy.h :sections: define enum typedef func +Memtarget +========================================== + +TODO: Add general information about memtarges. + +Memtarget +------------------------------------------ +.. doxygenfile:: memtarget.h + :sections: define enum typedef func Inter-Process Communication ========================================== diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 890ac5572..78c3e9c2b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -215,6 +215,10 @@ if(LINUX) # OS-specific functions are implemented only for Linux now NAME mempolicy SRCS memspaces/mempolicy.cpp LIBS ${LIBNUMA_LIBRARIES}) + add_umf_test( + NAME memtarget + SRCS memspaces/memtarget.cpp + LIBS ${LIBNUMA_LIBRARIES}) if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND UMF_BUILD_FUZZTESTS) add_subdirectory(fuzz) endif() diff --git a/test/memspaces/memtarget.cpp b/test/memspaces/memtarget.cpp new file mode 100644 index 000000000..11eb10135 --- /dev/null +++ b/test/memspaces/memtarget.cpp @@ -0,0 +1,9 @@ +// Copyright (C) 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 "memspace_helpers.hpp" +#include +#include + +using umf_test::test; From f4b768aee5aa53d4afc461a936992722462e59b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Plewa?= Date: Tue, 23 Jul 2024 17:35:34 +0200 Subject: [PATCH 010/352] Add umfMemspaceMemtarget[Num|Get] --- include/umf/memspace.h | 16 ++++++++++++++++ src/libumf.def.in | 2 ++ src/libumf.map | 2 ++ src/memspace.c | 16 ++++++++++++++++ test/memspaces/memspace_numa.cpp | 23 ++++++++++++++++++++++- 5 files changed, 58 insertions(+), 1 deletion(-) diff --git a/include/umf/memspace.h b/include/umf/memspace.h index 2d2d77728..10cf0417d 100644 --- a/include/umf/memspace.h +++ b/include/umf/memspace.h @@ -14,6 +14,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -84,6 +85,21 @@ umf_const_memspace_handle_t umfMemspaceHighestBandwidthGet(void); /// umf_const_memspace_handle_t umfMemspaceLowestLatencyGet(void); +/// \brief Returns number of memory targets in memspace. +/// \param hMemspace handle to memspace +/// \return number of memory targets in memspace +/// +size_t umfMemspaceMemtargetNum(umf_const_memspace_handle_t hMemspace); + +/// \brief Returns memory target by index. +/// \param hMemspace handle to memspace +/// \param targetNum index of the memory target +/// \return memory target handle on success or NULL on invalid input. +/// +umf_const_memtarget_handle_t +umfMemspaceMemtargetGet(umf_const_memspace_handle_t hMemspace, + unsigned targetNum); + #ifdef __cplusplus } #endif diff --git a/src/libumf.def.in b/src/libumf.def.in index 8ee99e024..f62f4f6dc 100644 --- a/src/libumf.def.in +++ b/src/libumf.def.in @@ -41,6 +41,8 @@ EXPORTS umfMempolicySetCustomSplitPartitions umfMempolicySetInterleavePartSize umfMemspaceDestroy + umfMemspaceMemtargetNum + umfMemspaceMemtargetGet umfOpenIPCHandle umfOsMemoryProviderOps umfPoolAlignedMalloc diff --git a/src/libumf.map b/src/libumf.map index cb09cdb94..4f4df92ce 100644 --- a/src/libumf.map +++ b/src/libumf.map @@ -37,6 +37,8 @@ UMF_1.0 { umfMempolicySetInterleavePartSize; umfMemspaceCreateFromNumaArray; umfMemspaceDestroy; + umfMemspaceMemtargetNum; + umfMemspaceMemtargetGet; umfMemspaceHighestBandwidthGet; umfMemspaceHighestCapacityGet; umfMemspaceHostAllGet; diff --git a/src/memspace.c b/src/memspace.c index 0dfbfeae3..01e20e617 100644 --- a/src/memspace.c +++ b/src/memspace.c @@ -292,3 +292,19 @@ umf_result_t umfMemspaceFilter(umf_const_memspace_handle_t hMemspace, umf_ba_global_free(uniqueBestNodes); return ret; } + +size_t umfMemspaceMemtargetNum(umf_const_memspace_handle_t hMemspace) { + if (!hMemspace) { + return 0; + } + return hMemspace->size; +} + +umf_const_memtarget_handle_t +umfMemspaceMemtargetGet(umf_const_memspace_handle_t hMemspace, + unsigned targetNum) { + if (!hMemspace || targetNum >= hMemspace->size) { + return NULL; + } + return hMemspace->nodes[targetNum]; +} diff --git a/test/memspaces/memspace_numa.cpp b/test/memspaces/memspace_numa.cpp index b50eceac9..c8485fadc 100644 --- a/test/memspaces/memspace_numa.cpp +++ b/test/memspaces/memspace_numa.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2023 Intel Corporation +// 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 @@ -7,6 +7,7 @@ #include "memspace_helpers.hpp" #include "memspace_internal.h" +#include #include struct memspaceNumaTest : ::numaNodesTest { @@ -56,6 +57,10 @@ TEST_F(numaNodesTest, createDestroy) { nodeIds.data(), nodeIds.size(), &hMemspace); ASSERT_EQ(ret, UMF_RESULT_SUCCESS); ASSERT_NE(hMemspace, nullptr); + EXPECT_EQ(umfMemspaceMemtargetNum(hMemspace), nodeIds.size()); + for (size_t i = 0; i < umfMemspaceMemtargetNum(hMemspace); ++i) { + EXPECT_NE(umfMemspaceMemtargetGet(hMemspace, i), nullptr); + } umfMemspaceDestroy(hMemspace); } @@ -91,6 +96,22 @@ TEST_F(memspaceNumaTest, providerFromNumaMemspace) { umfMemoryProviderDestroy(hProvider); } +TEST_F(numaNodesTest, memtargetsInvalid) { + umf_memspace_handle_t hMemspace = nullptr; + EXPECT_EQ(umfMemspaceMemtargetNum(nullptr), 0); + EXPECT_EQ(umfMemspaceMemtargetGet(nullptr, 0), nullptr); + + umf_result_t ret = umfMemspaceCreateFromNumaArray( + nodeIds.data(), nodeIds.size(), &hMemspace); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(hMemspace, nullptr); + + ASSERT_EQ(umfMemspaceMemtargetNum(hMemspace), nodeIds.size()); + EXPECT_EQ(umfMemspaceMemtargetGet(hMemspace, nodeIds.size()), nullptr); + + umfMemspaceDestroy(hMemspace); +} + TEST_F(memspaceNumaProviderTest, allocFree) { void *ptr = nullptr; size_t size = SIZE_4K; From 3fe23a36dbc4b5cea4ad1378d13222f7adebdc3d Mon Sep 17 00:00:00 2001 From: Patryk Kaminski Date: Wed, 24 Jul 2024 11:13:13 +0200 Subject: [PATCH 011/352] Disable memory poisoning in DisjointPool ASan throws an error whenever the memory poison is called for the memory allocated on GPU: "AddressSanitizer: CHECK failed: asan_mapping.h:359 "((AddrIsInMem(p))) != (0)" (0x0, 0x0)". This commit disables poisoning. --- src/pool/pool_disjoint.cpp | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/src/pool/pool_disjoint.cpp b/src/pool/pool_disjoint.cpp index d48d430ce..a1375a3ee 100644 --- a/src/pool/pool_disjoint.cpp +++ b/src/pool/pool_disjoint.cpp @@ -31,6 +31,27 @@ #include "utils_math.h" #include "utils_sanitizers.h" +// Temporary solution for disabling memory poisoning. This is needed because +// AddressSanitizer does not support memory poisoning for GPU allocations. +// More info: https://github.com/oneapi-src/unified-memory-framework/issues/634 +#ifndef POISON_MEMORY +#define POISON_MEMORY 0 +#endif + +static inline void annotate_memory_inaccessible([[maybe_unused]] void *ptr, + [[maybe_unused]] size_t size) { +#ifdef POISON_MEMORY + utils_annotate_memory_inaccessible(ptr, size); +#endif +} + +static inline void annotate_memory_undefined([[maybe_unused]] void *ptr, + [[maybe_unused]] size_t size) { +#ifdef POISON_MEMORY + utils_annotate_memory_undefined(ptr, size); +#endif +} + typedef struct umf_disjoint_pool_shared_limits_t { size_t MaxSize; std::atomic TotalSize; @@ -400,7 +421,7 @@ static void *memoryProviderAlloc(umf_memory_provider_handle_t hProvider, if (ret != UMF_RESULT_SUCCESS) { throw MemoryProviderError{ret}; } - utils_annotate_memory_inaccessible(ptr, size); + annotate_memory_inaccessible(ptr, size); return ptr; } @@ -822,7 +843,7 @@ void *DisjointPool::AllocImpl::allocate(size_t Size, bool &FromPool) try { FromPool = false; if (Size > getParams().MaxPoolableSize) { Ptr = memoryProviderAlloc(getMemHandle(), Size); - utils_annotate_memory_undefined(Ptr, Size); + annotate_memory_undefined(Ptr, Size); return Ptr; } @@ -839,7 +860,7 @@ void *DisjointPool::AllocImpl::allocate(size_t Size, bool &FromPool) try { } VALGRIND_DO_MEMPOOL_ALLOC(this, Ptr, Size); - utils_annotate_memory_undefined(Ptr, Bucket.getSize()); + annotate_memory_undefined(Ptr, Bucket.getSize()); return Ptr; } catch (MemoryProviderError &e) { @@ -877,7 +898,7 @@ void *DisjointPool::AllocImpl::allocate(size_t Size, size_t Alignment, FromPool = false; if (AlignedSize > getParams().MaxPoolableSize) { Ptr = memoryProviderAlloc(getMemHandle(), Size, Alignment); - utils_annotate_memory_undefined(Ptr, Size); + annotate_memory_undefined(Ptr, Size); return Ptr; } @@ -894,8 +915,7 @@ void *DisjointPool::AllocImpl::allocate(size_t Size, size_t Alignment, } VALGRIND_DO_MEMPOOL_ALLOC(this, AlignPtrUp(Ptr, Alignment), Size); - utils_annotate_memory_undefined(AlignPtrUp(Ptr, Alignment), Size); - + annotate_memory_undefined(AlignPtrUp(Ptr, Alignment), Size); return AlignPtrUp(Ptr, Alignment); } catch (MemoryProviderError &e) { umf::getPoolLastStatusRef() = e.code; @@ -962,8 +982,7 @@ void DisjointPool::AllocImpl::deallocate(void *Ptr, bool &ToPool) { } VALGRIND_DO_MEMPOOL_FREE(this, Ptr); - utils_annotate_memory_inaccessible(Ptr, Bucket.getSize()); - + annotate_memory_inaccessible(Ptr, Bucket.getSize()); if (Bucket.getSize() <= Bucket.ChunkCutOff()) { Bucket.freeChunk(Ptr, Slab, ToPool); } else { From 166709ed1b628cebb556d49890ec3ba6ee65c4b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Plewa?= Date: Tue, 23 Jul 2024 18:43:10 +0200 Subject: [PATCH 012/352] add memtargetGetType --- include/umf/memtarget.h | 14 ++++++++++++++ src/libumf.def.in | 1 + src/libumf.map | 1 + src/memtarget.c | 9 +++++++++ src/memtarget_ops.h | 2 ++ src/memtargets/memtarget_numa.c | 10 ++++++++++ test/memspaces/memtarget.cpp | 30 ++++++++++++++++++++++++++++++ 7 files changed, 67 insertions(+) diff --git a/include/umf/memtarget.h b/include/umf/memtarget.h index 47f938691..2a7850015 100644 --- a/include/umf/memtarget.h +++ b/include/umf/memtarget.h @@ -10,6 +10,8 @@ #ifndef UMF_MEMTARGET_H #define UMF_MEMTARGET_H 1 +#include + #ifdef __cplusplus extern "C" { #endif @@ -17,6 +19,18 @@ extern "C" { typedef struct umf_memtarget_t *umf_memtarget_handle_t; typedef const struct umf_memtarget_t *umf_const_memtarget_handle_t; +typedef enum umf_memtarget_type_t { + UMF_MEMTARGET_TYPE_UNKNOWN = 0, + UMF_MEMTARGET_TYPE_NUMA = 1, +} umf_memtarget_type_t; + +/// \brief Gets the type of the memory target. +/// \param hMemtarget handle to the memory target +/// \param type [out] type of the memory target +/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfMemtargetGetType(umf_const_memtarget_handle_t hMemtarget, + umf_memtarget_type_t *type); + #ifdef __cplusplus } #endif diff --git a/src/libumf.def.in b/src/libumf.def.in index f62f4f6dc..00a1995ae 100644 --- a/src/libumf.def.in +++ b/src/libumf.def.in @@ -43,6 +43,7 @@ EXPORTS umfMemspaceDestroy umfMemspaceMemtargetNum umfMemspaceMemtargetGet + umfMemtargetGetType umfOpenIPCHandle umfOsMemoryProviderOps umfPoolAlignedMalloc diff --git a/src/libumf.map b/src/libumf.map index 4f4df92ce..2dc6956c9 100644 --- a/src/libumf.map +++ b/src/libumf.map @@ -43,6 +43,7 @@ UMF_1.0 { umfMemspaceHighestCapacityGet; umfMemspaceHostAllGet; umfMemspaceLowestLatencyGet; + umfMemtargetGetType; umfOpenIPCHandle; umfOsMemoryProviderOps; umfPoolAlignedMalloc; diff --git a/src/memtarget.c b/src/memtarget.c index 33c737ae0..4c851a772 100644 --- a/src/memtarget.c +++ b/src/memtarget.c @@ -106,3 +106,12 @@ umf_result_t umfMemtargetGetLatency(umf_memtarget_handle_t srcMemoryTarget, return srcMemoryTarget->ops->get_latency(srcMemoryTarget->priv, dstMemoryTarget->priv, latency); } + +umf_result_t umfMemtargetGetType(umf_const_memtarget_handle_t memoryTarget, + umf_memtarget_type_t *type) { + if (!memoryTarget || !type) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + return memoryTarget->ops->get_type(memoryTarget->priv, type); +} diff --git a/src/memtarget_ops.h b/src/memtarget_ops.h index 85555f0ce..08936fcde 100644 --- a/src/memtarget_ops.h +++ b/src/memtarget_ops.h @@ -43,6 +43,8 @@ typedef struct umf_memtarget_ops_t { size_t *bandwidth); umf_result_t (*get_latency)(void *srcMemoryTarget, void *dstMemoryTarget, size_t *latency); + + umf_result_t (*get_type)(void *memoryTarget, umf_memtarget_type_t *type); } umf_memtarget_ops_t; #ifdef __cplusplus diff --git a/src/memtargets/memtarget_numa.c b/src/memtargets/memtarget_numa.c index 553c780bc..32f9bf448 100644 --- a/src/memtargets/memtarget_numa.c +++ b/src/memtargets/memtarget_numa.c @@ -317,6 +317,15 @@ static umf_result_t numa_get_latency(void *srcMemoryTarget, return UMF_RESULT_SUCCESS; } +static umf_result_t numa_get_type(void *memTarget, umf_memtarget_type_t *type) { + if (!memTarget || !type) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + *type = UMF_MEMTARGET_TYPE_NUMA; + return UMF_RESULT_SUCCESS; +} + struct umf_memtarget_ops_t UMF_MEMTARGET_NUMA_OPS = { .version = UMF_VERSION_CURRENT, .initialize = numa_initialize, @@ -326,5 +335,6 @@ struct umf_memtarget_ops_t UMF_MEMTARGET_NUMA_OPS = { .get_capacity = numa_get_capacity, .get_bandwidth = numa_get_bandwidth, .get_latency = numa_get_latency, + .get_type = numa_get_type, .memory_provider_create_from_memspace = numa_memory_provider_create_from_memspace}; diff --git a/test/memspaces/memtarget.cpp b/test/memspaces/memtarget.cpp index 11eb10135..84001a705 100644 --- a/test/memspaces/memtarget.cpp +++ b/test/memspaces/memtarget.cpp @@ -3,7 +3,37 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include "memspace_helpers.hpp" + +#include #include #include using umf_test::test; + +TEST_F(test, memTargetNuma) { + auto memspace = umfMemspaceHostAllGet(); + ASSERT_NE(memspace, nullptr); + + for (size_t i = 0; i < umfMemspaceMemtargetNum(memspace); i++) { + auto hTarget = umfMemspaceMemtargetGet(memspace, i); + ASSERT_NE(hTarget, nullptr); + umf_memtarget_type_t type; + auto ret = umfMemtargetGetType(hTarget, &type); + EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + EXPECT_EQ(type, UMF_MEMTARGET_TYPE_NUMA); + } +} + +TEST_F(test, memTargetInvalid) { + auto memspace = umfMemspaceHostAllGet(); + ASSERT_NE(memspace, nullptr); + umf_memtarget_type_t type; + auto ret = umfMemtargetGetType(NULL, &type); + EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + ret = umfMemtargetGetType(NULL, NULL); + EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + auto hTarget = umfMemspaceMemtargetGet(memspace, 0); + ASSERT_NE(hTarget, nullptr); + ret = umfMemtargetGetType(hTarget, NULL); + EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} From b6d5f2cb3367c5937620259ca4aea5210ffd5695 Mon Sep 17 00:00:00 2001 From: Krzysztof Swiecicki Date: Thu, 25 Jul 2024 09:05:10 +0000 Subject: [PATCH 013/352] Fix disjoint pool memory poison macro The poison memory macro definition is always defined, so an #ifdef check is insufficient. --- src/pool/pool_disjoint.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pool/pool_disjoint.cpp b/src/pool/pool_disjoint.cpp index a1375a3ee..edb5fc649 100644 --- a/src/pool/pool_disjoint.cpp +++ b/src/pool/pool_disjoint.cpp @@ -40,14 +40,14 @@ static inline void annotate_memory_inaccessible([[maybe_unused]] void *ptr, [[maybe_unused]] size_t size) { -#ifdef POISON_MEMORY +#if (POISON_MEMORY != 0) utils_annotate_memory_inaccessible(ptr, size); #endif } static inline void annotate_memory_undefined([[maybe_unused]] void *ptr, [[maybe_unused]] size_t size) { -#ifdef POISON_MEMORY +#if (POISON_MEMORY != 0) utils_annotate_memory_undefined(ptr, size); #endif } From 13e801ecb061d97013a409981e8326ec438d1545 Mon Sep 17 00:00:00 2001 From: Krzysztof Swiecicki Date: Fri, 26 Jul 2024 09:13:55 +0000 Subject: [PATCH 014/352] Add default switch warning suppression --- cmake/helpers.cmake | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/cmake/helpers.cmake b/cmake/helpers.cmake index bb9b703d8..8899077ef 100644 --- a/cmake/helpers.cmake +++ b/cmake/helpers.cmake @@ -176,7 +176,27 @@ function(get_program_version_major_minor name ret) PARENT_SCOPE) endfunction() +# Checks compiler for given ${flag}, stores the output in C_HAS_${flag} and +# CXX_HAS_${flag} (if compiler supports C++) +function(check_compilers_flag flag) + check_c_compiler_flag("${flag}" "C_HAS_${flag}") + if(CMAKE_CXX_COMPILE_FEATURES) + check_cxx_compiler_flag("${flag}" "CXX_HAS_${flag}") + endif() +endfunction() + +function(check_add_target_compile_options target) + foreach(option ${ARGN}) + check_compilers_flag(${option}) + if(C_HAS_${option} AND CXX_HAS_${option}) + target_compile_options(${target} PRIVATE ${option}) + endif() + endforeach() +endfunction() + function(add_umf_target_compile_options name) + check_add_target_compile_options(${name} "-Wno-covered-switch-default") + if(NOT MSVC) target_compile_options( ${name} From ebf618f57e25badd0cd609f2eb140d9dee443386 Mon Sep 17 00:00:00 2001 From: Krzysztof Swiecicki Date: Fri, 26 Jul 2024 09:14:33 +0000 Subject: [PATCH 015/352] Remove werror compile option from UMF targets --- cmake/helpers.cmake | 1 - 1 file changed, 1 deletion(-) diff --git a/cmake/helpers.cmake b/cmake/helpers.cmake index 8899077ef..29cd774b6 100644 --- a/cmake/helpers.cmake +++ b/cmake/helpers.cmake @@ -203,7 +203,6 @@ function(add_umf_target_compile_options name) PRIVATE -fPIC -Wall -Wextra - -Werror -Wpedantic -Wempty-body -Wunused-parameter From 7c4959b4a487b2fadb51f211478a685038c8dde4 Mon Sep 17 00:00:00 2001 From: Krzysztof Swiecicki Date: Fri, 26 Jul 2024 13:34:20 +0000 Subject: [PATCH 016/352] Remove WX MSVC compiler option --- cmake/helpers.cmake | 1 - 1 file changed, 1 deletion(-) diff --git a/cmake/helpers.cmake b/cmake/helpers.cmake index 29cd774b6..0e226d679 100644 --- a/cmake/helpers.cmake +++ b/cmake/helpers.cmake @@ -232,7 +232,6 @@ function(add_umf_target_compile_options name) /analyze /DYNAMICBASE /W4 - /WX /Gy /GS # disable warning 6326: Potential comparison of a constant From 60abad6bd77fbd289161a299bbc9ac45f58ff6d6 Mon Sep 17 00:00:00 2001 From: Igor Chorazewicz Date: Fri, 26 Jul 2024 19:49:41 +0000 Subject: [PATCH 017/352] Add option to disable hwloc --- .github/workflows/basic.yml | 11 +++++- CMakeLists.txt | 27 ++++++++++----- examples/CMakeLists.txt | 8 ++--- src/CMakeLists.txt | 43 +++++++++++++++++------ src/libumf.c | 6 ++-- test/CMakeLists.txt | 68 +++++++++++++++++++++---------------- 6 files changed, 108 insertions(+), 55 deletions(-) diff --git a/.github/workflows/basic.yml b/.github/workflows/basic.yml index b5ce1e948..2842191e4 100644 --- a/.github/workflows/basic.yml +++ b/.github/workflows/basic.yml @@ -23,6 +23,7 @@ jobs: shared_library: ['OFF'] level_zero_provider: ['ON'] install_tbb: ['ON'] + disable_hwloc: ['OFF'] include: - os: 'ubuntu-20.04' build_type: Release @@ -69,6 +70,13 @@ jobs: shared_library: 'ON' level_zero_provider: 'ON' install_tbb: 'OFF' + - os: 'ubuntu-22.04' + build_type: Release + compiler: {c: gcc, cxx: g++} + shared_library: 'ON' + level_zero_provider: 'ON' + install_tbb: 'ON' + disable_hwloc: 'ON' runs-on: ${{matrix.os}} steps: @@ -122,6 +130,7 @@ jobs: -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON -DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON -DUMF_TESTS_FAIL_ON_SKIP=ON + -DUMF_DISABLE_HWLOC=${{matrix.disable_hwloc}} - name: Build UMF run: cmake --build ${{env.BUILD_DIR}} -j $(nproc) @@ -144,7 +153,7 @@ jobs: --build-type ${{matrix.build_type}} --disjoint-pool --jemalloc-pool - ${{ matrix.install_tbb == 'ON' && '--proxy' || '' }} + ${{ matrix.install_tbb == 'ON' && matrix.disable_hwloc != 'ON' && '--proxy' || '' }} --umf-version ${{env.UMF_VERSION}} ${{ matrix.shared_library == 'ON' && '--shared-library' || '' }} diff --git a/CMakeLists.txt b/CMakeLists.txt index f3ae1292b..6005f9d92 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,6 +61,10 @@ option(USE_TSAN "Enable ThreadSanitizer checks" OFF) option(USE_MSAN "Enable MemorySanitizer checks" OFF) option(USE_VALGRIND "Enable Valgrind instrumentation" OFF) option(USE_GCOV "Enable gcov support" OFF) +option( + UMF_DISABLE_HWLOC + "Disable features that requires hwloc (OS provider, memory targets, topolgy discovery)" + OFF) # set UMF_PROXY_LIB_BASED_ON_POOL to one of: SCALABLE or JEMALLOC set(KNOWN_PROXY_LIB_POOLS SCALABLE JEMALLOC) @@ -95,14 +99,17 @@ else() endif() if(NOT UMF_LINK_HWLOC_STATICALLY) - pkg_check_modules(LIBHWLOC hwloc>=2.3.0) - if(NOT LIBHWLOC_FOUND) - find_package(LIBHWLOC 2.3.0 REQUIRED hwloc) + if(NOT UMF_DISABLE_HWLOC) + pkg_check_modules(LIBHWLOC hwloc>=2.3.0) + if(NOT LIBHWLOC_FOUND) + find_package(LIBHWLOC 2.3.0 REQUIRED hwloc) + endif() + + # add PATH to DLL on Windows + set(DLL_PATH_LIST + "${DLL_PATH_LIST};PATH=path_list_append:${LIBHWLOC_LIBRARY_DIRS}/../bin" + ) endif() - # add PATH to DLL on Windows - set(DLL_PATH_LIST - "${DLL_PATH_LIST};PATH=path_list_append:${LIBHWLOC_LIBRARY_DIRS}/../bin" - ) else() if(NOT WINDOWS) message(FATAL_ERROR "hwloc can be statically linked only on Windows") @@ -329,7 +336,11 @@ if(UMF_BUILD_BENCHMARKS) endif() if(UMF_BUILD_EXAMPLES) - add_subdirectory(examples) + if(NOT UMF_DISABLE_HWLOC) + add_subdirectory(examples) + else() + message(WARNING "Examples cannot be build - hwloc disabled") + endif() endif() # Conditional configuration for Level Zero provider diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 7656a9246..d06e51755 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -18,7 +18,7 @@ set(EXAMPLE_NAME umf_example_basic) add_umf_executable( NAME ${EXAMPLE_NAME} SRCS basic/basic.c - LIBS umf hwloc) + LIBS umf ${LIBHWLOC_LIBRARIES}) target_include_directories( ${EXAMPLE_NAME} PRIVATE ${UMF_CMAKE_SOURCE_DIR}/src/utils @@ -172,7 +172,7 @@ if(LINUX) add_umf_executable( NAME ${EXAMPLE_NAME} SRCS memspace/memspace_numa.c - LIBS umf hwloc numa) + LIBS umf ${LIBHWLOC_LIBRARIES} numa) target_include_directories( ${EXAMPLE_NAME} PRIVATE ${UMF_CMAKE_SOURCE_DIR}/src/utils @@ -190,7 +190,7 @@ if(LINUX) add_umf_executable( NAME ${EXAMPLE_NAME} SRCS memspace/memspace_hmat.c - LIBS umf hwloc numa) + LIBS umf ${LIBHWLOC_LIBRARIES} numa) target_include_directories( ${EXAMPLE_NAME} PRIVATE ${UMF_CMAKE_SOURCE_DIR}/src/utils @@ -209,7 +209,7 @@ if(LINUX) add_umf_executable( NAME ${EXAMPLE_NAME} SRCS custom_provider/file_provider.c - LIBS umf hwloc) + LIBS umf ${LIBHWLOC_LIBRARIES}) target_include_directories( ${EXAMPLE_NAME} PRIVATE ${UMF_CMAKE_SOURCE_DIR}/src/utils diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 78ed07389..1ecfa359f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -61,6 +61,8 @@ set(BA_SOURCES ${BA_SOURCES} PARENT_SCOPE) +set(HWLOC_DEPENDENT_SOURCES topology.c) + set(UMF_SOURCES ${BA_SOURCES} libumf.c @@ -74,8 +76,11 @@ set(UMF_SOURCES provider/provider_tracking.c critnib/critnib.c pool/pool_proxy.c - pool/pool_scalable.c - topology.c) + pool/pool_scalable.c) + +if(NOT UMF_DISABLE_HWLOC) + set(UMF_SOURCES ${UMF_SOURCES} ${HWLOC_DEPENDENT_SOURCES}) +endif() set(UMF_SOURCES_LINUX libumf_linux.c) @@ -93,16 +98,22 @@ set(UMF_SOURCES_COMMON_LINUX_MACOSX memspaces/memspace_highest_bandwidth.c memspaces/memspace_lowest_latency.c) -set(UMF_SOURCES_LINUX ${UMF_SOURCES_LINUX} ${UMF_SOURCES_COMMON_LINUX_MACOSX} - provider/provider_os_memory_linux.c) +if(NOT UMF_DISABLE_HWLOC) + set(UMF_SOURCES_LINUX + ${UMF_SOURCES_LINUX} ${UMF_SOURCES_COMMON_LINUX_MACOSX} + provider/provider_os_memory_linux.c) -set(UMF_SOURCES_MACOSX ${UMF_SOURCES_MACOSX} ${UMF_SOURCES_COMMON_LINUX_MACOSX} - provider/provider_os_memory_macosx.c) + set(UMF_SOURCES_MACOSX + ${UMF_SOURCES_MACOSX} ${UMF_SOURCES_COMMON_LINUX_MACOSX} + provider/provider_os_memory_macosx.c) -set(UMF_SOURCES_WINDOWS ${UMF_SOURCES_WINDOWS} provider/provider_os_memory.c - provider/provider_os_memory_windows.c) + set(UMF_SOURCES_WINDOWS + ${UMF_SOURCES_WINDOWS} provider/provider_os_memory.c + provider/provider_os_memory_windows.c) + + set(UMF_LIBS ${UMF_LIBS} ${LIBHWLOC_LIBRARIES}) +endif() -set(UMF_LIBS ${UMF_LIBS} ${LIBHWLOC_LIBRARIES}) set(UMF_PRIVATE_LIBRARY_DIRS ${UMF_PRIVATE_LIBRARY_DIRS} ${LIBHWLOC_LIBRARY_DIRS}) @@ -121,11 +132,14 @@ elseif(MACOSX) endif() if(UMF_BUILD_SHARED_LIBRARY) + if(NOT UMF_DISABLE_HWLOC) + set(HWLOC_LIB hwloc) + endif() add_umf_library( NAME umf TYPE SHARED SRCS ${UMF_SOURCES} - LIBS ${UMF_LIBS} hwloc + LIBS ${UMF_LIBS} ${HWLOC_LIB} LINUX_MAP_FILE ${CMAKE_CURRENT_SOURCE_DIR}/libumf.map WINDOWS_DEF_FILE ${CMAKE_CURRENT_BINARY_DIR}/libumf.def) set(UMF_COMMON_COMPILE_DEFINITIONS ${UMF_COMMON_COMPILE_DEFINITIONS} @@ -143,6 +157,11 @@ else() LIBS ${UMF_LIBS}) endif() +if(UMF_DISABLE_HWLOC) + set(UMF_COMMON_COMPILE_DEFINITIONS ${UMF_COMMON_COMPILE_DEFINITIONS} + UMF_NO_HWLOC=1) +endif() + if(UMF_LINK_HWLOC_STATICALLY) add_dependencies(umf hwloc) endif() @@ -190,6 +209,8 @@ install(TARGETS umf EXPORT ${PROJECT_NAME}-targets) add_subdirectory(pool) -if(UMF_PROXY_LIB_ENABLED AND NOT UMF_LINK_HWLOC_STATICALLY) +if(UMF_PROXY_LIB_ENABLED + AND NOT UMF_LINK_HWLOC_STATICALLY + AND NOT UMF_DISABLE_HWLOC) add_subdirectory(proxy_lib) endif() diff --git a/src/libumf.c b/src/libumf.c index d11fa1637..1d99ab26a 100644 --- a/src/libumf.c +++ b/src/libumf.c @@ -12,8 +12,10 @@ #include "base_alloc_global.h" #include "memspace_internal.h" #include "provider_tracking.h" -#include "topology.h" #include "utils_log.h" +#if !defined(UMF_NO_HWLOC) +#include "topology.h" +#endif umf_memory_tracker_handle_t TRACKER = NULL; @@ -30,7 +32,7 @@ int umfInit(void) { void umfTearDown(void) { if (util_fetch_and_add64(&umfRefCount, -1) == 1) { -#ifndef _WIN32 +#if !defined(_WIN32) && !defined(UMF_NO_HWLOC) umfMemspaceHostAllDestroy(); umfMemspaceHighestCapacityDestroy(); umfMemspaceHighestBandwidthDestroy(); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 78c3e9c2b..d005ece00 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -152,26 +152,29 @@ endif() if(UMF_BUILD_LIBUMF_POOL_DISJOINT AND UMF_BUILD_LIBUMF_POOL_JEMALLOC - AND UMF_POOL_SCALABLE_ENABLED) + AND UMF_POOL_SCALABLE_ENABLED + AND (NOT UMF_DISABLE_HWLOC)) add_umf_test( NAME c_api_multi_pool SRCS c_api/multi_pool.c LIBS disjoint_pool jemalloc_pool ${JEMALLOC_LIBRARIES}) endif() -if(UMF_BUILD_LIBUMF_POOL_JEMALLOC) +if(UMF_BUILD_LIBUMF_POOL_JEMALLOC AND (NOT UMF_DISABLE_HWLOC)) add_umf_test( NAME jemalloc_pool SRCS pools/jemalloc_pool.cpp malloc_compliance_tests.cpp LIBS jemalloc_pool) endif() -if(UMF_POOL_SCALABLE_ENABLED) +if(UMF_POOL_SCALABLE_ENABLED AND (NOT UMF_DISABLE_HWLOC)) add_umf_test(NAME scalable_pool SRCS pools/scalable_pool.cpp malloc_compliance_tests.cpp) endif() -if(LINUX) # OS-specific functions are implemented only for Linux now +if(LINUX AND (NOT UMF_DISABLE_HWLOC)) # OS-specific functions are implemented + # only for + # Linux now if(PkgConfig_FOUND) pkg_check_modules(LIBNUMA numa) endif() @@ -266,7 +269,9 @@ add_umf_test( LIBS ${UMF_UTILS_FOR_TEST}) # tests for the proxy library -if(UMF_PROXY_LIB_ENABLED AND UMF_BUILD_SHARED_LIBRARY) +if(UMF_PROXY_LIB_ENABLED + AND UMF_BUILD_SHARED_LIBRARY + AND NOT UMF_DISABLE_HWLOC) add_umf_test( NAME proxy_lib_basic SRCS ${BA_SOURCES_FOR_TEST} test_proxy_lib.cpp @@ -317,22 +322,24 @@ function(add_umf_ipc_test) endfunction() if(LINUX) - build_umf_test( - NAME - ipc_os_prov_consumer - SRCS - ipc_os_prov_consumer.c - common/ipc_common.c - common/ipc_os_prov_common.c) - build_umf_test( - NAME - ipc_os_prov_producer - SRCS - ipc_os_prov_producer.c - common/ipc_common.c - common/ipc_os_prov_common.c) - add_umf_ipc_test(TEST ipc_os_prov_anon_fd) - add_umf_ipc_test(TEST ipc_os_prov_shm) + if(NOT UMF_DISABLE_HWLOC) + build_umf_test( + NAME + ipc_os_prov_consumer + SRCS + ipc_os_prov_consumer.c + common/ipc_common.c + common/ipc_os_prov_common.c) + build_umf_test( + NAME + ipc_os_prov_producer + SRCS + ipc_os_prov_producer.c + common/ipc_common.c + common/ipc_os_prov_common.c) + add_umf_ipc_test(TEST ipc_os_prov_anon_fd) + add_umf_ipc_test(TEST ipc_os_prov_shm) + endif() if(UMF_BUILD_GPU_TESTS AND UMF_BUILD_LEVEL_ZERO_PROVIDER) build_umf_test( NAME @@ -368,7 +375,8 @@ endif() if(LINUX AND UMF_BUILD_SHARED_LIBRARY - AND UMF_POOL_SCALABLE_ENABLED) + AND UMF_POOL_SCALABLE_ENABLED + AND NOT UMF_DISABLE_HWLOC) add_umf_test( NAME init_teardown SRCS test_init_teardown.c @@ -431,11 +439,13 @@ if(LINUX ) endif() - add_test( - NAME umf_standalone_examples - COMMAND - ${UMF_CMAKE_SOURCE_DIR}/test/test_examples.sh - ${UMF_CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${CMAKE_INSTALL_PREFIX} - ${EXAMPLES} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + if(NOT UMF_DISABLE_HWLOC) + add_test( + NAME umf_standalone_examples + COMMAND + ${UMF_CMAKE_SOURCE_DIR}/test/test_examples.sh + ${UMF_CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} + ${CMAKE_INSTALL_PREFIX} ${EXAMPLES} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + endif() endif() From 09c089a8420b43196b5462dd70119ea4e581632a Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 29 Jul 2024 16:43:24 +0200 Subject: [PATCH 018/352] Fix: size_fd has to be read under a lock Signed-off-by: Lukasz Dorau --- src/provider/provider_os_memory.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/provider/provider_os_memory.c b/src/provider/provider_os_memory.c index 38cb3ff4a..00251e53b 100644 --- a/src/provider/provider_os_memory.c +++ b/src/provider/provider_os_memory.c @@ -637,7 +637,8 @@ static inline void assert_is_page_aligned(uintptr_t ptr, size_t page_size) { static int os_mmap_aligned(void *hint_addr, size_t length, size_t alignment, size_t page_size, int prot, int flag, int fd, size_t max_fd_size, os_mutex_t *lock_fd, - void **out_addr, size_t *fd_size) { + void **out_addr, size_t *fd_size, + size_t *fd_offset) { assert(out_addr); size_t extended_length = length; @@ -650,7 +651,7 @@ static int os_mmap_aligned(void *hint_addr, size_t length, size_t alignment, extended_length += alignment; } - size_t fd_offset = 0; + *fd_offset = 0; if (fd > 0) { if (util_mutex_lock(lock_fd)) { @@ -664,12 +665,12 @@ static int os_mmap_aligned(void *hint_addr, size_t length, size_t alignment, return -1; } - fd_offset = *fd_size; + *fd_offset = *fd_size; *fd_size += extended_length; util_mutex_unlock(lock_fd); } - void *ptr = os_mmap(hint_addr, extended_length, prot, flag, fd, fd_offset); + void *ptr = os_mmap(hint_addr, extended_length, prot, flag, fd, *fd_offset); if (ptr == NULL) { LOG_PDEBUG("memory mapping failed"); return -1; @@ -912,14 +913,14 @@ static umf_result_t os_alloc(void *provider, size_t size, size_t alignment, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - size_t fd_offset = os_provider->size_fd; // needed for critnib_insert() + size_t fd_offset; // needed for critnib_insert() void *addr = NULL; errno = 0; - ret = os_mmap_aligned(NULL, size, alignment, page_size, - os_provider->protection, os_provider->visibility, - os_provider->fd, os_provider->max_size_fd, - &os_provider->lock_fd, &addr, &os_provider->size_fd); + ret = os_mmap_aligned( + NULL, size, alignment, page_size, os_provider->protection, + os_provider->visibility, os_provider->fd, os_provider->max_size_fd, + &os_provider->lock_fd, &addr, &os_provider->size_fd, &fd_offset); if (ret) { os_store_last_native_error(UMF_OS_RESULT_ERROR_ALLOC_FAILED, 0); LOG_ERR("memory allocation failed"); From cdb6c5af7b383cbbd5d8d6429287ef54c03254ab Mon Sep 17 00:00:00 2001 From: Igor Chorazewicz Date: Fri, 26 Jul 2024 18:03:14 +0000 Subject: [PATCH 019/352] Add option to link with hwloc statically on linux Co-authored-by: Krzysztof Filipek --- .github/workflows/basic.yml | 6 ++-- CMakeLists.txt | 64 +++++++++++++++++++++++++++++++++---- test/CMakeLists.txt | 3 +- 3 files changed, 63 insertions(+), 10 deletions(-) diff --git a/.github/workflows/basic.yml b/.github/workflows/basic.yml index 2842191e4..4105e606f 100644 --- a/.github/workflows/basic.yml +++ b/.github/workflows/basic.yml @@ -153,7 +153,7 @@ jobs: --build-type ${{matrix.build_type}} --disjoint-pool --jemalloc-pool - ${{ matrix.install_tbb == 'ON' && matrix.disable_hwloc != 'ON' && '--proxy' || '' }} + ${{ matrix.install_tbb == 'ON' && matrix.disable_hwloc != 'ON' && matrix.link_hwloc_statically != 'ON' && '--proxy' || '' }} --umf-version ${{env.UMF_VERSION}} ${{ matrix.shared_library == 'ON' && '--shared-library' || '' }} @@ -349,7 +349,7 @@ jobs: run: python3 -m pip install -r third_party/requirements.txt - name: Install hwloc - run: brew install hwloc jemalloc tbb + run: brew install hwloc jemalloc tbb autoconf automake libtool - name: Configure build run: > @@ -376,6 +376,6 @@ jobs: --build-type ${{env.BUILD_TYPE}} --disjoint-pool --jemalloc-pool - --proxy + ${{ matrix.link_hwloc_statically != 'ON' && '--proxy' || '' }} --umf-version ${{env.UMF_VERSION}} --shared-library diff --git a/CMakeLists.txt b/CMakeLists.txt index 6005f9d92..946eb8984 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,8 +48,10 @@ option(UMF_BUILD_EXAMPLES "Build UMF examples" ON) option(UMF_BUILD_FUZZTESTS "Build UMF fuzz tests" OFF) option(UMF_BUILD_GPU_EXAMPLES "Build UMF GPU examples" OFF) option(UMF_DEVELOPER_MODE "Enable additional developer checks" OFF) -option(UMF_LINK_HWLOC_STATICALLY - "Link UMF with HWLOC library statically (Windows+Release only)" OFF) +option( + UMF_LINK_HWLOC_STATICALLY + "Link UMF with HWLOC library statically (supported for Linux, MacOS and Release build on Windows)" + OFF) option(UMF_FORMAT_CODE_STYLE "Add clang, cmake, and black -format-check and -format-apply targets" OFF) @@ -110,10 +112,11 @@ if(NOT UMF_LINK_HWLOC_STATICALLY) "${DLL_PATH_LIST};PATH=path_list_append:${LIBHWLOC_LIBRARY_DIRS}/../bin" ) endif() -else() - if(NOT WINDOWS) - message(FATAL_ERROR "hwloc can be statically linked only on Windows") - endif() + # add PATH to DLL on Windows + set(DLL_PATH_LIST + "${DLL_PATH_LIST};PATH=path_list_append:${LIBHWLOC_LIBRARY_DIRS}/../bin" + ) +elseif(WINDOWS) include(FetchContent) set(HWLOC_ENABLE_TESTING OFF) set(HWLOC_SKIP_LSTOPO ON) @@ -134,6 +137,55 @@ else() set(LIBHWLOC_LIBRARY_DIRS ${hwloc_targ_BINARY_DIR}/Release;${hwloc_targ_BINARY_DIR}/Debug) + message(STATUS " LIBHWLOC_LIBRARIES = ${LIBHWLOC_LIBRARIES}") + message(STATUS " LIBHWLOC_INCLUDE_DIRS = ${LIBHWLOC_INCLUDE_DIRS}") + message(STATUS " LIBHWLOC_LIBRARY_DIRS = ${LIBHWLOC_LIBRARY_DIRS}") +else() + include(FetchContent) + FetchContent_Declare( + hwloc_targ + GIT_REPOSITORY "https://github.com/open-mpi/hwloc.git" + GIT_TAG hwloc-2.10.0) + + FetchContent_GetProperties(hwloc_targ) + if(NOT hwloc_targ_POPULATED) + FetchContent_MakeAvailable(hwloc_targ) + endif() + + add_custom_command( + COMMAND ./autogen.sh + WORKING_DIRECTORY ${hwloc_targ_SOURCE_DIR} + OUTPUT ${hwloc_targ_SOURCE_DIR}/configure) + add_custom_command( + COMMAND + ./configure --prefix=${hwloc_targ_BINARY_DIR} --enable-static=yes + --enable-shared=no --disable-libxml2 --disable-levelzero + CFLAGS=-fPIC CXXFLAGS=-fPIC + WORKING_DIRECTORY ${hwloc_targ_SOURCE_DIR} + OUTPUT ${hwloc_targ_SOURCE_DIR}/Makefile + DEPENDS ${hwloc_targ_SOURCE_DIR}/configure) + add_custom_command( + COMMAND make + WORKING_DIRECTORY ${hwloc_targ_SOURCE_DIR} + OUTPUT ${hwloc_targ_SOURCE_DIR}/lib/libhwloc.la + DEPENDS ${hwloc_targ_SOURCE_DIR}/Makefile) + add_custom_command( + COMMAND make install + WORKING_DIRECTORY ${hwloc_targ_SOURCE_DIR} + OUTPUT ${hwloc_targ_BINARY_DIR}/lib/libhwloc.a + DEPENDS ${hwloc_targ_SOURCE_DIR}/lib/libhwloc.la) + + add_custom_target(hwloc_prod + DEPENDS ${hwloc_targ_BINARY_DIR}/lib/libhwloc.a) + add_library(hwloc INTERFACE) + target_link_libraries(hwloc + INTERFACE ${hwloc_targ_BINARY_DIR}/lib/libhwloc.a) + add_dependencies(hwloc hwloc_prod) + + set(LIBHWLOC_LIBRARY_DIRS ${hwloc_targ_BINARY_DIR}/lib) + set(LIBHWLOC_INCLUDE_DIRS ${hwloc_targ_BINARY_DIR}/include) + set(LIBHWLOC_LIBRARIES ${hwloc_targ_BINARY_DIR}/lib/libhwloc.a) + message(STATUS " LIBHWLOC_LIBRARIES = ${LIBHWLOC_LIBRARIES}") message(STATUS " LIBHWLOC_INCLUDE_DIRS = ${LIBHWLOC_INCLUDE_DIRS}") message(STATUS " LIBHWLOC_LIBRARY_DIRS = ${LIBHWLOC_LIBRARY_DIRS}") diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index d005ece00..bc435bfd8 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -271,7 +271,8 @@ add_umf_test( # tests for the proxy library if(UMF_PROXY_LIB_ENABLED AND UMF_BUILD_SHARED_LIBRARY - AND NOT UMF_DISABLE_HWLOC) + AND NOT UMF_DISABLE_HWLOC + AND NOT UMF_LINK_HWLOC_STATICALLY) add_umf_test( NAME proxy_lib_basic SRCS ${BA_SOURCES_FOR_TEST} test_proxy_lib.cpp From d677e1c8c7d051d7ef5e83575a370b0b06123a4c Mon Sep 17 00:00:00 2001 From: Igor Chorazewicz Date: Fri, 26 Jul 2024 18:06:51 +0000 Subject: [PATCH 020/352] Add more CI runs with UMF_LINK_HWLOC_STATICALLY=1 --- .github/workflows/basic.yml | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/.github/workflows/basic.yml b/.github/workflows/basic.yml index 4105e606f..736f08eef 100644 --- a/.github/workflows/basic.yml +++ b/.github/workflows/basic.yml @@ -24,6 +24,7 @@ jobs: level_zero_provider: ['ON'] install_tbb: ['ON'] disable_hwloc: ['OFF'] + link_hwloc_statically: ['OFF'] include: - os: 'ubuntu-20.04' build_type: Release @@ -71,12 +72,19 @@ jobs: level_zero_provider: 'ON' install_tbb: 'OFF' - os: 'ubuntu-22.04' - build_type: Release + build_type: Debug compiler: {c: gcc, cxx: g++} shared_library: 'ON' level_zero_provider: 'ON' install_tbb: 'ON' disable_hwloc: 'ON' + - os: 'ubuntu-22.04' + build_type: Release + compiler: {c: gcc, cxx: g++} + shared_library: 'ON' + level_zero_provider: 'ON' + install_tbb: 'ON' + link_hwloc_statically: 'ON' runs-on: ${{matrix.os}} steps: @@ -131,6 +139,7 @@ jobs: -DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON -DUMF_TESTS_FAIL_ON_SKIP=ON -DUMF_DISABLE_HWLOC=${{matrix.disable_hwloc}} + -DUMF_LINK_HWLOC_STATICALLY=${{matrix.link_hwloc_statically}} - name: Build UMF run: cmake --build ${{env.BUILD_DIR}} -j $(nproc) @@ -349,7 +358,7 @@ jobs: run: python3 -m pip install -r third_party/requirements.txt - name: Install hwloc - run: brew install hwloc jemalloc tbb autoconf automake libtool + run: brew install hwloc jemalloc tbb - name: Configure build run: > @@ -376,6 +385,6 @@ jobs: --build-type ${{env.BUILD_TYPE}} --disjoint-pool --jemalloc-pool - ${{ matrix.link_hwloc_statically != 'ON' && '--proxy' || '' }} + --proxy --umf-version ${{env.UMF_VERSION}} --shared-library From b32b89ae5cfef073c10f3447899447383e833f11 Mon Sep 17 00:00:00 2001 From: Igor Chorazewicz Date: Mon, 29 Jul 2024 18:33:27 +0000 Subject: [PATCH 021/352] Add option to change hwloc repo url and tag --- CMakeLists.txt | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 946eb8984..cf245ce10 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -100,6 +100,14 @@ else() message(FATAL_ERROR "Unknown OS type") endif() +if(NOT DEFINED UMF_HWLOC_REPO) + set(UMF_HWLOC_REPO "https://github.com/open-mpi/hwloc.git") +endif() + +if(NOT DEFINED UMF_HWLOC_TAG) + set(UMF_HWLOC_TAG hwloc-2.10.0) +endif() + if(NOT UMF_LINK_HWLOC_STATICALLY) if(NOT UMF_DISABLE_HWLOC) pkg_check_modules(LIBHWLOC hwloc>=2.3.0) @@ -121,10 +129,13 @@ elseif(WINDOWS) set(HWLOC_ENABLE_TESTING OFF) set(HWLOC_SKIP_LSTOPO ON) set(HWLOC_SKIP_TOOLS ON) + + message(STATUS "Will fetch hwloc from ${UMF_HWLOC_REPO}") + FetchContent_Declare( hwloc_targ - GIT_REPOSITORY "https://github.com/open-mpi/hwloc.git" - GIT_TAG hwloc-2.10.0 + GIT_REPOSITORY ${UMF_HWLOC_REPO} + GIT_TAG ${UMF_HWLOC_TAG} SOURCE_SUBDIR contrib/windows-cmake/ FIND_PACKAGE_ARGS) FetchContent_GetProperties(hwloc_targ) @@ -142,10 +153,12 @@ elseif(WINDOWS) message(STATUS " LIBHWLOC_LIBRARY_DIRS = ${LIBHWLOC_LIBRARY_DIRS}") else() include(FetchContent) + message(STATUS "Will fetch hwloc from ${UMF_HWLOC_REPO}") + FetchContent_Declare( hwloc_targ - GIT_REPOSITORY "https://github.com/open-mpi/hwloc.git" - GIT_TAG hwloc-2.10.0) + GIT_REPOSITORY ${UMF_HWLOC_REPO} + GIT_TAG ${UMF_HWLOC_TAG}) FetchContent_GetProperties(hwloc_targ) if(NOT hwloc_targ_POPULATED) From 91b8f76b5126b7ea073a41c0558dec90e36231af Mon Sep 17 00:00:00 2001 From: Igor Chorazewicz Date: Mon, 29 Jul 2024 17:29:39 +0000 Subject: [PATCH 022/352] Avoid using non-existing symbols in .map to fix: "ld.lld: error: version script assignment of 'UMF_1.0' to symbol 'umfLevelZeroMemoryProviderOps' failed: symbol not defined" when using lld linker --- CMakeLists.txt | 23 ++++++++++++----------- cmake/helpers.cmake | 9 +++++++++ src/CMakeLists.txt | 23 ++++++++++++++++++++++- src/libumf.def.in | 3 +-- src/{libumf.map => libumf.map.in} | 8 +------- 5 files changed, 45 insertions(+), 21 deletions(-) rename src/{libumf.map => libumf.map.in} (87%) diff --git a/CMakeLists.txt b/CMakeLists.txt index cf245ce10..2c6d05d41 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -390,6 +390,18 @@ else() ) endif() +set(UMF_OPTIONAL_SYMBOLS_LINUX "") +set(UMF_OPTIONAL_SYMBOLS_WINDOWS "") + +# Conditional configuration for Level Zero provider +if(UMF_BUILD_LEVEL_ZERO_PROVIDER) + add_optional_symbol(umfLevelZeroMemoryProviderOps) +endif() + +if(NOT UMF_DISABLE_HWLOC) + add_optional_symbol(umfOsMemoryProviderOps) +endif() + add_subdirectory(src) if(UMF_BUILD_TESTS) @@ -408,17 +420,6 @@ if(UMF_BUILD_EXAMPLES) endif() endif() -# Conditional configuration for Level Zero provider -if(UMF_BUILD_LEVEL_ZERO_PROVIDER) - set(OPTIONAL_SYMBOLS "umfLevelZeroMemoryProviderOps") -else() - set(OPTIONAL_SYMBOLS "") -endif() - -# Configure the DEF file based on whether Level Zero provider is built -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/libumf.def.in" - "${CMAKE_CURRENT_BINARY_DIR}/src/libumf.def" @ONLY) - if(UMF_FORMAT_CODE_STYLE) find_program(CLANG_FORMAT NAMES clang-format-15 clang-format-15.0 clang-format) diff --git a/cmake/helpers.cmake b/cmake/helpers.cmake index 0e226d679..a4f59a763 100644 --- a/cmake/helpers.cmake +++ b/cmake/helpers.cmake @@ -417,3 +417,12 @@ macro(add_sanitizer_flag flag) set(CMAKE_REQUIRED_FLAGS ${SAVED_CMAKE_REQUIRED_FLAGS}) endmacro() + +function(add_optional_symbol symbol) + set(UMF_OPTIONAL_SYMBOLS_WINDOWS + "${UMF_OPTIONAL_SYMBOLS_WINDOWS} \n ${symbol}" + PARENT_SCOPE) + set(UMF_OPTIONAL_SYMBOLS_LINUX + "${UMF_OPTIONAL_SYMBOLS_LINUX} \n ${symbol};" + PARENT_SCOPE) +endfunction() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1ecfa359f..7d2f151f0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -112,8 +112,29 @@ if(NOT UMF_DISABLE_HWLOC) provider/provider_os_memory_windows.c) set(UMF_LIBS ${UMF_LIBS} ${LIBHWLOC_LIBRARIES}) + + if(NOT WINDOWS) + add_optional_symbol(umfMemspaceCreateFromNumaArray) + add_optional_symbol(umfMemspaceHighestBandwidthGet) + add_optional_symbol(umfMemspaceHighestCapacityGet) + add_optional_symbol(umfMemspaceHostAllGet) + add_optional_symbol(umfMemspaceLowestLatencyGet) + endif() endif() +if(WINDOWS) + message(STATUS "UMF_OPTIONAL_SYMBOLS: ${UMF_OPTIONAL_SYMBOLS_WINDOWS}") +else() + message(STATUS "UMF_OPTIONAL_SYMBOLS: ${UMF_OPTIONAL_SYMBOLS_LINUX}") +endif() + +# Configure the DEF file based on whether Level Zero provider is built +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/libumf.def.in" + "${CMAKE_CURRENT_BINARY_DIR}/libumf.def" @ONLY) + +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/libumf.map.in" + "${CMAKE_CURRENT_BINARY_DIR}/libumf.map" @ONLY) + set(UMF_PRIVATE_LIBRARY_DIRS ${UMF_PRIVATE_LIBRARY_DIRS} ${LIBHWLOC_LIBRARY_DIRS}) @@ -140,7 +161,7 @@ if(UMF_BUILD_SHARED_LIBRARY) TYPE SHARED SRCS ${UMF_SOURCES} LIBS ${UMF_LIBS} ${HWLOC_LIB} - LINUX_MAP_FILE ${CMAKE_CURRENT_SOURCE_DIR}/libumf.map + LINUX_MAP_FILE ${CMAKE_CURRENT_BINARY_DIR}/libumf.map WINDOWS_DEF_FILE ${CMAKE_CURRENT_BINARY_DIR}/libumf.def) set(UMF_COMMON_COMPILE_DEFINITIONS ${UMF_COMMON_COMPILE_DEFINITIONS} "UMF_SHARED_LIBRARY") diff --git a/src/libumf.def.in b/src/libumf.def.in index 00a1995ae..cb8d4d74c 100644 --- a/src/libumf.def.in +++ b/src/libumf.def.in @@ -45,7 +45,6 @@ EXPORTS umfMemspaceMemtargetGet umfMemtargetGetType umfOpenIPCHandle - umfOsMemoryProviderOps umfPoolAlignedMalloc umfPoolByPtr umfPoolCalloc @@ -62,4 +61,4 @@ EXPORTS umfProxyPoolOps umfPutIPCHandle umfScalablePoolOps - @OPTIONAL_SYMBOLS@ + @UMF_OPTIONAL_SYMBOLS_WINDOWS@ diff --git a/src/libumf.map b/src/libumf.map.in similarity index 87% rename from src/libumf.map rename to src/libumf.map.in index 2dc6956c9..7c2002a1f 100644 --- a/src/libumf.map +++ b/src/libumf.map.in @@ -11,7 +11,6 @@ UMF_1.0 { umfFree; umfGetIPCHandle; umfGetLastFailedMemoryProvider; - umfLevelZeroMemoryProviderOps; umfMemoryTrackerGetAllocInfo; umfMemoryProviderAlloc; umfMemoryProviderAllocationMerge; @@ -35,17 +34,11 @@ UMF_1.0 { umfMempolicyDestroy; umfMempolicySetCustomSplitPartitions; umfMempolicySetInterleavePartSize; - umfMemspaceCreateFromNumaArray; umfMemspaceDestroy; umfMemspaceMemtargetNum; umfMemspaceMemtargetGet; - umfMemspaceHighestBandwidthGet; - umfMemspaceHighestCapacityGet; - umfMemspaceHostAllGet; - umfMemspaceLowestLatencyGet; umfMemtargetGetType; umfOpenIPCHandle; - umfOsMemoryProviderOps; umfPoolAlignedMalloc; umfPoolByPtr; umfPoolCalloc; @@ -62,6 +55,7 @@ UMF_1.0 { umfProxyPoolOps; umfPutIPCHandle; umfScalablePoolOps; + @UMF_OPTIONAL_SYMBOLS_LINUX@ local: *; }; From a66c76acef6c995550b2d1f98b27471aa9de42cc Mon Sep 17 00:00:00 2001 From: Igor Chorazewicz Date: Mon, 29 Jul 2024 23:21:36 +0000 Subject: [PATCH 023/352] Allow completely disabling hwloc on windows --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2c6d05d41..d104c42a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,7 +124,7 @@ if(NOT UMF_LINK_HWLOC_STATICALLY) set(DLL_PATH_LIST "${DLL_PATH_LIST};PATH=path_list_append:${LIBHWLOC_LIBRARY_DIRS}/../bin" ) -elseif(WINDOWS) +elseif(WINDOWS AND NOT UMF_DISABLE_HWLOC) include(FetchContent) set(HWLOC_ENABLE_TESTING OFF) set(HWLOC_SKIP_LSTOPO ON) @@ -151,7 +151,7 @@ elseif(WINDOWS) message(STATUS " LIBHWLOC_LIBRARIES = ${LIBHWLOC_LIBRARIES}") message(STATUS " LIBHWLOC_INCLUDE_DIRS = ${LIBHWLOC_INCLUDE_DIRS}") message(STATUS " LIBHWLOC_LIBRARY_DIRS = ${LIBHWLOC_LIBRARY_DIRS}") -else() +elseif(NOT UMF_DISABLE_HWLOC) include(FetchContent) message(STATUS "Will fetch hwloc from ${UMF_HWLOC_REPO}") From d85f56cbfee1a64fdd19b598e6b359a4aecee616 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Mon, 29 Jul 2024 17:30:19 +0200 Subject: [PATCH 024/352] Minor updates in README --- CMakeLists.txt | 2 +- README.md | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d104c42a3..f0689bdcd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,7 +65,7 @@ option(USE_VALGRIND "Enable Valgrind instrumentation" OFF) option(USE_GCOV "Enable gcov support" OFF) option( UMF_DISABLE_HWLOC - "Disable features that requires hwloc (OS provider, memory targets, topolgy discovery)" + "Disable features that requires hwloc (OS provider, memory targets, topology discovery)" OFF) # set UMF_PROXY_LIB_BASED_ON_POOL to one of: SCALABLE or JEMALLOC diff --git a/README.md b/README.md index 808965c5f..10ec1872f 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,14 @@ # Unified Memory Framework -[![Basic builds](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/basic.yml/badge.svg?branch=main)](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/basic.yml) -[![CodeQL](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/codeql.yml/badge.svg?branch=main)](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/codeql.yml) -[![SpellCheck](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/spellcheck.yml/badge.svg?branch=main)](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/spellcheck.yml) +[![PR/push](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/pr_push.yml/badge.svg?branch=main)](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/pr_push.yml) [![GitHubPages](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/docs.yml/badge.svg?branch=main)](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/docs.yml) -[![Benchmarks](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/benchmarks.yml/badge.svg?branch=main)](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/benchmarks.yml) [![Nightly](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/nightly.yml/badge.svg?branch=main)](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/nightly.yml) -[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/oneapi-src/unified-memory-framework/badge)](https://securityscorecards.dev/viewer/?uri=github.com/oneapi-src/unified-memory-framework) +[![Bandit](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/bandit.yml/badge.svg?branch=main)](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/bandit.yml) +[![CodeQL](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/codeql.yml/badge.svg?branch=main)](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/codeql.yml) [![Coverity build](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/coverity.yml/badge.svg?branch=main)](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/coverity.yml) [![Coverity report](https://scan.coverity.com/projects/29761/badge.svg?flat=0)](https://scan.coverity.com/projects/oneapi-src-unified-memory-framework) -[![Bandit](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/bandit.yml/badge.svg?branch=main)](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/bandit.yml) +[![Trivy](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/trivy.yml/badge.svg)](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/trivy.yml) +[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/oneapi-src/unified-memory-framework/badge)](https://securityscorecards.dev/viewer/?uri=github.com/oneapi-src/unified-memory-framework) ## Introduction @@ -120,6 +119,7 @@ List of options provided by CMake: | USE_VALGRIND | Enable Valgrind instrumentation | ON/OFF | OFF | | USE_GCOV | Enable gcov support (Linux only) | ON/OFF | OFF | | UMF_LINK_HWLOC_STATICALLY | Link UMF with HWLOC library statically (Windows+Release only) | ON/OFF | OFF | +| UMF_DISABLE_HWLOC | Disable features that requires hwloc (OS provider, memory targets, topology discovery) | ON/OFF | OFF | ## Architecture: memory pools and providers @@ -208,7 +208,7 @@ It is distributed as part of libumf. To use this pool, TBB must be installed in ##### Requirements -Required packages: +Packages required for using this pool and executing tests/benchmarks (not required for build): - libtbb-dev (libtbbmalloc.so.2) on Linux or tbb (tbbmalloc.dll) on Windows ### Memspaces (Linux-only) From c06b4f0bec3399689abbb250112f3086dd44ffd3 Mon Sep 17 00:00:00 2001 From: Patryk Kaminski Date: Tue, 30 Jul 2024 11:35:58 +0200 Subject: [PATCH 025/352] Move 3rd party programs license to a subdir --- CMakeLists.txt | 4 +++- .../third-party-programs.txt | 0 test/test_installation.py | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) rename third-party-programs.txt => licensing/third-party-programs.txt (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index d104c42a3..2e4f7ab1b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -600,8 +600,10 @@ endif() # Configure make install/uninstall and packages # --------------------------------------------------------------------------- # install(FILES ${CMAKE_SOURCE_DIR}/LICENSE.TXT - ${CMAKE_SOURCE_DIR}/third-party-programs.txt DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME}/") +install( + FILES ${CMAKE_SOURCE_DIR}/licensing/third-party-programs.txt + DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME}/licensing/") install(DIRECTORY examples DESTINATION "${CMAKE_INSTALL_DOCDIR}") diff --git a/third-party-programs.txt b/licensing/third-party-programs.txt similarity index 100% rename from third-party-programs.txt rename to licensing/third-party-programs.txt diff --git a/test/test_installation.py b/test/test_installation.py index 6acb4a0bc..49a382969 100644 --- a/test/test_installation.py +++ b/test/test_installation.py @@ -146,7 +146,8 @@ def _create_match_list(self) -> List[str]: examples.insert(0, "share/doc/umf/examples") share.extend(examples) share.append("share/doc/umf/LICENSE.TXT") - share.append("share/doc/umf/third-party-programs.txt") + share.append("share/doc/umf/licensing") + share.append("share/doc/umf/licensing/third-party-programs.txt") all_files = bin + include + lib + share if platform.system() == "Windows": From d2cd0241b321b2c385fe048e676e4ca5da750a19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20=C5=BDu=C5=BEek?= Date: Wed, 31 Jul 2024 16:24:07 +0100 Subject: [PATCH 026/352] [CMake] Don't use CMAKE_SOURCE_DIR during install Referring to an installed file using `CMAKE_SOURCE_DIR` only works when UMF is built and installed standalone, but not when it's included by other projects. Only `LICENSE.TXT` and `licensing/third-party-programs.txt` still had these issue, while other files already used `PROJECT_SOURCE_DIR`. --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 077359689..afe2b563e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -599,10 +599,10 @@ endif() # --------------------------------------------------------------------------- # # Configure make install/uninstall and packages # --------------------------------------------------------------------------- # -install(FILES ${CMAKE_SOURCE_DIR}/LICENSE.TXT +install(FILES ${PROJECT_SOURCE_DIR}/LICENSE.TXT DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME}/") install( - FILES ${CMAKE_SOURCE_DIR}/licensing/third-party-programs.txt + FILES ${PROJECT_SOURCE_DIR}/licensing/third-party-programs.txt DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME}/licensing/") install(DIRECTORY examples DESTINATION "${CMAKE_INSTALL_DOCDIR}") From f7afaad23870f73bf7a4615df817404e659a2d3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Fri, 2 Aug 2024 12:48:02 +0200 Subject: [PATCH 027/352] [CMake] Add missing UMF_ prefix in 'public' umf options --- .github/workflows/nightly.yml | 2 +- .github/workflows/sanitizers.yml | 8 ++++---- .github/workflows/valgrind.yml | 2 +- CMakeLists.txt | 20 ++++++++++---------- CONTRIBUTING.md | 4 ++-- README.md | 12 ++++++------ cmake/helpers.cmake | 4 ++-- src/utils/CMakeLists.txt | 12 ++++++------ test/CMakeLists.txt | 8 ++++---- 9 files changed, 36 insertions(+), 36 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 28a07c3a9..f2bf8f08f 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -79,7 +79,7 @@ jobs: -DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON -DUMF_BUILD_LEVEL_ZERO_PROVIDER=OFF - -DUSE_VALGRIND=1 + -DUMF_USE_VALGRIND=1 -DUMF_TESTS_FAIL_ON_SKIP=ON - name: Build diff --git a/.github/workflows/sanitizers.yml b/.github/workflows/sanitizers.yml index 4b4b37aaf..2ca712543 100644 --- a/.github/workflows/sanitizers.yml +++ b/.github/workflows/sanitizers.yml @@ -59,9 +59,9 @@ jobs: -DUMF_DEVELOPER_MODE=ON -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON -DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON - -DUSE_ASAN=${{matrix.sanitizers.asan}} - -DUSE_UBSAN=${{matrix.sanitizers.ubsan}} - -DUSE_TSAN=${{matrix.sanitizers.tsan}} + -DUMF_USE_ASAN=${{matrix.sanitizers.asan}} + -DUMF_USE_UBSAN=${{matrix.sanitizers.ubsan}} + -DUMF_USE_TSAN=${{matrix.sanitizers.tsan}} -DUMF_BUILD_EXAMPLES=ON -DUMF_TESTS_FAIL_ON_SKIP=ON @@ -127,7 +127,7 @@ jobs: -DUMF_FORMAT_CODE_STYLE=OFF -DUMF_DEVELOPER_MODE=ON -DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON - -DUSE_ASAN=${{matrix.sanitizers.asan}} + -DUMF_USE_ASAN=${{matrix.sanitizers.asan}} -DUMF_BUILD_EXAMPLES=ON -DUMF_BUILD_LEVEL_ZERO_PROVIDER=OFF -DUMF_TESTS_FAIL_ON_SKIP=ON diff --git a/.github/workflows/valgrind.yml b/.github/workflows/valgrind.yml index 0ca9bf779..53569385e 100644 --- a/.github/workflows/valgrind.yml +++ b/.github/workflows/valgrind.yml @@ -35,7 +35,7 @@ jobs: -DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON -DUMF_BUILD_LEVEL_ZERO_PROVIDER=OFF - -DUSE_VALGRIND=1 + -DUMF_USE_VALGRIND=1 -DUMF_TESTS_FAIL_ON_SKIP=ON - name: Build diff --git a/CMakeLists.txt b/CMakeLists.txt index afe2b563e..70b99aaf2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,12 +57,12 @@ option(UMF_FORMAT_CODE_STYLE OFF) # Only a part of skips is treated as a failure now. TODO: extend to all tests option(UMF_TESTS_FAIL_ON_SKIP "Treat skips in tests as fail" OFF) -option(USE_ASAN "Enable AddressSanitizer checks" OFF) -option(USE_UBSAN "Enable UndefinedBehaviorSanitizer checks" OFF) -option(USE_TSAN "Enable ThreadSanitizer checks" OFF) -option(USE_MSAN "Enable MemorySanitizer checks" OFF) -option(USE_VALGRIND "Enable Valgrind instrumentation" OFF) -option(USE_GCOV "Enable gcov support" OFF) +option(UMF_USE_ASAN "Enable AddressSanitizer checks" OFF) +option(UMF_USE_UBSAN "Enable UndefinedBehaviorSanitizer checks" OFF) +option(UMF_USE_TSAN "Enable ThreadSanitizer checks" OFF) +option(UMF_USE_MSAN "Enable MemorySanitizer checks" OFF) +option(UMF_USE_VALGRIND "Enable Valgrind instrumentation" OFF) +option(UMF_USE_GCOV "Enable gcov support" OFF) option( UMF_DISABLE_HWLOC "Disable features that requires hwloc (OS provider, memory targets, topology discovery)" @@ -266,16 +266,16 @@ if(MSVC) endif() # Sanitizer flags -if(USE_ASAN) +if(UMF_USE_ASAN) add_sanitizer_flag(address) endif() -if(USE_UBSAN) +if(UMF_USE_UBSAN) add_sanitizer_flag(undefined) endif() -if(USE_TSAN) +if(UMF_USE_TSAN) add_sanitizer_flag(thread) endif() -if(USE_MSAN) +if(UMF_USE_MSAN) message(WARNING "MemorySanitizer requires instrumented libraries to " "prevent reporting false-positives") add_sanitizer_flag(memory) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 771fa1211..e350cd8d0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -207,12 +207,12 @@ origin: https://dependency_origin.com ## Code coverage After adding a new functionality add tests and check coverage before and after the change. -To do this, enable coverage instrumentation by turning on the USE_GCOV flag in CMake. +To do this, enable coverage instrumentation by turning on the UMF_USE_GCOV flag in CMake. Coverage instrumentation feature is supported only by GCC and Clang. An example flow might look like the following: ```bash -$ cmake -B build -DUSE_GCOV=1 -DCMAKE_BUILD_TYPE=Debug +$ cmake -B build -DUMF_USE_GCOV=1 -DCMAKE_BUILD_TYPE=Debug $ cmake --build build -j $ cd build $ ctest diff --git a/README.md b/README.md index 10ec1872f..0004f0923 100644 --- a/README.md +++ b/README.md @@ -112,12 +112,12 @@ List of options provided by CMake: | UMF_DEVELOPER_MODE | Enable additional developer checks | ON/OFF | OFF | | UMF_FORMAT_CODE_STYLE | Add clang, cmake, and black -format-check and -format-apply targets to make | ON/OFF | OFF | | UMF_TESTS_FAIL_ON_SKIP | Treat skips in tests as fail | ON/OFF | OFF | -| USE_ASAN | Enable AddressSanitizer checks | ON/OFF | OFF | -| USE_UBSAN | Enable UndefinedBehaviorSanitizer checks | ON/OFF | OFF | -| USE_TSAN | Enable ThreadSanitizer checks | ON/OFF | OFF | -| USE_MSAN | Enable MemorySanitizer checks | ON/OFF | OFF | -| USE_VALGRIND | Enable Valgrind instrumentation | ON/OFF | OFF | -| USE_GCOV | Enable gcov support (Linux only) | ON/OFF | OFF | +| UMF_USE_ASAN | Enable AddressSanitizer checks | ON/OFF | OFF | +| UMF_USE_UBSAN | Enable UndefinedBehaviorSanitizer checks | ON/OFF | OFF | +| UMF_USE_TSAN | Enable ThreadSanitizer checks | ON/OFF | OFF | +| UMF_USE_MSAN | Enable MemorySanitizer checks | ON/OFF | OFF | +| UMF_USE_VALGRIND | Enable Valgrind instrumentation | ON/OFF | OFF | +| UMF_USE_GCOV | Enable gcov support (Linux only) | ON/OFF | OFF | | UMF_LINK_HWLOC_STATICALLY | Link UMF with HWLOC library statically (Windows+Release only) | ON/OFF | OFF | | UMF_DISABLE_HWLOC | Disable features that requires hwloc (OS provider, memory targets, topology discovery) | ON/OFF | OFF | diff --git a/cmake/helpers.cmake b/cmake/helpers.cmake index a4f59a763..1d3e175fa 100644 --- a/cmake/helpers.cmake +++ b/cmake/helpers.cmake @@ -218,7 +218,7 @@ function(add_umf_target_compile_options name) target_compile_options(${name} PRIVATE -fno-omit-frame-pointer -fstack-protector-strong) endif() - if(USE_GCOV) + if(UMF_USE_GCOV) if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") message(FATAL_ERROR "To use gcov, the build type must be Debug") endif() @@ -254,7 +254,7 @@ function(add_umf_target_link_options name) if(NOT MSVC) if(NOT APPLE) target_link_options(${name} PRIVATE "LINKER:-z,relro,-z,now") - if(USE_GCOV) + if(UMF_USE_GCOV) if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") message( FATAL_ERROR "To use gcov, the build type must be Debug") diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt index 78cd0e129..c7a285ce2 100644 --- a/src/utils/CMakeLists.txt +++ b/src/utils/CMakeLists.txt @@ -13,11 +13,11 @@ set(UMF_UTILS_SOURCES_POSIX utils_posix_common.c utils_posix_concurrency.c set(UMF_UTILS_SOURCES_WINDOWS utils_windows_common.c utils_windows_concurrency.c utils_windows_math.c) -if(USE_VALGRIND) - if(USE_ASAN - OR USE_TSAN - OR USE_UBSAN - OR USE_MSAN) +if(UMF_USE_VALGRIND) + if(UMF_USE_ASAN + OR UMF_USE_TSAN + OR UMF_USE_UBSAN + OR UMF_USE_MSAN) message(FATAL_ERROR "Cannot use valgrind and sanitizers together") endif() @@ -51,7 +51,7 @@ target_include_directories( $ $) -if(USE_VALGRIND) +if(UMF_USE_VALGRIND) set(UMF_UTILS_INTERFACE_DEFS "UMF_VG_ENABLED=1") endif() diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index bc435bfd8..c1e3b2c18 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -394,10 +394,10 @@ endif() if(LINUX AND UMF_BUILD_SHARED_LIBRARY AND NOT - (USE_ASAN - OR USE_UBSAN - OR USE_TSAN - OR USE_MSAN)) + (UMF_USE_ASAN + OR UMF_USE_UBSAN + OR UMF_USE_TSAN + OR UMF_USE_MSAN)) set(EXAMPLES "") if(UMF_POOL_SCALABLE_ENABLED) set(EXAMPLES ${EXAMPLES} basic) From 04f864649480583c609691f2d690b03acf31f140 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Fri, 2 Aug 2024 12:51:26 +0200 Subject: [PATCH 028/352] Properly prefix test_common lib with 'umf_' --- test/CMakeLists.txt | 2 +- test/common/CMakeLists.txt | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c1e3b2c18..59c76fe31 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -45,7 +45,7 @@ function(build_umf_test) endif() set(TEST_LIBS - test_common + umf_test_common ${ARG_LIBS} GTest::gtest_main ${LIBS_OPTIONAL} diff --git a/test/common/CMakeLists.txt b/test/common/CMakeLists.txt index 14f36ce8e..4f88fd7d8 100644 --- a/test/common/CMakeLists.txt +++ b/test/common/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2023 Intel Corporation +# 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 @@ -10,8 +10,9 @@ set(COMMON_SOURCES provider_trace.c) add_umf_library( - NAME test_common + NAME umf_test_common TYPE STATIC SRCS ${COMMON_SOURCES}) -target_include_directories(test_common PRIVATE ${UMF_CMAKE_SOURCE_DIR}/include) +target_include_directories(umf_test_common + PRIVATE ${UMF_CMAKE_SOURCE_DIR}/include) From a52dc0fc30c3cb0ab598ac5b07dd47d984915407 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Fri, 2 Aug 2024 13:10:33 +0200 Subject: [PATCH 029/352] Fix or add missing include guards Add UMF_ prefix, where missing. In bench, tests, and examples use UMF_X_ prefix. --- benchmark/multithread.hpp | 5 +++++ examples/common/utils_level_zero.h | 5 +++++ src/cpp_helpers.hpp | 6 +++--- src/critnib/critnib.h | 8 ++++---- src/utils/utils_math.h | 7 ++++++- test/common/base.hpp | 2 +- test/common/ipc_common.h | 6 +++--- test/common/ipc_os_prov_common.h | 6 +++--- test/common/multithread_helpers.hpp | 5 +++++ test/common/numa_helpers.h | 6 +++--- test/common/pool.hpp | 2 +- test/common/pool_null.h | 8 ++++---- test/common/pool_trace.h | 8 ++++---- test/common/provider_null.h | 8 ++++---- test/common/provider_trace.h | 8 ++++---- test/fuzz/utils.hpp | 5 +++++ test/memspaces/memspace_fixtures.hpp | 7 ++++--- test/memspaces/memspace_helpers.hpp | 6 +++--- test/providers/ipc_level_zero_prov_common.h | 6 +++--- test/providers/level_zero_helpers.h | 6 +++--- 20 files changed, 73 insertions(+), 47 deletions(-) diff --git a/benchmark/multithread.hpp b/benchmark/multithread.hpp index 3eac38a2d..e642d2987 100644 --- a/benchmark/multithread.hpp +++ b/benchmark/multithread.hpp @@ -7,6 +7,9 @@ * */ +#ifndef UMF_BENCH_MULTITHREAD_HPP +#define UMF_BENCH_MULTITHREAD_HPP + #include #include #include @@ -87,3 +90,5 @@ template double std_dev(const std::vector &values) { } } // namespace umf_bench + +#endif /* UMF_BENCH_MULTITHREAD_HPP */ diff --git a/examples/common/utils_level_zero.h b/examples/common/utils_level_zero.h index 8786e7dea..46f892278 100644 --- a/examples/common/utils_level_zero.h +++ b/examples/common/utils_level_zero.h @@ -7,6 +7,9 @@ * */ +#ifndef UMF_EXAMPLE_UTILS_LEVEL_ZERO_H +#define UMF_EXAMPLE_UTILS_LEVEL_ZERO_H + #include #include @@ -412,3 +415,5 @@ int destroy_context(ze_context_handle_t context) { return 0; } + +#endif // UMF_EXAMPLE_UTILS_LEVEL_ZERO_H diff --git a/src/cpp_helpers.hpp b/src/cpp_helpers.hpp index 2145a7df4..86204a20e 100644 --- a/src/cpp_helpers.hpp +++ b/src/cpp_helpers.hpp @@ -7,8 +7,8 @@ * */ -#ifndef UMF_HELPERS_H -#define UMF_HELPERS_H 1 +#ifndef UMF_HELPERS_HPP +#define UMF_HELPERS_HPP 1 #include #include @@ -164,4 +164,4 @@ template umf_result_t &getPoolLastStatusRef() { } // namespace umf -#endif /* UMF_HELPERS_H */ +#endif /* UMF_HELPERS_HPP */ diff --git a/src/critnib/critnib.h b/src/critnib/critnib.h index 868622ea5..e03780374 100644 --- a/src/critnib/critnib.h +++ b/src/critnib/critnib.h @@ -1,14 +1,14 @@ /* * - * Copyright (C) 2023 Intel Corporation + * 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 CRITNIB_H -#define CRITNIB_H 1 +#ifndef UMF_CRITNIB_H +#define UMF_CRITNIB_H 1 #include @@ -44,4 +44,4 @@ void critnib_iter(critnib *c, uintptr_t min, uintptr_t max, } #endif -#endif +#endif // UMF_CRITNIB_H diff --git a/src/utils/utils_math.h b/src/utils/utils_math.h index 636ffa35d..c78be1136 100644 --- a/src/utils/utils_math.h +++ b/src/utils/utils_math.h @@ -1,12 +1,15 @@ /* * - * Copyright (C) 2023 Intel Corporation + * 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_MATH_H +#define UMF_MATH_H 1 + #include #include @@ -22,3 +25,5 @@ static inline size_t log2Utils(size_t num) { return getLeftmostSetBitPos(num); } #ifdef __cplusplus } #endif + +#endif /* UMF_MATH_H */ diff --git a/test/common/base.hpp b/test/common/base.hpp index e58bc35b1..8f2d5f6be 100644 --- a/test/common/base.hpp +++ b/test/common/base.hpp @@ -1,6 +1,6 @@ /* * - * Copyright (C) 2023 Intel Corporation + * 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 diff --git a/test/common/ipc_common.h b/test/common/ipc_common.h index f51a90b46..a73b01435 100644 --- a/test/common/ipc_common.h +++ b/test/common/ipc_common.h @@ -5,8 +5,8 @@ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ -#ifndef IPC_COMMON_H -#define IPC_COMMON_H +#ifndef UMF_TEST_IPC_COMMON_H +#define UMF_TEST_IPC_COMMON_H #include @@ -24,4 +24,4 @@ int run_consumer(int port, umf_memory_provider_ops_t *provider_ops, void *provider_params, memcopy_callback_t memcopy_callback, void *memcopy_ctx); -#endif // IPC_COMMON_H +#endif // UMF_TEST_IPC_COMMON_H diff --git a/test/common/ipc_os_prov_common.h b/test/common/ipc_os_prov_common.h index adcb27e0a..386c9658d 100644 --- a/test/common/ipc_os_prov_common.h +++ b/test/common/ipc_os_prov_common.h @@ -5,11 +5,11 @@ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ -#ifndef IPC_OS_PROV_COMMON_H -#define IPC_OS_PROV_COMMON_H +#ifndef UMF_TEST_IPC_OS_PROV_COMMON_H +#define UMF_TEST_IPC_OS_PROV_COMMON_H #include void memcopy(void *dst, const void *src, size_t size, void *context); -#endif // IPC_OS_PROV_COMMON_H +#endif // UMF_TEST_IPC_OS_PROV_COMMON_H diff --git a/test/common/multithread_helpers.hpp b/test/common/multithread_helpers.hpp index 28b91d8ed..500705b92 100644 --- a/test/common/multithread_helpers.hpp +++ b/test/common/multithread_helpers.hpp @@ -7,6 +7,9 @@ * */ +#ifndef UMF_TEST_MULTITHREAD_HELPERS_HPP +#define UMF_TEST_MULTITHREAD_HELPERS_HPP + #include #include #include @@ -84,3 +87,5 @@ struct syncthreads_barrier { }; } // namespace umf_test + +#endif /* UMF_TEST_MULTITHREAD_HELPERS_HPP */ diff --git a/test/common/numa_helpers.h b/test/common/numa_helpers.h index 960d2e850..aa9888fea 100644 --- a/test/common/numa_helpers.h +++ b/test/common/numa_helpers.h @@ -2,8 +2,8 @@ // Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#ifndef UMF_NUMA_HELPERS_H -#define UMF_NUMA_HELPERS_H 1 +#ifndef UMF_TEST_NUMA_HELPERS_H +#define UMF_TEST_NUMA_HELPERS_H 1 #include #include @@ -31,4 +31,4 @@ int getNumaNodeByPtr(void *ptr) { } #endif -#endif /* UMF_NUMA_HELPERS_H */ +#endif /* UMF_TEST_NUMA_HELPERS_H */ diff --git a/test/common/pool.hpp b/test/common/pool.hpp index 556e9d23c..9a5739085 100644 --- a/test/common/pool.hpp +++ b/test/common/pool.hpp @@ -1,6 +1,6 @@ /* * - * Copyright (C) 2023 Intel Corporation + * 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 diff --git a/test/common/pool_null.h b/test/common/pool_null.h index 5130dfcd8..2a5a14d75 100644 --- a/test/common/pool_null.h +++ b/test/common/pool_null.h @@ -1,9 +1,9 @@ -// Copyright (C) 2023 Intel Corporation +// 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_NULL_POOL_H -#define UMF_NULL_POOL_H +#ifndef UMF_TEST_NULL_POOL_H +#define UMF_TEST_NULL_POOL_H #include @@ -17,4 +17,4 @@ extern umf_memory_pool_ops_t UMF_NULL_POOL_OPS; } #endif -#endif // UMF_NULL_POOL_H +#endif // UMF_TEST_NULL_POOL_H diff --git a/test/common/pool_trace.h b/test/common/pool_trace.h index 79f4d5eba..c49d61107 100644 --- a/test/common/pool_trace.h +++ b/test/common/pool_trace.h @@ -1,9 +1,9 @@ -// Copyright (C) 2023 Intel Corporation +// 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_TRACE_POOL_H -#define UMF_TRACE_POOL_H +#ifndef UMF_TEST_TRACE_POOL_H +#define UMF_TEST_TRACE_POOL_H #include @@ -24,4 +24,4 @@ extern umf_memory_pool_ops_t UMF_TRACE_POOL_OPS; } #endif -#endif // UMF_TRACE_POOL_H +#endif // UMF_TEST_TRACE_POOL_H diff --git a/test/common/provider_null.h b/test/common/provider_null.h index d7dab9cb7..fa7f2f6db 100644 --- a/test/common/provider_null.h +++ b/test/common/provider_null.h @@ -1,9 +1,9 @@ -// Copyright (C) 2023 Intel Corporation +// 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_NULL_PROVIDER_H -#define UMF_NULL_PROVIDER_H +#ifndef UMF_TEST_NULL_PROVIDER_H +#define UMF_TEST_NULL_PROVIDER_H #include @@ -17,4 +17,4 @@ extern umf_memory_provider_ops_t UMF_NULL_PROVIDER_OPS; } #endif -#endif // UMF_NULL_PROVIDER_H +#endif // UMF_TEST_NULL_PROVIDER_H diff --git a/test/common/provider_trace.h b/test/common/provider_trace.h index bb1bbd33c..f0f2a367b 100644 --- a/test/common/provider_trace.h +++ b/test/common/provider_trace.h @@ -1,9 +1,9 @@ -// Copyright (C) 2023 Intel Corporation +// 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_TRACE_PROVIDER_H -#define UMF_TRACE_PROVIDER_H +#ifndef UMF_TEST_TRACE_PROVIDER_H +#define UMF_TEST_TRACE_PROVIDER_H #include @@ -27,4 +27,4 @@ extern umf_memory_provider_ops_t UMF_TRACE_PROVIDER_OPS; } #endif -#endif // UMF_TRACE_PROVIDER_H +#endif // UMF_TEST_TRACE_PROVIDER_H diff --git a/test/fuzz/utils.hpp b/test/fuzz/utils.hpp index ec1dda700..645353fb2 100644 --- a/test/fuzz/utils.hpp +++ b/test/fuzz/utils.hpp @@ -2,6 +2,9 @@ // Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#ifndef UMF_TEST_FUZZ_UTILS_HPP +#define UMF_TEST_FUZZ_UTILS_HPP + #include "umf/pools/pool_scalable.h" #include "umf/providers/provider_os_memory.h" #include @@ -75,3 +78,5 @@ struct TestState { } }; } // namespace fuzz + +#endif /* UMF_TEST_FUZZ_UTILS_HPP */ diff --git a/test/memspaces/memspace_fixtures.hpp b/test/memspaces/memspace_fixtures.hpp index d408a1352..fac50b031 100644 --- a/test/memspaces/memspace_fixtures.hpp +++ b/test/memspaces/memspace_fixtures.hpp @@ -2,8 +2,9 @@ // Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#ifndef UMF_MEMSPACE_FIXTURES_HPP -#define UMF_MEMSPACE_FIXTURES_HPP +#ifndef UMF_TEST_MEMSPACE_FIXTURES_HPP +#define UMF_TEST_MEMSPACE_FIXTURES_HPP + #include #include #include @@ -218,4 +219,4 @@ TEST_P(memspaceProviderTest, allocLocalMt) { } } -#endif /* UMF_MEMSPACE_FIXTURES_HPP */ +#endif /* UMF_TEST_MEMSPACE_FIXTURES_HPP */ diff --git a/test/memspaces/memspace_helpers.hpp b/test/memspaces/memspace_helpers.hpp index a789f0c3e..1adee2607 100644 --- a/test/memspaces/memspace_helpers.hpp +++ b/test/memspaces/memspace_helpers.hpp @@ -2,8 +2,8 @@ // Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#ifndef UMF_MEMSPACE_HELPERS_HPP -#define UMF_MEMSPACE_HELPERS_HPP +#ifndef UMF_TEST_MEMSPACE_HELPERS_HPP +#define UMF_TEST_MEMSPACE_HELPERS_HPP #include "base.hpp" #include "memspace_internal.h" @@ -56,4 +56,4 @@ void getAllocationPolicy(void *ptr, unsigned long maxNodeId, int &mode, allocNodeId = static_cast(nodeId); } -#endif /* UMF_MEMSPACE_HELPERS_HPP */ +#endif /* UMF_TEST_MEMSPACE_HELPERS_HPP */ diff --git a/test/providers/ipc_level_zero_prov_common.h b/test/providers/ipc_level_zero_prov_common.h index fdfdeba6d..dff51d08b 100644 --- a/test/providers/ipc_level_zero_prov_common.h +++ b/test/providers/ipc_level_zero_prov_common.h @@ -5,11 +5,11 @@ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ -#ifndef IPC_LEVEL_ZERO_PROV_COMMON_H -#define IPC_LEVEL_ZERO_PROV_COMMON_H +#ifndef UMF_TEST_IPC_LEVEL_ZERO_PROV_COMMON_H +#define UMF_TEST_IPC_LEVEL_ZERO_PROV_COMMON_H #include void memcopy(void *dst, const void *src, size_t size, void *context); -#endif // IPC_LEVEL_ZERO_PROV_COMMON_H +#endif // UMF_TEST_IPC_LEVEL_ZERO_PROV_COMMON_H diff --git a/test/providers/level_zero_helpers.h b/test/providers/level_zero_helpers.h index 2bb8261d5..6cd452c1c 100644 --- a/test/providers/level_zero_helpers.h +++ b/test/providers/level_zero_helpers.h @@ -5,8 +5,8 @@ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ -#ifndef TEST_COMMON_LEVEL_ZERO_HELPERS_HPP -#define TEST_COMMON_LEVEL_ZERO_HELPERS_HPP +#ifndef UMF_TEST_LEVEL_ZERO_HELPERS_H +#define UMF_TEST_LEVEL_ZERO_HELPERS_H #include @@ -45,4 +45,4 @@ create_level_zero_prov_params(umf_usm_memory_type_t memory_type); } #endif -#endif // TEST_COMMON_LEVEL_ZERO_HELPERS_HPP +#endif // UMF_TEST_LEVEL_ZERO_HELPERS_H From 1a47f1137367f9c4935e8f8418546cf40df169f7 Mon Sep 17 00:00:00 2001 From: Igor Chorazewicz Date: Fri, 2 Aug 2024 20:59:34 +0000 Subject: [PATCH 030/352] Disable opencl, cuda and nvml when configuring hwloc Without explicitly disabling them and if a system where hwloc is being build has opencl/cuda/nvml installed those libraries will become hwloc dependencies which would force umf to link with them. The problem manifested on a system where opencl was installed and umf compilation failed due to missing clGetDevices symbol. --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 70b99aaf2..e366726fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -173,7 +173,8 @@ elseif(NOT UMF_DISABLE_HWLOC) COMMAND ./configure --prefix=${hwloc_targ_BINARY_DIR} --enable-static=yes --enable-shared=no --disable-libxml2 --disable-levelzero - CFLAGS=-fPIC CXXFLAGS=-fPIC + --disable-opencl --disable-cuda --disable-nvml CFLAGS=-fPIC + CXXFLAGS=-fPIC WORKING_DIRECTORY ${hwloc_targ_SOURCE_DIR} OUTPUT ${hwloc_targ_SOURCE_DIR}/Makefile DEPENDS ${hwloc_targ_SOURCE_DIR}/configure) From 3b7b3691a3c3dfad9a7232974d44616971b9b5af Mon Sep 17 00:00:00 2001 From: Rafal Rudnicki Date: Mon, 5 Aug 2024 11:44:30 +0200 Subject: [PATCH 031/352] add googletest to 3rd party programs --- licensing/third-party-programs.txt | 34 ++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/licensing/third-party-programs.txt b/licensing/third-party-programs.txt index 4adbd8cf6..54520c141 100644 --- a/licensing/third-party-programs.txt +++ b/licensing/third-party-programs.txt @@ -386,6 +386,40 @@ _______________________________________________________________________________ and prospectively choose to deem waived or otherwise exclude such Section(s) of the License, but only in their entirety and only with respect to the Combined Software. + +_______________________________________________________________________________ + +7. googletest: + + Copyright 2008, Google Inc. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + _______________________________________________________________________________ *Other names and brands may be claimed as the property of others. From 66198258d1081b6b0e0d13084a5a342d193b8dbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Tue, 6 Aug 2024 09:43:40 +0200 Subject: [PATCH 032/352] [CI] enable new runners for some of jobs --- .github/workflows/bandit.yml | 2 +- .github/workflows/docs.yml | 7 +++++-- .github/workflows/fast.yml | 2 +- .github/workflows/pr_push.yml | 7 +++++-- .github/workflows/proxy_lib.yml | 3 +-- .github/workflows/spellcheck.yml | 2 +- .github/workflows/trivy.yml | 2 +- 7 files changed, 15 insertions(+), 10 deletions(-) diff --git a/.github/workflows/bandit.yml b/.github/workflows/bandit.yml index 80b383665..acb64034b 100644 --- a/.github/workflows/bandit.yml +++ b/.github/workflows/bandit.yml @@ -19,7 +19,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest] - runs-on: ${{matrix.os}} + runs-on: ${{ (matrix.os == 'ubuntu-latest' && github.repository_owner == 'oneapi-src') && 'intel-ubuntu-22.04' || matrix.os }} steps: - name: Checkout repository diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 4fdd89766..6e128b603 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -16,7 +16,7 @@ permissions: jobs: build: name: Build docs - runs-on: ubuntu-latest + runs-on: ${{ github.repository_owner == 'oneapi-src' && 'intel-ubuntu-22.04' || 'ubuntu-latest' }} steps: - name: Checkout repository @@ -32,6 +32,9 @@ jobs: - name: Install pip requirements run: python3 -m pip install -r third_party/requirements.txt + - name: Setup PATH for python + run: echo "$HOME/.local/bin" >> $GITHUB_PATH + - name: Build the documentation working-directory: scripts run: python3 generate_docs.py @@ -53,7 +56,7 @@ jobs: name: github-pages url: ${{ steps.deployment.outputs.page_url }} - runs-on: ubuntu-latest + runs-on: ${{ github.repository_owner == 'oneapi-src' && 'intel-ubuntu-22.04' || 'ubuntu-latest' }} steps: - name: Deploy the documentation to GitHub Pages diff --git a/.github/workflows/fast.yml b/.github/workflows/fast.yml index a42f0b694..3bf8e5248 100644 --- a/.github/workflows/fast.yml +++ b/.github/workflows/fast.yml @@ -54,7 +54,7 @@ jobs: build_tests: 'ON' extra_build_options: '-DCMAKE_BUILD_TYPE=Release' simple_cmake: 'ON' - runs-on: ${{matrix.os}} + runs-on: ${{ (matrix.os == 'ubuntu-latest' && github.repository_owner == 'oneapi-src') && 'intel-ubuntu-22.04' || matrix.os }} steps: - name: Checkout repository diff --git a/.github/workflows/pr_push.yml b/.github/workflows/pr_push.yml index c35664a56..c42d6e098 100644 --- a/.github/workflows/pr_push.yml +++ b/.github/workflows/pr_push.yml @@ -17,7 +17,7 @@ permissions: jobs: CodeStyle: name: Coding style - runs-on: ubuntu-latest + runs-on: ${{ github.repository_owner == 'oneapi-src' && 'intel-ubuntu-22.04' || 'ubuntu-latest' }} steps: - name: Checkout repository @@ -52,7 +52,7 @@ jobs: DocsBuild: name: Build docs - runs-on: ubuntu-latest + runs-on: ${{ github.repository_owner == 'oneapi-src' && 'intel-ubuntu-22.04' || 'ubuntu-latest' }} steps: - name: Checkout repository @@ -68,6 +68,9 @@ jobs: - name: Install pip requirements run: python3 -m pip install -r third_party/requirements.txt + - name: Setup PATH for python + run: echo "$HOME/.local/bin" >> $GITHUB_PATH + - name: Build the documentation working-directory: scripts run: python3 generate_docs.py diff --git a/.github/workflows/proxy_lib.yml b/.github/workflows/proxy_lib.yml index 8d73569f0..80ac75e89 100644 --- a/.github/workflows/proxy_lib.yml +++ b/.github/workflows/proxy_lib.yml @@ -16,11 +16,10 @@ jobs: strategy: matrix: - os: ['ubuntu-22.04'] build_type: [Release, Debug] compiler: [{c: gcc, cxx: g++}] proxy_lib_pool: ['SCALABLE', 'JEMALLOC'] - runs-on: ${{matrix.os}} + runs-on: ${{ github.repository_owner == 'oneapi-src' && 'intel-ubuntu-22.04' || 'ubuntu-22.04' }} steps: - name: Checkout diff --git a/.github/workflows/spellcheck.yml b/.github/workflows/spellcheck.yml index 07265fc17..dbd6f1c8e 100644 --- a/.github/workflows/spellcheck.yml +++ b/.github/workflows/spellcheck.yml @@ -9,7 +9,7 @@ permissions: jobs: analyze: name: Run spell check - runs-on: ubuntu-latest + runs-on: ${{ github.repository_owner == 'oneapi-src' && 'intel-ubuntu-22.04' || 'ubuntu-latest' }} steps: - name: Checkout diff --git a/.github/workflows/trivy.yml b/.github/workflows/trivy.yml index 1c3e63120..21a76d0cd 100644 --- a/.github/workflows/trivy.yml +++ b/.github/workflows/trivy.yml @@ -24,7 +24,7 @@ permissions: jobs: trivy: name: Trivy - runs-on: ubuntu-latest + runs-on: ${{ github.repository_owner == 'oneapi-src' && 'intel-ubuntu-22.04' || 'ubuntu-latest' }} permissions: security-events: write From d421990974190c3d7682c375227d414f0fb3f77d Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Thu, 8 Aug 2024 10:38:14 +0200 Subject: [PATCH 033/352] [CI] Run Coverity only on upstream Run Coverity only on upstream. Forks do not know Username/Password. Signed-off-by: Lukasz Dorau --- .github/workflows/coverity.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml index f6fe2ad26..dfa03fc4f 100644 --- a/.github/workflows/coverity.yml +++ b/.github/workflows/coverity.yml @@ -18,6 +18,8 @@ permissions: jobs: coverity: name: Coverity + # run only on upstream; forks do not know Username/Password + if: github.repository == 'oneapi-src/unified-memory-framework' runs-on: ubuntu-latest steps: - name: Checkout repository From 80e6459d2c644e33ec08d545f9772c76f40fc021 Mon Sep 17 00:00:00 2001 From: Agata Momot Date: Tue, 23 Jul 2024 14:48:32 +0200 Subject: [PATCH 034/352] fix: skip tests requiring NUMA if NUMA is not supported Substitute GTEST_FAIL() with GTEST_SKIP() or add GTEST_SKIP(). Remove UT_ASSERTs checking for NUMA. Enable skipping tests in CMakeLists.txt. Add UMF_TEST_SKIP_RETURN_CODE (=125) to CMakeLists.txt. Add test_skip_error_code (=125) to helper header files for examples and tests. Allow uninstantiated tests in /test/provider_os_memory_multiple_numa_nodes.cpp. Make get_available_numa_nodes() return an empty vector in the environment without NUMA. Fixes: #635 Signed-off-by: Agata Momot --- examples/CMakeLists.txt | 20 ++++++++++---- examples/common/utils_examples.h | 16 ++++++++++++ examples/memspace/memspace_hmat.c | 7 +++-- examples/memspace/memspace_numa.c | 4 ++- test/common/test_helpers.h | 3 +++ test/memspaces/memspace_fixtures.hpp | 6 ++++- test/memspaces/memspace_numa.cpp | 8 ++++++ ...provider_os_memory_multiple_numa_nodes.cpp | 26 +++++++++++++++---- 8 files changed, 74 insertions(+), 16 deletions(-) create mode 100644 examples/common/utils_examples.h diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index d06e51755..8b61c82a5 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -167,6 +167,8 @@ else() endif() if(LINUX) + set(UMF_TEST_SKIP_RETURN_CODE 125) + set(EXAMPLE_NAME umf_example_memspace_numa) add_umf_executable( @@ -175,8 +177,10 @@ if(LINUX) LIBS umf ${LIBHWLOC_LIBRARIES} numa) target_include_directories( - ${EXAMPLE_NAME} PRIVATE ${UMF_CMAKE_SOURCE_DIR}/src/utils - ${UMF_CMAKE_SOURCE_DIR}/include) + ${EXAMPLE_NAME} + PRIVATE ${UMF_CMAKE_SOURCE_DIR}/src/utils + ${UMF_CMAKE_SOURCE_DIR}/include + ${UMF_CMAKE_SOURCE_DIR}/examples/common) target_link_directories(${EXAMPLE_NAME} PRIVATE ${LIBHWLOC_LIBRARY_DIRS}) @@ -185,6 +189,9 @@ if(LINUX) COMMAND ${EXAMPLE_NAME} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + set_tests_properties(${EXAMPLE_NAME} PROPERTIES + SKIP_RETURN_CODE ${UMF_TEST_SKIP_RETURN_CODE}) + set(EXAMPLE_NAME umf_example_memspace_hmat) add_umf_executable( @@ -193,8 +200,10 @@ if(LINUX) LIBS umf ${LIBHWLOC_LIBRARIES} numa) target_include_directories( - ${EXAMPLE_NAME} PRIVATE ${UMF_CMAKE_SOURCE_DIR}/src/utils - ${UMF_CMAKE_SOURCE_DIR}/include) + ${EXAMPLE_NAME} + PRIVATE ${UMF_CMAKE_SOURCE_DIR}/src/utils + ${UMF_CMAKE_SOURCE_DIR}/include + ${UMF_CMAKE_SOURCE_DIR}/examples/common) target_link_directories(${EXAMPLE_NAME} PRIVATE ${LIBHWLOC_LIBRARY_DIRS}) @@ -203,7 +212,8 @@ if(LINUX) COMMAND ${EXAMPLE_NAME} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - set_tests_properties(${EXAMPLE_NAME} PROPERTIES SKIP_RETURN_CODE 125) + set_tests_properties(${EXAMPLE_NAME} PROPERTIES + SKIP_RETURN_CODE ${UMF_TEST_SKIP_RETURN_CODE}) set(EXAMPLE_NAME umf_example_file_provider) add_umf_executable( diff --git a/examples/common/utils_examples.h b/examples/common/utils_examples.h new file mode 100644 index 000000000..9e4a93bcf --- /dev/null +++ b/examples/common/utils_examples.h @@ -0,0 +1,16 @@ +/* + * + * Copyright (C) 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_EXAMPLE_UTILS_H +#define UMF_EXAMPLE_UTILS_H + +// Needed for CI +#define TEST_SKIP_ERROR_CODE 125 + +#endif /* UMF_EXAMPLE_UTILS_H */ diff --git a/examples/memspace/memspace_hmat.c b/examples/memspace/memspace_hmat.c index 64d869e73..1a4cf154e 100644 --- a/examples/memspace/memspace_hmat.c +++ b/examples/memspace/memspace_hmat.c @@ -15,8 +15,7 @@ #include #include -// Needed for CI -#define test_skip_error_code 125 +#include "utils_examples.h" // Function to create a memory provider which allocates memory from the specified NUMA node int createMemoryProvider(umf_memory_provider_handle_t *hProvider, @@ -63,13 +62,13 @@ int main(void) { // Check if NUMA is available if (numa_available() < 0) { fprintf(stderr, "NUMA is not available on this system.\n"); - return -1; + return TEST_SKIP_ERROR_CODE; } // Create the memory provider that allocates memory from the highest bandwidth numa nodes ret = createMemoryProvider(&hProvider, umfMemspaceHighestBandwidthGet()); if (ret != UMF_RESULT_SUCCESS) { - return ret == 1 ? test_skip_error_code : -1; + return ret == 1 ? TEST_SKIP_ERROR_CODE : -1; } // Allocate memory from the memory provider diff --git a/examples/memspace/memspace_numa.c b/examples/memspace/memspace_numa.c index 7d328d4a0..8116825ed 100644 --- a/examples/memspace/memspace_numa.c +++ b/examples/memspace/memspace_numa.c @@ -15,6 +15,8 @@ #include #include +#include "utils_examples.h" + // Function to create a memory provider which allocates memory from the specified NUMA node int createMemoryProvider(umf_memory_provider_handle_t *hProvider, unsigned numa) { @@ -65,7 +67,7 @@ int main(void) { // Check if NUMA is available if (numa_available() < 0) { fprintf(stderr, "NUMA is not available on this system.\n"); - return -1; + return TEST_SKIP_ERROR_CODE; } // Create the memory provider that allocates memory from the specified NUMA node diff --git a/test/common/test_helpers.h b/test/common/test_helpers.h index e361feba4..df4c3c235 100644 --- a/test/common/test_helpers.h +++ b/test/common/test_helpers.h @@ -19,6 +19,9 @@ extern "C" { #endif +// Needed for CI +#define TEST_SKIP_ERROR_CODE 125 + static inline void UT_FATAL(const char *format, ...) { va_list args_list; va_start(args_list, format); diff --git a/test/memspaces/memspace_fixtures.hpp b/test/memspaces/memspace_fixtures.hpp index fac50b031..5aaaed787 100644 --- a/test/memspaces/memspace_fixtures.hpp +++ b/test/memspaces/memspace_fixtures.hpp @@ -30,7 +30,7 @@ struct numaNodesTest : ::umf_test::test { ::umf_test::test::SetUp(); if (numa_available() == -1 || numa_all_nodes_ptr == nullptr) { - GTEST_FAIL() << "Failed to initialize libnuma"; + GTEST_SKIP() << "No available NUMA support; skipped"; } int maxNode = numa_max_node(); @@ -59,6 +59,10 @@ struct memspaceGetTest : ::numaNodesTest, void SetUp() override { ::numaNodesTest::SetUp(); + if (numa_available() == -1 || numa_all_nodes_ptr == nullptr) { + GTEST_SKIP() << "No available NUMA support; skipped"; + } + auto [isQuerySupported, memspaceGet] = this->GetParam(); if (!isQuerySupported(nodeIds.front())) { diff --git a/test/memspaces/memspace_numa.cpp b/test/memspaces/memspace_numa.cpp index c8485fadc..180efd9c2 100644 --- a/test/memspaces/memspace_numa.cpp +++ b/test/memspaces/memspace_numa.cpp @@ -14,6 +14,10 @@ struct memspaceNumaTest : ::numaNodesTest { void SetUp() override { ::numaNodesTest::SetUp(); + if (numa_available() == -1) { + GTEST_SKIP() << "NUMA not supported on this system; test skipped"; + } + umf_result_t ret = umfMemspaceCreateFromNumaArray( nodeIds.data(), nodeIds.size(), &hMemspace); ASSERT_EQ(ret, UMF_RESULT_SUCCESS); @@ -34,6 +38,10 @@ struct memspaceNumaProviderTest : ::memspaceNumaTest { void SetUp() override { ::memspaceNumaTest::SetUp(); + if (numa_available() == -1) { + GTEST_SKIP() << "NUMA not supported on this system; test skipped"; + } + umf_result_t ret = umfMemoryProviderCreateFromMemspace(hMemspace, nullptr, &hProvider); ASSERT_EQ(ret, UMF_RESULT_SUCCESS); diff --git a/test/provider_os_memory_multiple_numa_nodes.cpp b/test/provider_os_memory_multiple_numa_nodes.cpp index 0f7f0fb2e..91f269e44 100644 --- a/test/provider_os_memory_multiple_numa_nodes.cpp +++ b/test/provider_os_memory_multiple_numa_nodes.cpp @@ -18,8 +18,9 @@ static umf_os_memory_provider_params_t UMF_OS_MEMORY_PROVIDER_PARAMS_TEST = umfOsMemoryProviderParamsDefault(); std::vector get_available_numa_nodes() { - UT_ASSERTne(numa_available(), -1); - UT_ASSERTne(numa_all_nodes_ptr, nullptr); + if (numa_available() == -1 || numa_all_nodes_ptr == nullptr) { + return std::vector(); + } std::vector available_numa_nodes; // Get all available NUMA nodes numbers. @@ -57,9 +58,6 @@ std::vector get_available_cpus() { } void set_all_available_nodemask_bits(bitmask *nodemask) { - UT_ASSERTne(numa_available(), -1); - UT_ASSERTne(numa_all_nodes_ptr, nullptr); - numa_bitmask_clearall(nodemask); // Set all available NUMA nodes numbers. @@ -124,6 +122,24 @@ struct testNuma : testing::Test { struct testNumaOnEachNode : testNuma, testing::WithParamInterface {}; struct testNumaOnEachCpu : testNuma, testing::WithParamInterface {}; +/* + - In case of the lack of support for NUMA on the system + get_available_numa_nodes() returns an empty vector + - Then in INSTANTIATE_TEST_SUITE_P an empty container is passed as the 3rd arg + (param_generator) + - Therefore INSTANTIATE_TEST_SUITE_P expands to nothing, which causes the test + to fail in the test suite GoogleTestVerification +- GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(testNumaOnEachNode) allows the +test suite testNumaOnEachNode to be uninstantiated, suppressing +the test failure +- Additionally, the fixture testNumaOnEachNode uses SetUp from testNuma before +running every test, thus the test is eventually skipped when the lack of NUMA +support is determined by numa_available() +- (Therefore probably a vector with dummy values could be returned instead of +using the macro) +*/ +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(testNumaOnEachNode); + INSTANTIATE_TEST_SUITE_P(testNumaNodesAllocations, testNumaOnEachNode, ::testing::ValuesIn(get_available_numa_nodes())); From 892f752fa674cca90b634845b6e81cf061c2d65c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Plewa?= Date: Wed, 24 Jul 2024 16:06:44 +0200 Subject: [PATCH 035/352] export MemtarGetCapacity --- include/umf/memtarget.h | 8 +++++++ src/libumf.def.in | 1 + src/libumf.map.in | 1 + src/memspace.c | 6 ++---- src/memspace_internal.h | 3 ++- src/memtarget.c | 2 +- src/memtarget_internal.h | 3 +-- test/CMakeLists.txt | 2 +- test/memspaces/memtarget.cpp | 41 ++++++++++++++++++++++++++++++++++-- 9 files changed, 56 insertions(+), 11 deletions(-) diff --git a/include/umf/memtarget.h b/include/umf/memtarget.h index 2a7850015..a4902b98d 100644 --- a/include/umf/memtarget.h +++ b/include/umf/memtarget.h @@ -10,6 +10,7 @@ #ifndef UMF_MEMTARGET_H #define UMF_MEMTARGET_H 1 +#include #include #ifdef __cplusplus @@ -31,6 +32,13 @@ typedef enum umf_memtarget_type_t { umf_result_t umfMemtargetGetType(umf_const_memtarget_handle_t hMemtarget, umf_memtarget_type_t *type); +/// \brief Get size of the memory target in bytes. +/// \param hMemtarget handle to the memory target +/// \param capacity [out] capacity of the memory target +/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfMemtargetGetCapacity(umf_const_memtarget_handle_t hMemtarget, + size_t *capacity); + #ifdef __cplusplus } #endif diff --git a/src/libumf.def.in b/src/libumf.def.in index cb8d4d74c..f69d7ac1a 100644 --- a/src/libumf.def.in +++ b/src/libumf.def.in @@ -43,6 +43,7 @@ EXPORTS umfMemspaceDestroy umfMemspaceMemtargetNum umfMemspaceMemtargetGet + umfMemtargetGetCapacity umfMemtargetGetType umfOpenIPCHandle umfPoolAlignedMalloc diff --git a/src/libumf.map.in b/src/libumf.map.in index 7c2002a1f..09be6dfe9 100644 --- a/src/libumf.map.in +++ b/src/libumf.map.in @@ -37,6 +37,7 @@ UMF_1.0 { umfMemspaceDestroy; umfMemspaceMemtargetNum; umfMemspaceMemtargetGet; + umfMemtargetGetCapacity; umfMemtargetGetType; umfOpenIPCHandle; umfPoolAlignedMalloc; diff --git a/src/memspace.c b/src/memspace.c index 01e20e617..bce5fb6ee 100644 --- a/src/memspace.c +++ b/src/memspace.c @@ -173,10 +173,8 @@ static int propertyCmp(const void *a, const void *b) { } } -umf_result_t -umfMemspaceSortDesc(umf_memspace_handle_t hMemspace, - umf_result_t (*getProperty)(umf_memtarget_handle_t node, - uint64_t *property)) { +umf_result_t umfMemspaceSortDesc(umf_memspace_handle_t hMemspace, + umfGetPropertyFn getProperty) { if (!hMemspace || !getProperty) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; } diff --git a/src/memspace_internal.h b/src/memspace_internal.h index 0cb28b92f..8f678ff7d 100644 --- a/src/memspace_internal.h +++ b/src/memspace_internal.h @@ -30,7 +30,8 @@ struct umf_memspace_t { umf_result_t umfMemspaceClone(umf_const_memspace_handle_t hMemspace, umf_memspace_handle_t *outHandle); -typedef umf_result_t (*umfGetPropertyFn)(umf_memtarget_handle_t, uint64_t *); +typedef umf_result_t (*umfGetPropertyFn)(umf_const_memtarget_handle_t, + uint64_t *); /// /// \brief Sorts memspace by getProperty() in descending order diff --git a/src/memtarget.c b/src/memtarget.c index 4c851a772..c85630769 100644 --- a/src/memtarget.c +++ b/src/memtarget.c @@ -76,7 +76,7 @@ umf_result_t umfMemtargetClone(umf_memtarget_handle_t memoryTarget, return UMF_RESULT_SUCCESS; } -umf_result_t umfMemtargetGetCapacity(umf_memtarget_handle_t memoryTarget, +umf_result_t umfMemtargetGetCapacity(umf_const_memtarget_handle_t memoryTarget, size_t *capacity) { if (!memoryTarget || !capacity) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; diff --git a/src/memtarget_internal.h b/src/memtarget_internal.h index bad309723..2e1547e07 100644 --- a/src/memtarget_internal.h +++ b/src/memtarget_internal.h @@ -30,8 +30,7 @@ void umfMemtargetDestroy(umf_memtarget_handle_t memoryTarget); umf_result_t umfMemtargetClone(umf_memtarget_handle_t memoryTarget, umf_memtarget_handle_t *outHandle); -umf_result_t umfMemtargetGetCapacity(umf_memtarget_handle_t memoryTarget, - size_t *capacity); + umf_result_t umfMemtargetGetBandwidth(umf_memtarget_handle_t srcMemoryTarget, umf_memtarget_handle_t dstMemoryTarget, size_t *bandwidth); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 59c76fe31..962d1e126 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -221,7 +221,7 @@ if(LINUX AND (NOT UMF_DISABLE_HWLOC)) # OS-specific functions are implemented add_umf_test( NAME memtarget SRCS memspaces/memtarget.cpp - LIBS ${LIBNUMA_LIBRARIES}) + LIBS ${LIBNUMA_LIBRARIES} ${LIBHWLOC_LIBRARIES}) if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND UMF_BUILD_FUZZTESTS) add_subdirectory(fuzz) endif() diff --git a/test/memspaces/memtarget.cpp b/test/memspaces/memtarget.cpp index 84001a705..c4cc80a8f 100644 --- a/test/memspaces/memtarget.cpp +++ b/test/memspaces/memtarget.cpp @@ -2,6 +2,7 @@ // Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include "memspace_fixtures.hpp" #include "memspace_helpers.hpp" #include @@ -13,17 +14,53 @@ using umf_test::test; TEST_F(test, memTargetNuma) { auto memspace = umfMemspaceHostAllGet(); ASSERT_NE(memspace, nullptr); - + umf_memtarget_type_t type; for (size_t i = 0; i < umfMemspaceMemtargetNum(memspace); i++) { auto hTarget = umfMemspaceMemtargetGet(memspace, i); ASSERT_NE(hTarget, nullptr); - umf_memtarget_type_t type; auto ret = umfMemtargetGetType(hTarget, &type); EXPECT_EQ(ret, UMF_RESULT_SUCCESS); EXPECT_EQ(type, UMF_MEMTARGET_TYPE_NUMA); } } +TEST_F(numaNodesTest, getCapacity) { + auto memspace = umfMemspaceHostAllGet(); + ASSERT_NE(memspace, nullptr); + std::vector capacities; + for (auto nodeId : nodeIds) { + capacities.push_back(numa_node_size64(nodeId, nullptr)); + } + + for (size_t i = 0; i < umfMemspaceMemtargetNum(memspace); i++) { + auto hTarget = umfMemspaceMemtargetGet(memspace, i); + ASSERT_NE(hTarget, nullptr); + size_t capacity; + auto ret = umfMemtargetGetCapacity(hTarget, &capacity); + EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + auto it = std::find(capacities.begin(), capacities.end(), capacity); + EXPECT_NE(it, capacities.end()); + if (it != capacities.end()) { + capacities.erase(it); + } + } + ASSERT_EQ(capacities.size(), 0); +} + +TEST_F(numaNodesTest, getCapacityInvalid) { + auto memspace = umfMemspaceHostAllGet(); + ASSERT_NE(memspace, nullptr); + size_t capacity; + auto ret = umfMemtargetGetCapacity(NULL, &capacity); + EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + ret = umfMemtargetGetCapacity(NULL, NULL); + EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + auto hTarget = umfMemspaceMemtargetGet(memspace, 0); + ASSERT_NE(hTarget, nullptr); + ret = umfMemtargetGetCapacity(hTarget, NULL); + EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} + TEST_F(test, memTargetInvalid) { auto memspace = umfMemspaceHostAllGet(); ASSERT_NE(memspace, nullptr); From ecc3a0ab3846c8c7a4e1770941f9575f21e9b987 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Fri, 9 Aug 2024 12:33:34 +0200 Subject: [PATCH 036/352] Fix one comment in test/test_valgrind.sh Signed-off-by: Lukasz Dorau --- test/test_valgrind.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_valgrind.sh b/test/test_valgrind.sh index ed30e9ad6..ef314b3f7 100755 --- a/test/test_valgrind.sh +++ b/test/test_valgrind.sh @@ -86,7 +86,7 @@ for test in $(ls -1 umf_test-*); do case $test in umf_test-ipc_os_prov_*) echo "- SKIPPED" - continue; # skip it - this is a 2 processes test run using the ipc_os_prov_anon_fd.sh script + continue; # skip testing helper binaries used by the ipc_os_prov_* tests ;; umf_test-memspace_host_all) FILTER='--gtest_filter="-*allocsSpreadAcrossAllNumaNodes"' From d82a8a3d96835725020893f44d47ce98a456e471 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Plewa?= Date: Tue, 6 Aug 2024 18:34:00 +0200 Subject: [PATCH 037/352] refactor numanode assert in tests http://google.github.io/googletest/advanced.html#propagating-fatal-failures --- test/common/numa_helpers.h | 34 ------------ test/common/numa_helpers.hpp | 50 +++++++++++++++++ test/memspaces/memspace_highest_capacity.cpp | 7 ++- test/memspaces/memspace_host_all.cpp | 2 +- ...provider_os_memory_multiple_numa_nodes.cpp | 53 +++++++++---------- 5 files changed, 80 insertions(+), 66 deletions(-) delete mode 100644 test/common/numa_helpers.h create mode 100644 test/common/numa_helpers.hpp diff --git a/test/common/numa_helpers.h b/test/common/numa_helpers.h deleted file mode 100644 index aa9888fea..000000000 --- a/test/common/numa_helpers.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (C) 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_TEST_NUMA_HELPERS_H -#define UMF_TEST_NUMA_HELPERS_H 1 - -#include -#include -#include -#include - -#include "test_helpers.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// returns the node where page starting at 'ptr' resides -int getNumaNodeByPtr(void *ptr) { - int nodeId; - int retm = - get_mempolicy(&nodeId, nullptr, 0, ptr, MPOL_F_ADDR | MPOL_F_NODE); - UT_ASSERTeq(retm, 0); - UT_ASSERT(nodeId >= 0); - - return nodeId; -} - -#ifdef __cplusplus -} -#endif - -#endif /* UMF_TEST_NUMA_HELPERS_H */ diff --git a/test/common/numa_helpers.hpp b/test/common/numa_helpers.hpp new file mode 100644 index 000000000..7c0946de7 --- /dev/null +++ b/test/common/numa_helpers.hpp @@ -0,0 +1,50 @@ +// Copyright (C) 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_TEST_NUMA_HELPERS_HPP +#define UMF_TEST_NUMA_HELPERS_HPP 1 + +#include +#include +#include +#include +#include + +#include "test_helpers.h" + +// returns the node where page starting at 'ptr' resides +static inline void getNumaNodeByPtr(void *ptr, int *node) { + int nodeId; + int ret = + get_mempolicy(&nodeId, nullptr, 0, ptr, MPOL_F_ADDR | MPOL_F_NODE); + + ASSERT_EQ(ret, 0) << "get_mempolicy failed"; + ASSERT_GE(nodeId, 0) + << "get_mempolicy returned nodeId < 0 - should never happen"; + + *node = nodeId; +} + +static inline void _assertNode(void *ptr, int nodeId, bool fatal) { + int node = -1; + + getNumaNodeByPtr(ptr, &node); + if (testing::Test::HasFatalFailure()) { + return; + } + if (fatal) { + ASSERT_EQ(nodeId, node); + } else { + EXPECT_EQ(nodeId, node); + } +} + +//Asserts that given nodeId is equal to the node where given ptr resides +#define ASSERT_NODE_EQ(ptr, nodeId) \ + ASSERT_NO_FATAL_FAILURE(_assertNode(ptr, nodeId, true)) + +#define EXPECT_NODE_EQ(ptr, nodeId) \ + ASSERT_NO_FATAL_FAILURE(_assertNode(ptr, nodeId, false)) + +#endif /* UMF_TEST_NUMA_HELPERS_HPP */ diff --git a/test/memspaces/memspace_highest_capacity.cpp b/test/memspaces/memspace_highest_capacity.cpp index fdfed91ec..872865251 100644 --- a/test/memspaces/memspace_highest_capacity.cpp +++ b/test/memspaces/memspace_highest_capacity.cpp @@ -6,7 +6,7 @@ #include "memspace_helpers.hpp" #include "memspace_internal.h" #include "memtarget_numa.h" -#include "numa_helpers.h" +#include "numa_helpers.hpp" #include "test_helpers.h" #include @@ -60,7 +60,10 @@ TEST_F(memspaceHighestCapacityProviderTest, highestCapacityVerify) { memset(ptr, 0, alloc_size); ASSERT_EQ(ret, UMF_RESULT_SUCCESS); - auto nodeId = getNumaNodeByPtr(ptr); + int nodeId; + + ASSERT_NO_FATAL_FAILURE(getNumaNodeByPtr(ptr, &nodeId)); + ASSERT_TRUE(std::any_of(maxCapacityNodes.begin(), maxCapacityNodes.end(), [nodeId](int node) { return nodeId == node; })); diff --git a/test/memspaces/memspace_host_all.cpp b/test/memspaces/memspace_host_all.cpp index 2ee817159..64cb210b2 100644 --- a/test/memspaces/memspace_host_all.cpp +++ b/test/memspaces/memspace_host_all.cpp @@ -13,7 +13,7 @@ #include "memspace_helpers.hpp" #include "memspace_internal.h" #include "memtarget_numa.h" -#include "numa_helpers.h" +#include "numa_helpers.hpp" #include "test_helpers.h" #include "utils_sanitizers.h" diff --git a/test/provider_os_memory_multiple_numa_nodes.cpp b/test/provider_os_memory_multiple_numa_nodes.cpp index 0f7f0fb2e..a00cc0511 100644 --- a/test/provider_os_memory_multiple_numa_nodes.cpp +++ b/test/provider_os_memory_multiple_numa_nodes.cpp @@ -3,7 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include "base.hpp" -#include "numa_helpers.h" +#include "numa_helpers.hpp" #include "test_helpers.h" #include @@ -122,14 +122,10 @@ struct testNuma : testing::Test { }; struct testNumaOnEachNode : testNuma, testing::WithParamInterface {}; -struct testNumaOnEachCpu : testNuma, testing::WithParamInterface {}; INSTANTIATE_TEST_SUITE_P(testNumaNodesAllocations, testNumaOnEachNode, ::testing::ValuesIn(get_available_numa_nodes())); -INSTANTIATE_TEST_SUITE_P(testNumaNodesAllocationsAllCpus, testNumaOnEachCpu, - ::testing::ValuesIn(get_available_cpus())); - // Test for allocations on numa nodes. It will be executed on each of // the available numa nodes. TEST_P(testNumaOnEachNode, checkNumaNodesAllocations) { @@ -152,8 +148,7 @@ TEST_P(testNumaOnEachNode, checkNumaNodesAllocations) { // 'ptr' must point to an initialized value before retrieving its numa node memset(ptr, 0xFF, alloc_size); - int retrieved_numa_node_number = getNumaNodeByPtr(ptr); - EXPECT_EQ(retrieved_numa_node_number, numa_node_number); + EXPECT_NODE_EQ(ptr, numa_node_number); } // Test for allocations on numa nodes with mode preferred. It will be executed @@ -177,8 +172,7 @@ TEST_P(testNumaOnEachNode, checkModePreferred) { // 'ptr' must point to an initialized value before retrieving its numa node memset(ptr, 0xFF, alloc_size); - int retrieved_numa_node_number = getNumaNodeByPtr(ptr); - EXPECT_EQ(retrieved_numa_node_number, numa_node_number); + EXPECT_NODE_EQ(ptr, numa_node_number); } // Test for allocation on numa node with default mode enabled. @@ -202,8 +196,7 @@ TEST_P(testNumaOnEachNode, checkModeDefaultSetMempolicy) { // 'ptr' must point to an initialized value before retrieving its numa node memset(ptr, 0xFF, alloc_size); - int retrieved_numa_node_number = getNumaNodeByPtr(ptr); - EXPECT_EQ(retrieved_numa_node_number, numa_node_number); + EXPECT_NODE_EQ(ptr, numa_node_number); } // Test for allocations on a single numa node with interleave mode enabled. @@ -229,10 +222,14 @@ TEST_P(testNumaOnEachNode, checkModeInterleaveSingleNode) { // 'ptr' must point to an initialized value before retrieving its numa node memset(ptr, 0xFF, pages_num * page_size); - int retrieved_numa_node_number = getNumaNodeByPtr(ptr); - EXPECT_EQ(retrieved_numa_node_number, numa_node_number); + EXPECT_NODE_EQ(ptr, numa_node_number); } +struct testNumaOnEachCpu : testNuma, testing::WithParamInterface {}; + +INSTANTIATE_TEST_SUITE_P(testNumaNodesAllocationsAllCpus, testNumaOnEachCpu, + ::testing::ValuesIn(get_available_cpus())); + // Test for allocation on numa node with mode preferred and an empty nodeset. // For the empty nodeset the memory is allocated on the node of the CPU that // triggered the allocation. It will be executed on each available CPU. @@ -269,8 +266,7 @@ TEST_P(testNumaOnEachCpu, checkModePreferredEmptyNodeset) { // 'ptr' must point to an initialized value before retrieving its numa node memset(ptr, 0xFF, alloc_size); - int retrieved_numa_node_number = getNumaNodeByPtr(ptr); - EXPECT_EQ(retrieved_numa_node_number, numa_node_number); + EXPECT_NODE_EQ(ptr, numa_node_number); } // Test for allocation on numa node with local mode enabled. The memory is @@ -307,8 +303,7 @@ TEST_P(testNumaOnEachCpu, checkModeLocal) { // 'ptr' must point to an initialized value before retrieving its numa node memset(ptr, 0xFF, alloc_size); - int retrieved_numa_node_number = getNumaNodeByPtr(ptr); - EXPECT_EQ(retrieved_numa_node_number, numa_node_number); + EXPECT_NODE_EQ(ptr, numa_node_number); } // Test for allocation on numa node with default mode enabled. @@ -332,8 +327,7 @@ TEST_F(testNuma, checkModeDefault) { // 'ptr' must point to an initialized value before retrieving its numa node memset(ptr, 0xFF, alloc_size); - int retrieved_numa_node_number = getNumaNodeByPtr(ptr); - EXPECT_EQ(retrieved_numa_node_number, numa_node_number); + EXPECT_NODE_EQ(ptr, numa_node_number); } // Test for allocations on numa nodes with interleave mode enabled. @@ -363,11 +357,11 @@ TEST_F(testNuma, checkModeInterleave) { // Test where each page will be allocated. // Get the first numa node for ptr; Each next page is expected to be on next nodes. - size_t index = getNumaNodeByPtr((char *)ptr); + int index = 0; + ASSERT_NO_FATAL_FAILURE(getNumaNodeByPtr(ptr, &index)); for (size_t i = 1; i < (size_t)pages_num; i++) { index = (index + 1) % numa_nodes.size(); - ASSERT_EQ(numa_nodes[index], - getNumaNodeByPtr((char *)ptr + page_size * i)); + EXPECT_NODE_EQ((char *)ptr + page_size * i, numa_nodes[index]); } bitmask *retrieved_nodemask = retrieve_nodemask(ptr); @@ -407,13 +401,11 @@ TEST_F(testNuma, checkModeInterleaveCustomPartSize) { memset(ptr, 0xFF, size); // Test where each page will be allocated. // Get the first numa node for ptr; Each next part is expected to be on next nodes. - size_t index = getNumaNodeByPtr((char *)ptr); + int index = 0; + ASSERT_NO_FATAL_FAILURE(getNumaNodeByPtr(ptr, &index)); for (size_t i = 0; i < (size_t)part_num; i++) { for (size_t j = 0; j < part_size; j += page_size) { - EXPECT_EQ(numa_nodes[index], - getNumaNodeByPtr((char *)ptr + part_size * i + j)) - << "for ptr " << ptr << " + " << part_size << " * " << i - << " + " << j; + ASSERT_NODE_EQ((char *)ptr + part_size * i + j, numa_nodes[index]); } index = (index + 1) % numa_nodes.size(); } @@ -425,7 +417,7 @@ TEST_F(testNuma, checkModeInterleaveCustomPartSize) { ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(ptr, nullptr); memset(ptr, 0xFF, size); - EXPECT_EQ(numa_nodes[index], getNumaNodeByPtr(ptr)); + EXPECT_NODE_EQ(ptr, numa_nodes[index]); umfMemoryProviderFree(os_memory_provider, ptr, size); } @@ -627,7 +619,10 @@ TEST_F(testNuma, checkModeBindOnAllNodes) { // 'ptr' must point to an initialized value before retrieving its numa node memset(ptr, 0xFF, alloc_size); - unsigned retrieved_numa_node_number = (unsigned)getNumaNodeByPtr(ptr); + + int node; + ASSERT_NO_FATAL_FAILURE(getNumaNodeByPtr(ptr, &node)); + unsigned retrieved_numa_node_number = (unsigned)node; int read_cpu = sched_getcpu(); int read_numa_node = numa_node_of_cpu(read_cpu); From fe6a82c096d0edb09569d57a0e2692e8a002b594 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Thu, 8 Aug 2024 19:29:35 +0200 Subject: [PATCH 038/352] Add missing license in qemu_config.py --- scripts/qemu/qemu_config.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/scripts/qemu/qemu_config.py b/scripts/qemu/qemu_config.py index 20dc67c50..a53dd12cf 100644 --- a/scripts/qemu/qemu_config.py +++ b/scripts/qemu/qemu_config.py @@ -1,3 +1,10 @@ +""" + 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 +""" + import re import subprocess # nosec import sys From 7fbb85702b93bf006ae7701942e8764da6a56e27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Thu, 18 Jul 2024 15:54:51 +0200 Subject: [PATCH 039/352] [CI] clean up the qemu workflow and scripts a little - rename 'qemu_config.py' to 'parse_config.py' (it's already in qemu dir); - minor changes, removal of redundant code, extra comments, etc. --- .github/workflows/qemu.yml | 36 ++++++++++--------- .../qemu/{qemu_config.py => parse_config.py} | 20 +++++++---- scripts/qemu/run-build.sh | 5 +-- scripts/qemu/run-tests.sh | 1 - scripts/qemu/start_qemu.sh | 9 ++--- 5 files changed, 41 insertions(+), 30 deletions(-) rename scripts/qemu/{qemu_config.py => parse_config.py} (82%) diff --git a/.github/workflows/qemu.yml b/.github/workflows/qemu.yml index f8916c7de..c4c78b6c7 100644 --- a/.github/workflows/qemu.yml +++ b/.github/workflows/qemu.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-22.04 steps: - - name: Checkout + - name: Checkout UMF uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: fetch-depth: 0 @@ -25,16 +25,20 @@ jobs: echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules sudo udevadm control --reload-rules sudo udevadm trigger --name-match=kvm - - name: Install qemu - run: | - sudo apt update && sudo apt install -y qemu-system genisoimage qemu-utils - - name: Install libvirt and script dependencies + + - name: Install dependencies run: | - sudo apt-get install -y libvirt-clients libvirt-daemon-system libvirt-daemon virtinst bridge-utils + sudo apt-get update + sudo apt-get install -y qemu-system genisoimage qemu-utils \ + libvirt-clients libvirt-daemon-system libvirt-daemon virtinst bridge-utils pip install -r scripts/qemu/requirements.txt - sudo usermod -a -G kvm,libvirt $USER + + - name: Add user to kvm group + run: sudo usermod -a -G kvm,libvirt $USER + - name: Run ssh-keygen run: ssh-keygen -b 4096 -N '' -f ~/.ssh/id_rsa + - name: Generate iso with user info run: | pub_key=$(cat ~/.ssh/id_rsa.pub) @@ -69,11 +73,14 @@ jobs: EOF sudo -Sk genisoimage -output ubuntu-cloud-init.iso -volid cidata -joliet -rock ./user-data ./meta-data + - name: Download ubuntu image run: wget https://cloud-images.ubuntu.com/releases/lunar/release/ubuntu-23.04-server-cloudimg-amd64.img + - name: Resize image run: qemu-img resize ./ubuntu-23.04-server-cloudimg-amd64.img +4G - - name: Build + + - name: Build UMF in QEMU run: | scripts/qemu/start_qemu.sh scripts/qemu/configs/default.xml @@ -85,27 +92,22 @@ jobs: scp -P 2222 ${{github.workspace}}/scripts/qemu/run-build.sh cxltest@127.0.0.1:/home/cxltest scp -P 2222 ${{github.workspace}}/scripts/qemu/run-tests.sh cxltest@127.0.0.1:/home/cxltest - ssh cxltest@127.0.0.1 -p 2222 -t "bash /home/cxltest/run-build.sh https://github.com/$CI_REPO ${{env.CI_BRANCH}}" + ssh cxltest@127.0.0.1 -p 2222 -t "bash /home/cxltest/run-build.sh https://github.com/$CI_REPO ${{env.CI_BRANCH}}" ssh cxltest@127.0.0.1 -p 2222 -t "sudo shutdown -h now" - - name: Run tests + - name: Run tests in QEMU run: | for config_file in scripts/qemu/configs/*.xml; do config_name=$(basename $config_file .xml) - echo testing $config_name while ps -aux | grep qemu-system-x86_64 | grep -q -v grep; do echo "Waiting for QEMU to shut down..." sleep 5 done + + echo "\n ### Testing ${config_name} ###" scripts/qemu/start_qemu.sh $config_file - - if [ ${{ github.event_name }} = 'pull_request' ]; then - CI_REPO="${{ github.event.pull_request.head.repo.full_name }}" - else - CI_REPO="$GITHUB_REPOSITORY" - fi ssh cxltest@127.0.0.1 -p 2222 -t "bash /home/cxltest/run-tests.sh" ssh cxltest@127.0.0.1 -p 2222 -t "sudo shutdown -h now" diff --git a/scripts/qemu/qemu_config.py b/scripts/qemu/parse_config.py similarity index 82% rename from scripts/qemu/qemu_config.py rename to scripts/qemu/parse_config.py index a53dd12cf..49e98a550 100644 --- a/scripts/qemu/qemu_config.py +++ b/scripts/qemu/parse_config.py @@ -13,10 +13,13 @@ import psutil import shutil -# If you want to manually run this script please install deps by: pip install -r requirements.txt -# To get virsh please install libvirt-clients +# This script parses the topology xml file and returns QEMU arguments. # -# Enable verbose mode by using environment variable ENABLE_VERBOSE=1 +# Before running this script: +# - install python deps for this script: pip install -r requirements.txt +# - install 'libvirt-clients' package (for virsh) +# +# Enable verbose mode by setting environment variable: ENABLE_VERBOSE=1 TopologyCfg = collections.namedtuple( "TopologyCfg", ["name", "hmat", "cpu_model", "cpu_options", "mem_options"] @@ -27,7 +30,7 @@ def enable_verbose(): """ - Parse command line arguments + Check if env var ENABLE_VERBOSE is set and enable verbose mode """ global verbose_mode verbose_mode = os.getenv("ENABLE_VERBOSE", False) @@ -50,6 +53,9 @@ def parse_topology_xml(tpg_file_name: str) -> TopologyCfg: result.check_returncode() libvirt_args = result.stdout.decode("utf-8").strip() + if verbose_mode != False: + print(f"\nFull libvirt_args: {libvirt_args}\n") + tpg_cfg = { "name": re.search(r"guest=(\w+)", libvirt_args).group(1), "hmat": "hmat=on" in libvirt_args, @@ -74,7 +80,7 @@ def parse_topology_xml(tpg_file_name: str) -> TopologyCfg: except subprocess.CalledProcessError: sys.exit(f"\n XML file: {tpg_file_name} error in virsh parsing") except Exception: - sys.exit(f"\n Provided file is missing or missing virsh.") + sys.exit(f"\n Provided file ({tpg_file_name}) is missing or missing virsh.") return tpg @@ -89,7 +95,7 @@ def get_qemu_args(tpg_file_name: str) -> str: def calculate_memory(tpg: TopologyCfg) -> str: """ - Memory used by QEMU + Total memory required by given QEMU config """ if tpg.mem_options: mem_needed = 0 @@ -112,4 +118,6 @@ def calculate_memory(tpg: TopologyCfg) -> str: tpg_file_name = sys.argv[1] else: sys.exit(f"\n Usage: {sys.argv[0]} ") + + # Print QEMU arguments as a result of this script print(get_qemu_args(tpg_file_name)) diff --git a/scripts/qemu/run-build.sh b/scripts/qemu/run-build.sh index 91c2e4f61..517c4d012 100755 --- a/scripts/qemu/run-build.sh +++ b/scripts/qemu/run-build.sh @@ -8,8 +8,9 @@ set -e repo=$1 branch=$2 -echo password | sudo -Sk apt update -echo password | sudo -Sk apt install -y git cmake gcc g++ numactl libnuma-dev libhwloc-dev libjemalloc-dev libtbb-dev pkg-config valgrind hwloc +echo password | sudo -Sk apt-get update +echo password | sudo -Sk apt-get install -y git cmake gcc g++ pkg-config \ + numactl libnuma-dev hwloc libhwloc-dev libjemalloc-dev libtbb-dev valgrind git clone $repo umf cd umf diff --git a/scripts/qemu/run-tests.sh b/scripts/qemu/run-tests.sh index 00fdfb8fd..14f50072c 100755 --- a/scripts/qemu/run-tests.sh +++ b/scripts/qemu/run-tests.sh @@ -23,4 +23,3 @@ numactl -N 1 ctest --output-on-failure # run tests under valgrind echo "Running tests under valgrind memcheck ..." ../test/test_valgrind.sh .. . memcheck - diff --git a/scripts/qemu/start_qemu.sh b/scripts/qemu/start_qemu.sh index 0962dd98a..e59aae897 100755 --- a/scripts/qemu/start_qemu.sh +++ b/scripts/qemu/start_qemu.sh @@ -3,12 +3,12 @@ # Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -set -x set -e config_file=$1 -python3 scripts/qemu/qemu_config.py $config_file +# Parse the config file to get topology info and fix escaped single quotes +parsed_config=$(python3 scripts/qemu/parse_config.py ${config_file} | sed s/''\''/'/g) if grep -q '' "$config_file"; then hmat="on" @@ -19,12 +19,13 @@ fi sudo qemu-system-x86_64 \ -drive file=./ubuntu-23.04-server-cloudimg-amd64.img,format=qcow2,index=0,media=disk,id=hd \ -cdrom ./ubuntu-cloud-init.iso \ - -machine q35,usb=off,hmat=$hmat \ + -machine q35,usb=off,hmat=${hmat} \ -enable-kvm \ -net nic -net user,hostfwd=tcp::2222-:22 \ - $(python3 scripts/qemu/qemu_config.py $config_file | sed s/''\''/'/g) \ + ${parsed_config} \ -daemonize -display none +# Enable ssh connection to the VM until ssh-keyscan -p 2222 -H 127.0.0.1 >> ~/.ssh/known_hosts 2>/dev/null; do echo "Waiting for SSH..." sleep 1 From d1fa1bad1264569fbdded9d2023aced4b85464a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Thu, 8 Aug 2024 20:15:15 +0200 Subject: [PATCH 040/352] [QEMU] move machine info to config parsing script to not duplicate hmat info parsing - extra parsing was done in start_qemu.sh. If "hmat" not found in libvirt args, assume hmat=off. --- scripts/qemu/parse_config.py | 8 ++++++-- scripts/qemu/start_qemu.sh | 7 ------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/scripts/qemu/parse_config.py b/scripts/qemu/parse_config.py index 49e98a550..3d14fb344 100644 --- a/scripts/qemu/parse_config.py +++ b/scripts/qemu/parse_config.py @@ -56,9 +56,10 @@ def parse_topology_xml(tpg_file_name: str) -> TopologyCfg: if verbose_mode != False: print(f"\nFull libvirt_args: {libvirt_args}\n") + hmat_search = re.search(r"hmat=(\w+)", libvirt_args) tpg_cfg = { "name": re.search(r"guest=(\w+)", libvirt_args).group(1), - "hmat": "hmat=on" in libvirt_args, + "hmat": hmat_search.group(0) if hmat_search else "hmat=off", "cpu_model": re.search(r"cpu (\S+)", libvirt_args).group(1), "cpu_options": re.search("(?=-smp)(.*)threads=[0-9]+", libvirt_args).group( 0 @@ -89,7 +90,10 @@ def get_qemu_args(tpg_file_name: str) -> str: Get QEMU arguments from topology xml file """ tpg = parse_topology_xml(tpg_file_name) - qemu_args = f"-name {tpg.name} {calculate_memory(tpg)} -cpu {tpg.cpu_model} {tpg.cpu_options} {tpg.mem_options}" + qemu_args = ( + f"-machine q35,usb=off,{tpg.hmat} -name {tpg.name} " + f"{calculate_memory(tpg)} -cpu {tpg.cpu_model} {tpg.cpu_options} {tpg.mem_options}" + ) return qemu_args diff --git a/scripts/qemu/start_qemu.sh b/scripts/qemu/start_qemu.sh index e59aae897..a1e75bbb4 100755 --- a/scripts/qemu/start_qemu.sh +++ b/scripts/qemu/start_qemu.sh @@ -10,16 +10,9 @@ config_file=$1 # Parse the config file to get topology info and fix escaped single quotes parsed_config=$(python3 scripts/qemu/parse_config.py ${config_file} | sed s/''\''/'/g) -if grep -q '' "$config_file"; then - hmat="on" -else - hmat="off" -fi - sudo qemu-system-x86_64 \ -drive file=./ubuntu-23.04-server-cloudimg-amd64.img,format=qcow2,index=0,media=disk,id=hd \ -cdrom ./ubuntu-cloud-init.iso \ - -machine q35,usb=off,hmat=${hmat} \ -enable-kvm \ -net nic -net user,hostfwd=tcp::2222-:22 \ ${parsed_config} \ From 9b69b8fd12df848cc834168b2d4c656968f67c05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Thu, 8 Aug 2024 20:40:41 +0200 Subject: [PATCH 041/352] [CI] don't extra clone repo in QEMU job just use the one available in the workflow - copy it into image. --- .github/workflows/qemu.yml | 29 +++++++++++------------------ scripts/qemu/run-build.sh | 7 ------- scripts/qemu/run-tests.sh | 2 +- scripts/qemu/start_qemu.sh | 7 +++++-- 4 files changed, 17 insertions(+), 28 deletions(-) diff --git a/.github/workflows/qemu.yml b/.github/workflows/qemu.yml index c4c78b6c7..a91b71a82 100644 --- a/.github/workflows/qemu.yml +++ b/.github/workflows/qemu.yml @@ -3,9 +3,6 @@ name: Qemu on: workflow_call -env: - CI_BRANCH: "${{ github.head_ref || github.ref_name }}" - permissions: contents: read @@ -19,6 +16,7 @@ jobs: uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: fetch-depth: 0 + path: umf - name: Enable KVM run: | @@ -31,7 +29,7 @@ jobs: sudo apt-get update sudo apt-get install -y qemu-system genisoimage qemu-utils \ libvirt-clients libvirt-daemon-system libvirt-daemon virtinst bridge-utils - pip install -r scripts/qemu/requirements.txt + pip install -r umf/scripts/qemu/requirements.txt - name: Add user to kvm group run: sudo usermod -a -G kvm,libvirt $USER @@ -82,24 +80,19 @@ jobs: - name: Build UMF in QEMU run: | - scripts/qemu/start_qemu.sh scripts/qemu/configs/default.xml - - if [ ${{ github.event_name }} = 'pull_request' ]; then - CI_REPO="${{ github.event.pull_request.head.repo.full_name }}" - else - CI_REPO="$GITHUB_REPOSITORY" - fi + umf/scripts/qemu/start_qemu.sh default.xml - scp -P 2222 ${{github.workspace}}/scripts/qemu/run-build.sh cxltest@127.0.0.1:/home/cxltest - scp -P 2222 ${{github.workspace}}/scripts/qemu/run-tests.sh cxltest@127.0.0.1:/home/cxltest + # Copy UMF repository's content into the home dir in QEMU + rsync -az -e "ssh -p 2222" ${{github.workspace}}/umf/ cxltest@127.0.0.1:/home/cxltest/ + ssh cxltest@127.0.0.1 -p 2222 -t "sudo chown -R cxltest:users /home/cxltest" - ssh cxltest@127.0.0.1 -p 2222 -t "bash /home/cxltest/run-build.sh https://github.com/$CI_REPO ${{env.CI_BRANCH}}" + ssh cxltest@127.0.0.1 -p 2222 -t "bash /home/cxltest/scripts/qemu/run-build.sh" ssh cxltest@127.0.0.1 -p 2222 -t "sudo shutdown -h now" - name: Run tests in QEMU run: | - for config_file in scripts/qemu/configs/*.xml; do - config_name=$(basename $config_file .xml) + for config_file in umf/scripts/qemu/configs/*.xml; do + config_name=$(basename $config_file) while ps -aux | grep qemu-system-x86_64 | grep -q -v grep; do echo "Waiting for QEMU to shut down..." @@ -107,8 +100,8 @@ jobs: done echo "\n ### Testing ${config_name} ###" - scripts/qemu/start_qemu.sh $config_file + umf/scripts/qemu/start_qemu.sh ${config_name} - ssh cxltest@127.0.0.1 -p 2222 -t "bash /home/cxltest/run-tests.sh" + ssh cxltest@127.0.0.1 -p 2222 -t "bash /home/cxltest/scripts/qemu/run-tests.sh" ssh cxltest@127.0.0.1 -p 2222 -t "sudo shutdown -h now" done diff --git a/scripts/qemu/run-build.sh b/scripts/qemu/run-build.sh index 517c4d012..5ed1e43da 100755 --- a/scripts/qemu/run-build.sh +++ b/scripts/qemu/run-build.sh @@ -5,17 +5,10 @@ set -e -repo=$1 -branch=$2 - echo password | sudo -Sk apt-get update echo password | sudo -Sk apt-get install -y git cmake gcc g++ pkg-config \ numactl libnuma-dev hwloc libhwloc-dev libjemalloc-dev libtbb-dev valgrind -git clone $repo umf -cd umf -git checkout $branch - mkdir build cd build diff --git a/scripts/qemu/run-tests.sh b/scripts/qemu/run-tests.sh index 14f50072c..2faa68831 100755 --- a/scripts/qemu/run-tests.sh +++ b/scripts/qemu/run-tests.sh @@ -13,7 +13,7 @@ echo password | sudo bash -c "echo 0 > /proc/sys/kernel/yama/ptrace_scope" numactl -H -cd umf/build +cd build ctest --verbose # run tests bound to a numa node diff --git a/scripts/qemu/start_qemu.sh b/scripts/qemu/start_qemu.sh index a1e75bbb4..8c1791d7e 100755 --- a/scripts/qemu/start_qemu.sh +++ b/scripts/qemu/start_qemu.sh @@ -5,10 +5,13 @@ set -e -config_file=$1 +# The config file name (should be located in ./configs/ sub-dir) +config_name=$1 # Parse the config file to get topology info and fix escaped single quotes -parsed_config=$(python3 scripts/qemu/parse_config.py ${config_file} | sed s/''\''/'/g) +parsed_config=$(python3 "$(dirname $0)/parse_config.py" "$(dirname $0)/configs/${config_name}" | sed s/''\''/'/g) + +set -x sudo qemu-system-x86_64 \ -drive file=./ubuntu-23.04-server-cloudimg-amd64.img,format=qcow2,index=0,media=disk,id=hd \ From c221579b01f2aabf648636e50882b01848a4c9fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Mon, 12 Aug 2024 12:05:06 +0200 Subject: [PATCH 042/352] [CI] change username in QEMU build Use 'testuser' instead of 'cxltest' - it's more generic here. --- .github/workflows/qemu.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/qemu.yml b/.github/workflows/qemu.yml index a91b71a82..fa3089b67 100644 --- a/.github/workflows/qemu.yml +++ b/.github/workflows/qemu.yml @@ -44,11 +44,11 @@ jobs: cat > user-data << EOF #cloud-config - # Add a 'cxltest' user to the system with a password + # Add a 'testuser' user to the system with a password users: - default - - name: cxltest - gecos: CXL Test User + - name: testuser + gecos: Test User primary_group: wheel groups: users sudo: ALL=(ALL) NOPASSWD:ALL @@ -61,13 +61,13 @@ jobs: chpasswd: list: | root:password - cxltest:password + testuser:password expire: False EOF cat > meta-data << EOF - instance-id: cxl-test - local-hostname: cxl-test + instance-id: qemu-test + local-hostname: qemu-test EOF sudo -Sk genisoimage -output ubuntu-cloud-init.iso -volid cidata -joliet -rock ./user-data ./meta-data @@ -83,11 +83,11 @@ jobs: umf/scripts/qemu/start_qemu.sh default.xml # Copy UMF repository's content into the home dir in QEMU - rsync -az -e "ssh -p 2222" ${{github.workspace}}/umf/ cxltest@127.0.0.1:/home/cxltest/ - ssh cxltest@127.0.0.1 -p 2222 -t "sudo chown -R cxltest:users /home/cxltest" + rsync -az -e "ssh -p 2222" ${{github.workspace}}/umf/ testuser@127.0.0.1:/home/testuser/ + ssh testuser@127.0.0.1 -p 2222 -t "sudo chown -R testuser:users /home/testuser" - ssh cxltest@127.0.0.1 -p 2222 -t "bash /home/cxltest/scripts/qemu/run-build.sh" - ssh cxltest@127.0.0.1 -p 2222 -t "sudo shutdown -h now" + ssh testuser@127.0.0.1 -p 2222 -t "bash /home/testuser/scripts/qemu/run-build.sh" + ssh testuser@127.0.0.1 -p 2222 -t "sudo shutdown -h now" - name: Run tests in QEMU run: | @@ -102,6 +102,6 @@ jobs: echo "\n ### Testing ${config_name} ###" umf/scripts/qemu/start_qemu.sh ${config_name} - ssh cxltest@127.0.0.1 -p 2222 -t "bash /home/cxltest/scripts/qemu/run-tests.sh" - ssh cxltest@127.0.0.1 -p 2222 -t "sudo shutdown -h now" + ssh testuser@127.0.0.1 -p 2222 -t "bash /home/testuser/scripts/qemu/run-tests.sh" + ssh testuser@127.0.0.1 -p 2222 -t "sudo shutdown -h now" done From 30b47ae38919e3b4d03a5088a07d099ec16901e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Fri, 9 Aug 2024 19:43:05 +0200 Subject: [PATCH 043/352] [CI] Switch one of the basic builds to run on Ubuntu 24.04 --- .github/workflows/basic.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/basic.yml b/.github/workflows/basic.yml index 736f08eef..3af136845 100644 --- a/.github/workflows/basic.yml +++ b/.github/workflows/basic.yml @@ -44,7 +44,7 @@ jobs: shared_library: 'ON' level_zero_provider: 'ON' install_tbb: 'ON' - - os: 'ubuntu-22.04' + - os: 'ubuntu-24.04' build_type: Debug compiler: {c: gcc, cxx: g++} shared_library: 'ON' From 8e073fd0a85137b144cf6c740130c2aa10e13a86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Fri, 2 Aug 2024 15:57:45 +0200 Subject: [PATCH 044/352] [CMake] Minor fixes --- CMakeLists.txt | 21 +++++++++++---------- src/CMakeLists.txt | 2 +- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e366726fe..b62942e72 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,6 +52,10 @@ option( UMF_LINK_HWLOC_STATICALLY "Link UMF with HWLOC library statically (supported for Linux, MacOS and Release build on Windows)" OFF) +option( + UMF_DISABLE_HWLOC + "Disable features that requires hwloc (OS provider, memory targets, topology discovery)" + OFF) option(UMF_FORMAT_CODE_STYLE "Add clang, cmake, and black -format-check and -format-apply targets" OFF) @@ -63,10 +67,6 @@ option(UMF_USE_TSAN "Enable ThreadSanitizer checks" OFF) option(UMF_USE_MSAN "Enable MemorySanitizer checks" OFF) option(UMF_USE_VALGRIND "Enable Valgrind instrumentation" OFF) option(UMF_USE_GCOV "Enable gcov support" OFF) -option( - UMF_DISABLE_HWLOC - "Disable features that requires hwloc (OS provider, memory targets, topology discovery)" - OFF) # set UMF_PROXY_LIB_BASED_ON_POOL to one of: SCALABLE or JEMALLOC set(KNOWN_PROXY_LIB_POOLS SCALABLE JEMALLOC) @@ -289,8 +289,7 @@ if(UMF_BUILD_FUZZTESTS add_link_options("-fsanitize=fuzzer-no-link") endif() -# A header only library to specify include directories in transitive -# dependencies. +# A header-only lib to specify include directories in transitive dependencies add_library(umf_headers INTERFACE) # Alias target to support FetchContent. @@ -343,7 +342,6 @@ if(UMF_BUILD_LIBUMF_POOL_JEMALLOC) ) endif() -# set UMF_PROXY_LIB_ENABLED if(WINDOWS) # TODO: enable the proxy library in the Debug build on Windows # @@ -362,6 +360,7 @@ if(WINDOWS) ) endif() endif() +# set UMF_PROXY_LIB_ENABLED if(UMF_PROXY_LIB_BASED_ON_POOL STREQUAL SCALABLE) if(UMF_POOL_SCALABLE_ENABLED) set(UMF_PROXY_LIB_ENABLED ON) @@ -391,10 +390,12 @@ else() ) endif() +# set optional symbols for map/def files +# +# TODO: ref. #649 set(UMF_OPTIONAL_SYMBOLS_LINUX "") set(UMF_OPTIONAL_SYMBOLS_WINDOWS "") -# Conditional configuration for Level Zero provider if(UMF_BUILD_LEVEL_ZERO_PROVIDER) add_optional_symbol(umfLevelZeroMemoryProviderOps) endif() @@ -551,12 +552,12 @@ if(UMF_FORMAT_CODE_STYLE) add_custom_target( black-format-check - COMMAND ${BLACK} --check --verbose ${CMAKE_SOURCE_DIR} + COMMAND ${BLACK} --check --verbose ${UMF_CMAKE_SOURCE_DIR} COMMENT "Check Python files formatting using black formatter") add_custom_target( black-format-apply - COMMAND ${BLACK} ${CMAKE_SOURCE_DIR} + COMMAND ${BLACK} ${UMF_CMAKE_SOURCE_DIR} COMMENT "Format Python files using black formatter") endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7d2f151f0..84c85975c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -128,7 +128,7 @@ else() message(STATUS "UMF_OPTIONAL_SYMBOLS: ${UMF_OPTIONAL_SYMBOLS_LINUX}") endif() -# Configure the DEF file based on whether Level Zero provider is built +# Configure map/def files with optional symbols configure_file("${CMAKE_CURRENT_SOURCE_DIR}/libumf.def.in" "${CMAKE_CURRENT_BINARY_DIR}/libumf.def" @ONLY) From b553b20a16cc17e5d22b8f8dd72730aeb14c805b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Fri, 2 Aug 2024 16:23:22 +0200 Subject: [PATCH 045/352] [CMake] Clean up code around UMF_DISABLE_HWLOC print general info when hwloc is disabled (not only for examples), remove the dead code when DLL_PATH_LIST would be set with empty var, print hwloc variables only once. --- CMakeLists.txt | 186 ++++++++++++++++++++++++------------------------- 1 file changed, 91 insertions(+), 95 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b62942e72..7b04bc517 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,12 +49,12 @@ option(UMF_BUILD_FUZZTESTS "Build UMF fuzz tests" OFF) option(UMF_BUILD_GPU_EXAMPLES "Build UMF GPU examples" OFF) option(UMF_DEVELOPER_MODE "Enable additional developer checks" OFF) option( - UMF_LINK_HWLOC_STATICALLY - "Link UMF with HWLOC library statically (supported for Linux, MacOS and Release build on Windows)" + UMF_DISABLE_HWLOC + "Disable hwloc and UMF features requiring it (OS provider, memtargets, topology discovery)" OFF) option( - UMF_DISABLE_HWLOC - "Disable features that requires hwloc (OS provider, memory targets, topology discovery)" + UMF_LINK_HWLOC_STATICALLY + "Link UMF with HWLOC library statically (supported for Linux, MacOS and Release build on Windows)" OFF) option(UMF_FORMAT_CODE_STYLE "Add clang, cmake, and black -format-check and -format-apply targets" @@ -100,16 +100,19 @@ else() message(FATAL_ERROR "Unknown OS type") endif() -if(NOT DEFINED UMF_HWLOC_REPO) - set(UMF_HWLOC_REPO "https://github.com/open-mpi/hwloc.git") -endif() +if(UMF_DISABLE_HWLOC) + message(STATUS "hwloc is disabled, hence OS provider, memtargets, " + "topology discovery, examples won't be available!") +else() + if(NOT DEFINED UMF_HWLOC_REPO) + set(UMF_HWLOC_REPO "https://github.com/open-mpi/hwloc.git") + endif() -if(NOT DEFINED UMF_HWLOC_TAG) - set(UMF_HWLOC_TAG hwloc-2.10.0) -endif() + if(NOT DEFINED UMF_HWLOC_TAG) + set(UMF_HWLOC_TAG hwloc-2.10.0) + endif() -if(NOT UMF_LINK_HWLOC_STATICALLY) - if(NOT UMF_DISABLE_HWLOC) + if(NOT UMF_LINK_HWLOC_STATICALLY) pkg_check_modules(LIBHWLOC hwloc>=2.3.0) if(NOT LIBHWLOC_FOUND) find_package(LIBHWLOC 2.3.0 REQUIRED hwloc) @@ -119,86 +122,83 @@ if(NOT UMF_LINK_HWLOC_STATICALLY) set(DLL_PATH_LIST "${DLL_PATH_LIST};PATH=path_list_append:${LIBHWLOC_LIBRARY_DIRS}/../bin" ) - endif() - # add PATH to DLL on Windows - set(DLL_PATH_LIST - "${DLL_PATH_LIST};PATH=path_list_append:${LIBHWLOC_LIBRARY_DIRS}/../bin" - ) -elseif(WINDOWS AND NOT UMF_DISABLE_HWLOC) - include(FetchContent) - set(HWLOC_ENABLE_TESTING OFF) - set(HWLOC_SKIP_LSTOPO ON) - set(HWLOC_SKIP_TOOLS ON) - - message(STATUS "Will fetch hwloc from ${UMF_HWLOC_REPO}") - - FetchContent_Declare( - hwloc_targ - GIT_REPOSITORY ${UMF_HWLOC_REPO} - GIT_TAG ${UMF_HWLOC_TAG} - SOURCE_SUBDIR contrib/windows-cmake/ FIND_PACKAGE_ARGS) - - FetchContent_GetProperties(hwloc_targ) - if(NOT hwloc_targ_POPULATED) - FetchContent_MakeAvailable(hwloc_targ) - endif() + elseif(WINDOWS) + include(FetchContent) + set(HWLOC_ENABLE_TESTING OFF) + set(HWLOC_SKIP_LSTOPO ON) + set(HWLOC_SKIP_TOOLS ON) + + message( + STATUS + "Will fetch hwloc from ${UMF_HWLOC_REPO} (tag: ${UMF_HWLOC_TAG})" + ) - set(LIBHWLOC_INCLUDE_DIRS - ${hwloc_targ_SOURCE_DIR}/include;${hwloc_targ_BINARY_DIR}/include) - set(LIBHWLOC_LIBRARY_DIRS - ${hwloc_targ_BINARY_DIR}/Release;${hwloc_targ_BINARY_DIR}/Debug) + FetchContent_Declare( + hwloc_targ + GIT_REPOSITORY ${UMF_HWLOC_REPO} + GIT_TAG ${UMF_HWLOC_TAG} + SOURCE_SUBDIR contrib/windows-cmake/ FIND_PACKAGE_ARGS) - message(STATUS " LIBHWLOC_LIBRARIES = ${LIBHWLOC_LIBRARIES}") - message(STATUS " LIBHWLOC_INCLUDE_DIRS = ${LIBHWLOC_INCLUDE_DIRS}") - message(STATUS " LIBHWLOC_LIBRARY_DIRS = ${LIBHWLOC_LIBRARY_DIRS}") -elseif(NOT UMF_DISABLE_HWLOC) - include(FetchContent) - message(STATUS "Will fetch hwloc from ${UMF_HWLOC_REPO}") - - FetchContent_Declare( - hwloc_targ - GIT_REPOSITORY ${UMF_HWLOC_REPO} - GIT_TAG ${UMF_HWLOC_TAG}) - - FetchContent_GetProperties(hwloc_targ) - if(NOT hwloc_targ_POPULATED) - FetchContent_MakeAvailable(hwloc_targ) - endif() + FetchContent_GetProperties(hwloc_targ) + if(NOT hwloc_targ_POPULATED) + FetchContent_MakeAvailable(hwloc_targ) + endif() + + set(LIBHWLOC_INCLUDE_DIRS + ${hwloc_targ_SOURCE_DIR}/include;${hwloc_targ_BINARY_DIR}/include) + set(LIBHWLOC_LIBRARY_DIRS + ${hwloc_targ_BINARY_DIR}/Release;${hwloc_targ_BINARY_DIR}/Debug) + else() + include(FetchContent) + message( + STATUS + "Will fetch hwloc from ${UMF_HWLOC_REPO} (tag: ${UMF_HWLOC_TAG})" + ) - add_custom_command( - COMMAND ./autogen.sh - WORKING_DIRECTORY ${hwloc_targ_SOURCE_DIR} - OUTPUT ${hwloc_targ_SOURCE_DIR}/configure) - add_custom_command( - COMMAND - ./configure --prefix=${hwloc_targ_BINARY_DIR} --enable-static=yes - --enable-shared=no --disable-libxml2 --disable-levelzero - --disable-opencl --disable-cuda --disable-nvml CFLAGS=-fPIC - CXXFLAGS=-fPIC - WORKING_DIRECTORY ${hwloc_targ_SOURCE_DIR} - OUTPUT ${hwloc_targ_SOURCE_DIR}/Makefile - DEPENDS ${hwloc_targ_SOURCE_DIR}/configure) - add_custom_command( - COMMAND make - WORKING_DIRECTORY ${hwloc_targ_SOURCE_DIR} - OUTPUT ${hwloc_targ_SOURCE_DIR}/lib/libhwloc.la - DEPENDS ${hwloc_targ_SOURCE_DIR}/Makefile) - add_custom_command( - COMMAND make install - WORKING_DIRECTORY ${hwloc_targ_SOURCE_DIR} - OUTPUT ${hwloc_targ_BINARY_DIR}/lib/libhwloc.a - DEPENDS ${hwloc_targ_SOURCE_DIR}/lib/libhwloc.la) - - add_custom_target(hwloc_prod - DEPENDS ${hwloc_targ_BINARY_DIR}/lib/libhwloc.a) - add_library(hwloc INTERFACE) - target_link_libraries(hwloc - INTERFACE ${hwloc_targ_BINARY_DIR}/lib/libhwloc.a) - add_dependencies(hwloc hwloc_prod) - - set(LIBHWLOC_LIBRARY_DIRS ${hwloc_targ_BINARY_DIR}/lib) - set(LIBHWLOC_INCLUDE_DIRS ${hwloc_targ_BINARY_DIR}/include) - set(LIBHWLOC_LIBRARIES ${hwloc_targ_BINARY_DIR}/lib/libhwloc.a) + FetchContent_Declare( + hwloc_targ + GIT_REPOSITORY ${UMF_HWLOC_REPO} + GIT_TAG ${UMF_HWLOC_TAG}) + + FetchContent_GetProperties(hwloc_targ) + if(NOT hwloc_targ_POPULATED) + FetchContent_MakeAvailable(hwloc_targ) + endif() + + add_custom_command( + COMMAND ./autogen.sh + WORKING_DIRECTORY ${hwloc_targ_SOURCE_DIR} + OUTPUT ${hwloc_targ_SOURCE_DIR}/configure) + add_custom_command( + COMMAND + ./configure --prefix=${hwloc_targ_BINARY_DIR} + --enable-static=yes --enable-shared=no --disable-libxml2 + --disable-levelzero CFLAGS=-fPIC CXXFLAGS=-fPIC + WORKING_DIRECTORY ${hwloc_targ_SOURCE_DIR} + OUTPUT ${hwloc_targ_SOURCE_DIR}/Makefile + DEPENDS ${hwloc_targ_SOURCE_DIR}/configure) + add_custom_command( + COMMAND make + WORKING_DIRECTORY ${hwloc_targ_SOURCE_DIR} + OUTPUT ${hwloc_targ_SOURCE_DIR}/lib/libhwloc.la + DEPENDS ${hwloc_targ_SOURCE_DIR}/Makefile) + add_custom_command( + COMMAND make install + WORKING_DIRECTORY ${hwloc_targ_SOURCE_DIR} + OUTPUT ${hwloc_targ_BINARY_DIR}/lib/libhwloc.a + DEPENDS ${hwloc_targ_SOURCE_DIR}/lib/libhwloc.la) + + add_custom_target(hwloc_prod + DEPENDS ${hwloc_targ_BINARY_DIR}/lib/libhwloc.a) + add_library(hwloc INTERFACE) + target_link_libraries(hwloc + INTERFACE ${hwloc_targ_BINARY_DIR}/lib/libhwloc.a) + add_dependencies(hwloc hwloc_prod) + + set(LIBHWLOC_LIBRARY_DIRS ${hwloc_targ_BINARY_DIR}/lib) + set(LIBHWLOC_INCLUDE_DIRS ${hwloc_targ_BINARY_DIR}/include) + set(LIBHWLOC_LIBRARIES ${hwloc_targ_BINARY_DIR}/lib/libhwloc.a) + endif() message(STATUS " LIBHWLOC_LIBRARIES = ${LIBHWLOC_LIBRARIES}") message(STATUS " LIBHWLOC_INCLUDE_DIRS = ${LIBHWLOC_INCLUDE_DIRS}") @@ -414,12 +414,8 @@ if(UMF_BUILD_BENCHMARKS) add_subdirectory(benchmark) endif() -if(UMF_BUILD_EXAMPLES) - if(NOT UMF_DISABLE_HWLOC) - add_subdirectory(examples) - else() - message(WARNING "Examples cannot be build - hwloc disabled") - endif() +if(UMF_BUILD_EXAMPLES AND NOT UMF_DISABLE_HWLOC) + add_subdirectory(examples) endif() if(UMF_FORMAT_CODE_STYLE) From 2a04237bb486291bd7086378b7f9e84d1c5cfcae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Fri, 2 Aug 2024 16:46:50 +0200 Subject: [PATCH 046/352] [CI] properly set hwloc related params in basic.yml "default" params are not propagated into include's. --- .github/workflows/basic.yml | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/.github/workflows/basic.yml b/.github/workflows/basic.yml index 3af136845..30ab2e600 100644 --- a/.github/workflows/basic.yml +++ b/.github/workflows/basic.yml @@ -32,24 +32,32 @@ jobs: shared_library: 'OFF' level_zero_provider: 'ON' install_tbb: 'ON' + disable_hwloc: 'OFF' + link_hwloc_statically: 'OFF' - os: 'ubuntu-22.04' build_type: Release compiler: {c: clang, cxx: clang++} shared_library: 'OFF' level_zero_provider: 'ON' install_tbb: 'ON' + disable_hwloc: 'OFF' + link_hwloc_statically: 'OFF' - os: 'ubuntu-22.04' build_type: Release compiler: {c: gcc, cxx: g++} shared_library: 'ON' level_zero_provider: 'ON' install_tbb: 'ON' + disable_hwloc: 'OFF' + link_hwloc_statically: 'OFF' - os: 'ubuntu-24.04' build_type: Debug compiler: {c: gcc, cxx: g++} shared_library: 'ON' level_zero_provider: 'ON' install_tbb: 'ON' + disable_hwloc: 'OFF' + link_hwloc_statically: 'OFF' # test level_zero_provider='OFF' - os: 'ubuntu-22.04' build_type: Release @@ -57,13 +65,17 @@ jobs: shared_library: 'OFF' level_zero_provider: 'OFF' install_tbb: 'ON' + disable_hwloc: 'OFF' + link_hwloc_statically: 'OFF' # test icx compiler - os: 'ubuntu-22.04' build_type: Release compiler: {c: icx, cxx: icpx} shared_library: 'ON' level_zero_provider: 'ON' - install_tbb: 'ON' + install_tbb: 'ON' + disable_hwloc: 'OFF' + link_hwloc_statically: 'OFF' # test without installing TBB - os: 'ubuntu-22.04' build_type: Release @@ -71,6 +83,8 @@ jobs: shared_library: 'ON' level_zero_provider: 'ON' install_tbb: 'OFF' + disable_hwloc: 'OFF' + link_hwloc_statically: 'OFF' - os: 'ubuntu-22.04' build_type: Debug compiler: {c: gcc, cxx: g++} @@ -78,12 +92,14 @@ jobs: level_zero_provider: 'ON' install_tbb: 'ON' disable_hwloc: 'ON' + link_hwloc_statically: 'OFF' - os: 'ubuntu-22.04' build_type: Release compiler: {c: gcc, cxx: g++} shared_library: 'ON' level_zero_provider: 'ON' install_tbb: 'ON' + disable_hwloc: 'OFF' link_hwloc_statically: 'ON' runs-on: ${{matrix.os}} From 352bb2242d3ec673f382fffbcbaa9cc0349e1664 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 14 Aug 2024 13:18:20 +0200 Subject: [PATCH 047/352] Replace two names of variables in test/test_examples.sh Replace names of the following variables: - WORKSPACE with SOURCE_DIR - workspace_dir with source_dir Signed-off-by: Lukasz Dorau --- test/test_examples.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/test_examples.sh b/test/test_examples.sh index 9331b1d06..469cd9c10 100755 --- a/test/test_examples.sh +++ b/test/test_examples.sh @@ -5,7 +5,7 @@ set -e -WORKSPACE=$1 +SOURCE_DIR=$1 BUILD_DIR=$2 INSTALL_DIR=$3 @@ -13,7 +13,7 @@ echo "Running: $0 $*" function print_usage() { echo "$(basename $0) - test all examples standalone" - echo "Usage: $(basename $0) " + echo "Usage: $(basename $0) " } if [ "$3" == "" ]; then @@ -28,13 +28,13 @@ if [ "$4" == "" ]; then exit 0 fi -if [ ! -f $WORKSPACE/README.md ]; then - echo -e "error: incorrect : $WORKSPACE\n" +if [ ! -f $SOURCE_DIR/README.md ]; then + echo -e "error: incorrect : $SOURCE_DIR\n" print_usage exit 1 fi -WORKSPACE=$(realpath $WORKSPACE) +SOURCE_DIR=$(realpath $SOURCE_DIR) BUILD_DIR=$(realpath $BUILD_DIR) INSTALL_DIR=$(realpath $INSTALL_DIR) @@ -51,7 +51,7 @@ make -j$(nproc) install set +x for ex in $EXAMPLES; do - SRC_DIR="${WORKSPACE}/examples/$ex" + SRC_DIR="${SOURCE_DIR}/examples/$ex" BLD_DIR="${BUILD_DIR}/examples-standalone/$ex" if [ ! -d $SRC_DIR ]; then From 5333734a2230863c0139e6599f8165a547043736 Mon Sep 17 00:00:00 2001 From: "Kenneth Benzie (Benie)" Date: Thu, 15 Aug 2024 07:20:20 -0700 Subject: [PATCH 048/352] Use PROJECT_VERSION not CMAKE_PROJECT_VERSION When building as a subproject the `CMAKE_PROJECT_VERSION` is the root project version not the current project version. As such, in a subproject which makes use of UMF, such as UR, the `.so` or `.dll` library version would be set to the UR project version, not the UMF version. This patch fixes this erroneous versioning by using `PROJECT_VERSION` (and derivatives) in place of `CMAKE_PROJECT_VERSION`. --- CMakeLists.txt | 2 +- src/CMakeLists.txt | 4 ++-- src/libumf.rc.in | 2 +- src/proxy_lib/CMakeLists.txt | 3 +-- src/proxy_lib/proxy_lib.rc.in | 2 +- 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b04bc517..8eb920712 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,7 +23,7 @@ project( VERSION ${UMF_CMAKE_VERSION} LANGUAGES C) -if(CMAKE_PROJECT_VERSION_PATCH GREATER 0) +if(PROJECT_VERSION_PATCH GREATER 0) # set extra variable for Windows dll metadata set(UMF_VERSION_BUGFIX 1) endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 84c85975c..3b407f7f2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -168,8 +168,8 @@ if(UMF_BUILD_SHARED_LIBRARY) set_target_properties( umf PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_UMF_OUTPUT_DIRECTORY} - VERSION ${CMAKE_PROJECT_VERSION} - SOVERSION ${CMAKE_PROJECT_VERSION_MAJOR}) + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR}) else() add_umf_library( NAME umf diff --git a/src/libumf.rc.in b/src/libumf.rc.in index 3915e0a10..7aba79e7e 100644 --- a/src/libumf.rc.in +++ b/src/libumf.rc.in @@ -8,7 +8,7 @@ #include "umf/base.h" -#define UMF_VERNUMBERS @CMAKE_PROJECT_VERSION_MAJOR@,@CMAKE_PROJECT_VERSION_MINOR@,@CMAKE_PROJECT_VERSION_PATCH@,@UMF_VERSION_REVISION@ +#define UMF_VERNUMBERS @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@,@UMF_VERSION_REVISION@ #define _UMF_VERSION "@UMF_VERSION@" #ifdef _DEBUG diff --git a/src/proxy_lib/CMakeLists.txt b/src/proxy_lib/CMakeLists.txt index 379a454d0..d6b07902d 100644 --- a/src/proxy_lib/CMakeLists.txt +++ b/src/proxy_lib/CMakeLists.txt @@ -32,8 +32,7 @@ add_umf_library( LIBS umf_utils ${PROXY_LIBS} LINUX_MAP_FILE ${CMAKE_CURRENT_SOURCE_DIR}/proxy_lib.map WINDOWS_DEF_FILE ${CMAKE_CURRENT_SOURCE_DIR}/proxy_lib.def) -set_target_properties(umf_proxy PROPERTIES SOVERSION - ${CMAKE_PROJECT_VERSION_MAJOR}) +set_target_properties(umf_proxy PROPERTIES SOVERSION ${PROJECT_VERSION_MAJOR}) add_library(${PROJECT_NAME}::proxy ALIAS umf_proxy) diff --git a/src/proxy_lib/proxy_lib.rc.in b/src/proxy_lib/proxy_lib.rc.in index 29c8b0482..dce151ec3 100644 --- a/src/proxy_lib/proxy_lib.rc.in +++ b/src/proxy_lib/proxy_lib.rc.in @@ -8,7 +8,7 @@ #include "umf/base.h" -#define UMF_VERNUMBERS @CMAKE_PROJECT_VERSION_MAJOR@,@CMAKE_PROJECT_VERSION_MINOR@,@CMAKE_PROJECT_VERSION_PATCH@,@UMF_VERSION_REVISION@ +#define UMF_VERNUMBERS @PROJECT_VERSION_MAJOR@,@PROJECT_VERSION_MINOR@,@PROJECT_VERSION_PATCH@,@UMF_VERSION_REVISION@ #define _UMF_VERSION "@UMF_VERSION@" #ifdef _DEBUG From 738d5c5f36074e9a640ceecc8298f1db6b89a532 Mon Sep 17 00:00:00 2001 From: Igor Chorazewicz Date: Fri, 16 Aug 2024 01:50:40 +0200 Subject: [PATCH 049/352] Fix stype for ze_device_mem_alloc_desc_t in l0 provider --- src/provider/provider_level_zero.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/provider/provider_level_zero.c b/src/provider/provider_level_zero.c index b7a5fde50..3f7340556 100644 --- a/src/provider/provider_level_zero.c +++ b/src/provider/provider_level_zero.c @@ -167,7 +167,7 @@ static umf_result_t ze_memory_provider_alloc(void *provider, size_t size, .pNext = NULL, .flags = 0}; ze_device_mem_alloc_desc_t dev_desc = { - .stype = ZE_STRUCTURE_TYPE_HOST_MEM_ALLOC_DESC, + .stype = ZE_STRUCTURE_TYPE_DEVICE_MEM_ALLOC_DESC, .pNext = NULL, .flags = 0, .ordinal = 0 // TODO From a838305378d888849422659fb1e4e0b2dcb92cef Mon Sep 17 00:00:00 2001 From: Patryk Kaminski Date: Wed, 14 Aug 2024 08:14:22 +0200 Subject: [PATCH 050/352] Disable pciaccess library in hwloc --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8eb920712..9854dfa1f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -173,7 +173,8 @@ else() COMMAND ./configure --prefix=${hwloc_targ_BINARY_DIR} --enable-static=yes --enable-shared=no --disable-libxml2 - --disable-levelzero CFLAGS=-fPIC CXXFLAGS=-fPIC + --disable-pciaccess --disable-levelzero CFLAGS=-fPIC + CXXFLAGS=-fPIC WORKING_DIRECTORY ${hwloc_targ_SOURCE_DIR} OUTPUT ${hwloc_targ_SOURCE_DIR}/Makefile DEPENDS ${hwloc_targ_SOURCE_DIR}/configure) From 6ed6f481ccd00503de9400f391560019e8a8a841 Mon Sep 17 00:00:00 2001 From: Agata Momot Date: Tue, 13 Aug 2024 14:03:20 +0200 Subject: [PATCH 051/352] docs: add details in CONTRIBUTING.md Add black installation details in CONTRIBUTING.md as it has been outlined in README.md --- CONTRIBUTING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e350cd8d0..ec579c0be 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -97,6 +97,7 @@ source files, respectively. **NOTE**: We use specific versions of formatting tools to ensure consistency across the project. The required versions are: - clang-format version **15.0**, which can be installed with the command: `python -m pip install clang-format==15.0.7`. - cmake-format version **0.6**, which can be installed with the command: `python -m pip install cmake-format==0.6.13`. +- black (no specific version required), which can be installed with the command: `python -m pip install black`. Please ensure you have these specific versions installed before contributing to the project. From 2b7141b0e4f2fdfd42465682394c093feef9c877 Mon Sep 17 00:00:00 2001 From: Agata Momot Date: Tue, 13 Aug 2024 12:18:18 +0200 Subject: [PATCH 052/352] fix: substitute UT_ASSERTs with asserts from GTEST Ref. #569 --- test/test_base_alloc.cpp | 2 +- test/test_base_alloc_linear.cpp | 17 ++++++++--------- test/test_proxy_lib.cpp | 2 +- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/test/test_base_alloc.cpp b/test/test_base_alloc.cpp index 497a22a69..80bc67541 100644 --- a/test/test_base_alloc.cpp +++ b/test/test_base_alloc.cpp @@ -37,7 +37,7 @@ TEST_F(test, baseAllocMultiThreadedAllocMemset) { for (int i = 0; i < ITERATIONS; i++) { for (int k = 0; k < ALLOCATION_SIZE; k++) { - UT_ASSERTeq(*(ptrs[i].get() + k), ((i + TID) & 0xFF)); + ASSERT_EQ(*(ptrs[i].get() + k), ((i + TID) & 0xFF)); } } }; diff --git a/test/test_base_alloc_linear.cpp b/test/test_base_alloc_linear.cpp index a361244fc..94425fb03 100644 --- a/test/test_base_alloc_linear.cpp +++ b/test/test_base_alloc_linear.cpp @@ -24,7 +24,7 @@ TEST_F(test, baseAllocLinearAllocMoreThanPoolSize) { size_t new_size = 20 * 1024 * 1024; // = 20 MB void *ptr = umf_ba_linear_alloc(pool.get(), new_size); - UT_ASSERTne(ptr, NULL); + ASSERT_NE(ptr, nullptr); memset(ptr, 0, new_size); umf_ba_linear_free(pool.get(), ptr); @@ -37,15 +37,14 @@ TEST_F(test, baseAllocLinearPoolContainsPointer) { size_t size = 16; void *ptr = umf_ba_linear_alloc(pool.get(), size); - UT_ASSERTne(ptr, NULL); + ASSERT_NE(ptr, nullptr); memset(ptr, 0, size); - // assert pool contains pointer ptr - UT_ASSERTne(umf_ba_linear_pool_contains_pointer(pool.get(), ptr), 0); + ASSERT_NE(umf_ba_linear_pool_contains_pointer(pool.get(), ptr), 0); // assert pool does NOT contain pointer 0x0123 - UT_ASSERTeq(umf_ba_linear_pool_contains_pointer(pool.get(), (void *)0x0123), - 0); + ASSERT_EQ(umf_ba_linear_pool_contains_pointer(pool.get(), (void *)0x0123), + 0); umf_ba_linear_free(pool.get(), ptr); } @@ -78,14 +77,14 @@ TEST_F(test, baseAllocLinearMultiThreadedAllocMemset) { (rand() / (double)RAND_MAX)); buffer[i].size = size; buffer[i].ptr = (unsigned char *)umf_ba_linear_alloc(pool, size); - UT_ASSERTne(buffer[i].ptr, NULL); + ASSERT_NE(buffer[i].ptr, nullptr); memset(buffer[i].ptr, (i + TID) & 0xFF, buffer[i].size); } for (int i = 0; i < ITERATIONS; i++) { - UT_ASSERTne(buffer[i].ptr, NULL); + ASSERT_NE(buffer[i].ptr, nullptr); for (size_t k = 0; k < buffer[i].size; k++) { - UT_ASSERTeq(*(buffer[i].ptr + k), (i + TID) & 0xFF); + ASSERT_EQ(*(buffer[i].ptr + k), (i + TID) & 0xFF); } } diff --git a/test/test_proxy_lib.cpp b/test/test_proxy_lib.cpp index 4cdb6568b..557698117 100644 --- a/test/test_proxy_lib.cpp +++ b/test/test_proxy_lib.cpp @@ -31,5 +31,5 @@ TEST_F(test, proxyLibBasic) { #else size_t size = ::malloc_usable_size(ptr); #endif - UT_ASSERTeq(size, 0xDEADBEEF); + ASSERT_EQ(size, 0xDEADBEEF); } From 5cb80d8b893548a5e9aa96c2afd7e8543beeccff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Mon, 19 Aug 2024 17:03:58 +0200 Subject: [PATCH 053/352] [CMake] Fix hwloc configure params Around changes in #667, perhaps in merge conflict resolution extra hwloc configure params were accidentally removed (ref. 660). --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9854dfa1f..dfe433c7f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -173,8 +173,8 @@ else() COMMAND ./configure --prefix=${hwloc_targ_BINARY_DIR} --enable-static=yes --enable-shared=no --disable-libxml2 - --disable-pciaccess --disable-levelzero CFLAGS=-fPIC - CXXFLAGS=-fPIC + --disable-pciaccess --disable-levelzero --disable-opencl + --disable-cuda --disable-nvml CFLAGS=-fPIC CXXFLAGS=-fPIC WORKING_DIRECTORY ${hwloc_targ_SOURCE_DIR} OUTPUT ${hwloc_targ_SOURCE_DIR}/Makefile DEPENDS ${hwloc_targ_SOURCE_DIR}/configure) From 61a58531d4aefae8ebe2ec9a6aa1e27c3e557ac7 Mon Sep 17 00:00:00 2001 From: Igor Chorazewicz Date: Thu, 22 Aug 2024 00:50:59 +0200 Subject: [PATCH 054/352] Add support for making memory resident on given devices in L0 provider --- include/umf/providers/provider_level_zero.h | 15 +++++++++++++-- src/provider/provider_level_zero.c | 20 +++++++++++++++++++- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/include/umf/providers/provider_level_zero.h b/include/umf/providers/provider_level_zero.h index f0c2acfbc..9685c8530 100644 --- a/include/umf/providers/provider_level_zero.h +++ b/include/umf/providers/provider_level_zero.h @@ -14,6 +14,9 @@ extern "C" { #endif +typedef struct _ze_context_handle_t *ze_context_handle_t; +typedef struct _ze_device_handle_t *ze_device_handle_t; + /// @brief USM memory allocation type typedef enum umf_usm_memory_type_t { UMF_MEMORY_TYPE_UNKNOWN = 0, ///< The memory pointed to is of unknown type @@ -24,9 +27,17 @@ typedef enum umf_usm_memory_type_t { /// @brief Level Zero Memory Provider settings struct typedef struct level_zero_memory_provider_params_t { - void *level_zero_context_handle; ///< Handle to the Level Zero context - void *level_zero_device_handle; ///< Handle to the Level Zero device + ze_context_handle_t + level_zero_context_handle; ///< Handle to the Level Zero context + ze_device_handle_t + level_zero_device_handle; ///< Handle to the Level Zero device + umf_usm_memory_type_t memory_type; ///< Allocation memory type + + ze_device_handle_t * + resident_device_handles; ///< Array of devices for which the memory should be made resident + uint32_t + resident_device_count; ///< Number of devices for which the memory should be made resident } level_zero_memory_provider_params_t; umf_memory_provider_ops_t *umfLevelZeroMemoryProviderOps(void); diff --git a/src/provider/provider_level_zero.c b/src/provider/provider_level_zero.c index 3f7340556..ac86b4771 100644 --- a/src/provider/provider_level_zero.c +++ b/src/provider/provider_level_zero.c @@ -27,6 +27,9 @@ typedef struct ze_memory_provider_t { ze_context_handle_t context; ze_device_handle_t device; ze_memory_type_t memory_type; + + ze_device_handle_t *resident_device_handles; + uint32_t resident_device_count; } ze_memory_provider_t; typedef struct ze_ops_t { @@ -48,6 +51,9 @@ typedef struct ze_ops_t { ze_ipc_mem_handle_t, ze_ipc_memory_flags_t, void **); ze_result_t (*zeMemCloseIpcHandle)(ze_context_handle_t, void *); + ze_result_t (*zeContextMakeMemoryResident)(ze_context_handle_t, + ze_device_handle_t, void *, + size_t); } ze_ops_t; static ze_ops_t g_ze_ops; @@ -78,11 +84,14 @@ static void init_ze_global_state(void) { util_get_symbol_addr(0, "zeMemOpenIpcHandle", lib_name); *(void **)&g_ze_ops.zeMemCloseIpcHandle = util_get_symbol_addr(0, "zeMemCloseIpcHandle", lib_name); + *(void **)&g_ze_ops.zeContextMakeMemoryResident = + util_get_symbol_addr(0, "zeContextMakeMemoryResident", lib_name); if (!g_ze_ops.zeMemAllocHost || !g_ze_ops.zeMemAllocDevice || !g_ze_ops.zeMemAllocShared || !g_ze_ops.zeMemFree || !g_ze_ops.zeMemGetIpcHandle || !g_ze_ops.zeMemOpenIpcHandle || - !g_ze_ops.zeMemCloseIpcHandle) { + !g_ze_ops.zeMemCloseIpcHandle || + !g_ze_ops.zeContextMakeMemoryResident) { // g_ze_ops.zeMemPutIpcHandle can be NULL because it was introduced // starting from Level Zero 1.6 LOG_ERR("Required Level Zero symbols not found."); @@ -181,6 +190,15 @@ static umf_result_t ze_memory_provider_alloc(void *provider, size_t size, return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; } + for (uint32_t i = 0; i < ze_provider->resident_device_count; i++) { + ze_result = g_ze_ops.zeContextMakeMemoryResident( + ze_provider->context, ze_provider->resident_device_handles[i], + *resultPtr, size); + if (ze_result != ZE_RESULT_SUCCESS) { + break; + } + } + // TODO add error reporting return (ze_result == ZE_RESULT_SUCCESS) ? UMF_RESULT_SUCCESS From 2bfecddf205f91438661f7c70db464e9d0426e9b Mon Sep 17 00:00:00 2001 From: Rafal Rudnicki Date: Wed, 21 Aug 2024 16:41:27 +0200 Subject: [PATCH 055/352] fix coverity issues in hwloc --- CMakeLists.txt | 19 +++++++++++++++++-- cmake/fix_coverity_issues.patch | 14 ++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 cmake/fix_coverity_issues.patch diff --git a/CMakeLists.txt b/CMakeLists.txt index dfe433c7f..2deabd371 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -127,6 +127,12 @@ else() set(HWLOC_ENABLE_TESTING OFF) set(HWLOC_SKIP_LSTOPO ON) set(HWLOC_SKIP_TOOLS ON) + set(HWLOC_PATCH + git + apply + ${PROJECT_SOURCE_DIR}/cmake/fix_coverity_issues.patch + || + true) message( STATUS @@ -137,7 +143,8 @@ else() hwloc_targ GIT_REPOSITORY ${UMF_HWLOC_REPO} GIT_TAG ${UMF_HWLOC_TAG} - SOURCE_SUBDIR contrib/windows-cmake/ FIND_PACKAGE_ARGS) + PATCH_COMMAND ${HWLOC_PATCH} SOURCE_SUBDIR contrib/windows-cmake/ + FIND_PACKAGE_ARGS) FetchContent_GetProperties(hwloc_targ) if(NOT hwloc_targ_POPULATED) @@ -150,6 +157,13 @@ else() ${hwloc_targ_BINARY_DIR}/Release;${hwloc_targ_BINARY_DIR}/Debug) else() include(FetchContent) + set(HWLOC_PATCH + git + apply + ${PROJECT_SOURCE_DIR}/cmake/fix_coverity_issues.patch + || + true) + message( STATUS "Will fetch hwloc from ${UMF_HWLOC_REPO} (tag: ${UMF_HWLOC_TAG})" @@ -158,7 +172,8 @@ else() FetchContent_Declare( hwloc_targ GIT_REPOSITORY ${UMF_HWLOC_REPO} - GIT_TAG ${UMF_HWLOC_TAG}) + GIT_TAG ${UMF_HWLOC_TAG} + PATCH_COMMAND ${HWLOC_PATCH}) FetchContent_GetProperties(hwloc_targ) if(NOT hwloc_targ_POPULATED) diff --git a/cmake/fix_coverity_issues.patch b/cmake/fix_coverity_issues.patch new file mode 100644 index 000000000..1edcbd336 --- /dev/null +++ b/cmake/fix_coverity_issues.patch @@ -0,0 +1,14 @@ +diff --git a/hwloc/topology-x86.c b/hwloc/topology-x86.c +index 7aabd168f..b01e44557 100644 +--- a/hwloc/topology-x86.c ++++ b/hwloc/topology-x86.c +@@ -1375,6 +1375,9 @@ look_procs(struct hwloc_backend *backend, struct procinfo *infos, unsigned long + hwloc_bitmap_t set = NULL; + unsigned i; + ++ if(!get_cpubind||!set_cpubind) ++ return -1; ++ + if (!data->src_cpuiddump_path) { + orig_cpuset = hwloc_bitmap_alloc(); + if (get_cpubind(topology, orig_cpuset, HWLOC_CPUBIND_STRICT)) { From 8f242a51bf1eb3cfcd547803fa46db10adb90edd Mon Sep 17 00:00:00 2001 From: Igor Chorazewicz Date: Thu, 22 Aug 2024 01:03:51 +0200 Subject: [PATCH 056/352] Allow allocations bigger than maxMemAllocSize in L0 provider by using ZE_RELAXED_ALLOCATION_LIMITS_EXP_FLAG_MAX_SIZE flag when appropriate. --- src/provider/provider_level_zero.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/provider/provider_level_zero.c b/src/provider/provider_level_zero.c index ac86b4771..87fed7851 100644 --- a/src/provider/provider_level_zero.c +++ b/src/provider/provider_level_zero.c @@ -30,6 +30,8 @@ typedef struct ze_memory_provider_t { ze_device_handle_t *resident_device_handles; uint32_t resident_device_count; + + ze_device_properties_t device_properties; } ze_memory_provider_t; typedef struct ze_ops_t { @@ -54,6 +56,8 @@ typedef struct ze_ops_t { ze_result_t (*zeContextMakeMemoryResident)(ze_context_handle_t, ze_device_handle_t, void *, size_t); + ze_result_t (*zeDeviceGetProperties)(ze_device_handle_t, + ze_device_properties_t *); } ze_ops_t; static ze_ops_t g_ze_ops; @@ -86,12 +90,15 @@ static void init_ze_global_state(void) { util_get_symbol_addr(0, "zeMemCloseIpcHandle", lib_name); *(void **)&g_ze_ops.zeContextMakeMemoryResident = util_get_symbol_addr(0, "zeContextMakeMemoryResident", lib_name); + *(void **)&g_ze_ops.zeDeviceGetProperties = + util_get_symbol_addr(0, "zeDeviceGetProperties", lib_name); if (!g_ze_ops.zeMemAllocHost || !g_ze_ops.zeMemAllocDevice || !g_ze_ops.zeMemAllocShared || !g_ze_ops.zeMemFree || !g_ze_ops.zeMemGetIpcHandle || !g_ze_ops.zeMemOpenIpcHandle || !g_ze_ops.zeMemCloseIpcHandle || - !g_ze_ops.zeContextMakeMemoryResident) { + !g_ze_ops.zeContextMakeMemoryResident || + !g_ze_ops.zeDeviceGetProperties) { // g_ze_ops.zeMemPutIpcHandle can be NULL because it was introduced // starting from Level Zero 1.6 LOG_ERR("Required Level Zero symbols not found."); @@ -123,6 +130,13 @@ umf_result_t ze_memory_provider_initialize(void *params, void **provider) { ze_provider->device = ze_params->level_zero_device_handle; ze_provider->memory_type = (ze_memory_type_t)ze_params->memory_type; + ze_result_t ret = g_ze_ops.zeDeviceGetProperties( + ze_provider->device, &ze_provider->device_properties); + if (ret != ZE_RESULT_SUCCESS) { + umf_ba_global_free(ze_provider); + return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; + } + *provider = ze_provider; return UMF_RESULT_SUCCESS; @@ -147,6 +161,16 @@ static umf_result_t ze_memory_provider_alloc(void *provider, size_t size, ze_memory_provider_t *ze_provider = (ze_memory_provider_t *)provider; + bool useRelaxedAllocationFlag = + size > ze_provider->device_properties.maxMemAllocSize; + ze_relaxed_allocation_limits_exp_desc_t relaxed_desc = { + .stype = ZE_STRUCTURE_TYPE_RELAXED_ALLOCATION_LIMITS_EXP_DESC, + .pNext = NULL, + .flags = 0}; + if (useRelaxedAllocationFlag) { + relaxed_desc.flags = ZE_RELAXED_ALLOCATION_LIMITS_EXP_FLAG_MAX_SIZE; + } + ze_result_t ze_result = ZE_RESULT_SUCCESS; switch (ze_provider->memory_type) { case UMF_MEMORY_TYPE_HOST: { @@ -161,7 +185,7 @@ static umf_result_t ze_memory_provider_alloc(void *provider, size_t size, case UMF_MEMORY_TYPE_DEVICE: { ze_device_mem_alloc_desc_t dev_desc = { .stype = ZE_STRUCTURE_TYPE_HOST_MEM_ALLOC_DESC, - .pNext = NULL, + .pNext = useRelaxedAllocationFlag ? &relaxed_desc : NULL, .flags = 0, .ordinal = 0 // TODO }; @@ -177,7 +201,7 @@ static umf_result_t ze_memory_provider_alloc(void *provider, size_t size, .flags = 0}; ze_device_mem_alloc_desc_t dev_desc = { .stype = ZE_STRUCTURE_TYPE_DEVICE_MEM_ALLOC_DESC, - .pNext = NULL, + .pNext = useRelaxedAllocationFlag ? &relaxed_desc : NULL, .flags = 0, .ordinal = 0 // TODO }; From e8c0fc44b0e6fbe096eb2a85601ba96404ff8386 Mon Sep 17 00:00:00 2001 From: Igor Chorazewicz Date: Thu, 22 Aug 2024 21:46:36 +0200 Subject: [PATCH 057/352] Implement getLastNativeError for L0 provider --- src/provider/provider_level_zero.c | 59 +++++++++++++++++++----------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/src/provider/provider_level_zero.c b/src/provider/provider_level_zero.c index 87fed7851..42d0783a1 100644 --- a/src/provider/provider_level_zero.c +++ b/src/provider/provider_level_zero.c @@ -63,6 +63,25 @@ typedef struct ze_ops_t { static ze_ops_t g_ze_ops; static UTIL_ONCE_FLAG ze_is_initialized = UTIL_ONCE_FLAG_INIT; static bool Init_ze_global_state_failed; +static __TLS ze_result_t TLS_last_native_error; + +static void store_last_native_error(int32_t native_error) { + TLS_last_native_error = native_error; +} + +umf_result_t ze2umf_result(ze_result_t result) { + switch (result) { + case ZE_RESULT_SUCCESS: + return UMF_RESULT_SUCCESS; + case ZE_RESULT_ERROR_OUT_OF_HOST_MEMORY: + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + case ZE_RESULT_ERROR_INVALID_ARGUMENT: + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + default: + store_last_native_error(result); + return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; + } +} static void init_ze_global_state(void) { #ifdef _WIN32 @@ -130,11 +149,12 @@ umf_result_t ze_memory_provider_initialize(void *params, void **provider) { ze_provider->device = ze_params->level_zero_device_handle; ze_provider->memory_type = (ze_memory_type_t)ze_params->memory_type; - ze_result_t ret = g_ze_ops.zeDeviceGetProperties( - ze_provider->device, &ze_provider->device_properties); - if (ret != ZE_RESULT_SUCCESS) { + umf_result_t ret = ze2umf_result(g_ze_ops.zeDeviceGetProperties( + ze_provider->device, &ze_provider->device_properties)); + + if (ret != UMF_RESULT_SUCCESS) { umf_ba_global_free(ze_provider); - return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; + return ret; } *provider = ze_provider; @@ -211,7 +231,11 @@ static umf_result_t ze_memory_provider_alloc(void *provider, size_t size, break; } default: - return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + if (ze_result != ZE_RESULT_SUCCESS) { + return ze2umf_result(ze_result); } for (uint32_t i = 0; i < ze_provider->resident_device_count; i++) { @@ -219,14 +243,11 @@ static umf_result_t ze_memory_provider_alloc(void *provider, size_t size, ze_provider->context, ze_provider->resident_device_handles[i], *resultPtr, size); if (ze_result != ZE_RESULT_SUCCESS) { - break; + return ze2umf_result(ze_result); } } - // TODO add error reporting - return (ze_result == ZE_RESULT_SUCCESS) - ? UMF_RESULT_SUCCESS - : UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; + return ze2umf_result(ze_result); } static umf_result_t ze_memory_provider_free(void *provider, void *ptr, @@ -236,11 +257,7 @@ static umf_result_t ze_memory_provider_free(void *provider, void *ptr, assert(provider); ze_memory_provider_t *ze_provider = (ze_memory_provider_t *)provider; ze_result_t ze_result = g_ze_ops.zeMemFree(ze_provider->context, ptr); - - // TODO add error reporting - return (ze_result == ZE_RESULT_SUCCESS) - ? UMF_RESULT_SUCCESS - : UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; + return ze2umf_result(ze_result); } void ze_memory_provider_get_last_native_error(void *provider, @@ -249,9 +266,9 @@ void ze_memory_provider_get_last_native_error(void *provider, (void)provider; (void)ppMessage; - // TODO assert(pError); - *pError = 0; + + *pError = TLS_last_native_error; } static umf_result_t ze_memory_provider_get_min_page_size(void *provider, @@ -356,7 +373,7 @@ static umf_result_t ze_memory_provider_get_ipc_handle(void *provider, &ze_ipc_data->ze_handle); if (ze_result != ZE_RESULT_SUCCESS) { LOG_ERR("zeMemGetIpcHandle() failed."); - return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; + return ze2umf_result(ze_result); } ze_ipc_data->pid = utils_getpid(); @@ -384,7 +401,7 @@ static umf_result_t ze_memory_provider_put_ipc_handle(void *provider, ze_ipc_data->ze_handle); if (ze_result != ZE_RESULT_SUCCESS) { LOG_ERR("zeMemPutIpcHandle() failed."); - return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; + return ze2umf_result(ze_result); } return UMF_RESULT_SUCCESS; } @@ -421,7 +438,7 @@ static umf_result_t ze_memory_provider_open_ipc_handle(void *provider, } if (ze_result != ZE_RESULT_SUCCESS) { LOG_ERR("zeMemOpenIpcHandle() failed."); - return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; + return ze2umf_result(ze_result); } return UMF_RESULT_SUCCESS; @@ -439,7 +456,7 @@ ze_memory_provider_close_ipc_handle(void *provider, void *ptr, size_t size) { ze_result = g_ze_ops.zeMemCloseIpcHandle(ze_provider->context, ptr); if (ze_result != ZE_RESULT_SUCCESS) { LOG_ERR("zeMemCloseIpcHandle() failed."); - return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; + return ze2umf_result(ze_result); } return UMF_RESULT_SUCCESS; From 2c8dadb44074d9e42ea53c10b28c4ca62e75fe68 Mon Sep 17 00:00:00 2001 From: Igor Chorazewicz Date: Thu, 15 Aug 2024 23:44:48 +0200 Subject: [PATCH 058/352] Add option to use local L0 include dir Turning UMF_BUILD_LEVEL_ZERO_PROVIDER on in UR results in configuration errors as both projects try to fetch and build L0 loader. --- src/CMakeLists.txt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3b407f7f2..07517d70f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,12 +4,17 @@ include(${UMF_CMAKE_SOURCE_DIR}/cmake/helpers.cmake) +set(UMF_LEVEL_ZERO_INCLUDE_DIR + "" + CACHE FILEPATH "Directory containing the Level Zero Headers") + # Compile definitions for UMF library. # # TODO: Cleanup the compile definitions across all the CMake files set(UMF_COMMON_COMPILE_DEFINITIONS UMF_VERSION=${UMF_VERSION}) -if(UMF_BUILD_LEVEL_ZERO_PROVIDER) +if(UMF_BUILD_LEVEL_ZERO_PROVIDER AND (UMF_BUILD_GPU_TESTS + OR (NOT UMF_LEVEL_ZERO_INCLUDE_DIR))) include(FetchContent) set(LEVEL_ZERO_LOADER_REPO "https://github.com/oneapi-src/level-zero.git") @@ -35,6 +40,10 @@ if(UMF_BUILD_LEVEL_ZERO_PROVIDER) ${level-zero-loader_SOURCE_DIR}/include CACHE PATH "Path to Level Zero Headers") message(STATUS "Level Zero include directory: ${LEVEL_ZERO_INCLUDE_DIRS}") +elseif(UMF_BUILD_LEVEL_ZERO_PROVIDER) + # Only header is needed to build UMF + set(LEVEL_ZERO_INCLUDE_DIRS ${UMF_LEVEL_ZERO_INCLUDE_DIR}) + message(STATUS "Level Zero include directory: ${LEVEL_ZERO_INCLUDE_DIRS}") endif() add_subdirectory(utils) From 10d4f9d6e8906b3339081670d15ac39c3fdf8325 Mon Sep 17 00:00:00 2001 From: Agata Momot Date: Fri, 16 Aug 2024 13:20:07 +0200 Subject: [PATCH 059/352] fix: substitute UT_ASSERTs with asserts from GTEST Ref. #569 --- test/memspaces/memspace_fixtures.hpp | 48 ++++++++++++++-------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/test/memspaces/memspace_fixtures.hpp b/test/memspaces/memspace_fixtures.hpp index 5aaaed787..52f21c934 100644 --- a/test/memspaces/memspace_fixtures.hpp +++ b/test/memspaces/memspace_fixtures.hpp @@ -108,8 +108,8 @@ TEST_P(memspaceGetTest, providerFromMemspace) { umf_memory_provider_handle_t hProvider = nullptr; umf_result_t ret = umfMemoryProviderCreateFromMemspace(hMemspace, nullptr, &hProvider); - UT_ASSERTeq(ret, UMF_RESULT_SUCCESS); - UT_ASSERTne(hProvider, nullptr); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(hProvider, nullptr); umfMemoryProviderDestroy(hProvider); } @@ -120,15 +120,15 @@ TEST_P(memspaceProviderTest, allocFree) { size_t alignment = 0; umf_result_t ret = umfMemoryProviderAlloc(hProvider, size, alignment, &ptr); - UT_ASSERTeq(ret, UMF_RESULT_SUCCESS); - UT_ASSERTne(ptr, nullptr); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(ptr, nullptr); // Access the allocation, so that all the pages associated with it are // allocated on some NUMA node. memset(ptr, 0xFF, size); ret = umfMemoryProviderFree(hProvider, ptr, size); - UT_ASSERTeq(ret, UMF_RESULT_SUCCESS); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); } static std::vector getAllCpus() { @@ -148,20 +148,20 @@ TEST_P(memspaceProviderTest, allocLocalMt) { auto pinAllocValidate = [&](umf_memory_provider_handle_t hProvider, int cpu) { hwloc_topology_t topology = NULL; - UT_ASSERTeq(hwloc_topology_init(&topology), 0); - UT_ASSERTeq(hwloc_topology_load(topology), 0); + ASSERT_EQ(hwloc_topology_init(&topology), 0); + ASSERT_EQ(hwloc_topology_load(topology), 0); // Pin current thread to the provided CPU. hwloc_cpuset_t pinCpuset = hwloc_bitmap_alloc(); - UT_ASSERTeq(hwloc_bitmap_set(pinCpuset, cpu), 0); - UT_ASSERTeq( - hwloc_set_cpubind(topology, pinCpuset, HWLOC_CPUBIND_THREAD), 0); + ASSERT_EQ(hwloc_bitmap_set(pinCpuset, cpu), 0); + ASSERT_EQ(hwloc_set_cpubind(topology, pinCpuset, HWLOC_CPUBIND_THREAD), + 0); // Confirm that the thread is pinned to the provided CPU. hwloc_cpuset_t curCpuset = hwloc_bitmap_alloc(); - UT_ASSERTeq( - hwloc_get_cpubind(topology, curCpuset, HWLOC_CPUBIND_THREAD), 0); - UT_ASSERT(hwloc_bitmap_isequal(curCpuset, pinCpuset)); + ASSERT_EQ(hwloc_get_cpubind(topology, curCpuset, HWLOC_CPUBIND_THREAD), + 0); + ASSERT_TRUE(hwloc_bitmap_isequal(curCpuset, pinCpuset)); hwloc_bitmap_free(curCpuset); hwloc_bitmap_free(pinCpuset); @@ -172,8 +172,8 @@ TEST_P(memspaceProviderTest, allocLocalMt) { umf_result_t ret = umfMemoryProviderAlloc(hProvider, size, alignment, &ptr); - UT_ASSERTeq(ret, UMF_RESULT_SUCCESS); - UT_ASSERTne(ptr, nullptr); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(ptr, nullptr); // Access the allocation, so that all the pages associated with it are // allocated on some NUMA node. @@ -194,20 +194,20 @@ TEST_P(memspaceProviderTest, allocLocalMt) { hwloc_location loc; loc.location.object = allocNodeObj, loc.type = hwloc_location_type_alias::HWLOC_LOCATION_TYPE_OBJECT; - UT_ASSERTeq(hwloc_get_local_numanode_objs(topology, &loc, &nNodes, - localNodes.data(), 0), - 0); - UT_ASSERT(nNodes <= MAX_NODES); + ASSERT_EQ(hwloc_get_local_numanode_objs(topology, &loc, &nNodes, + localNodes.data(), 0), + 0); + ASSERT_LE(nNodes, MAX_NODES); // Confirm that the allocation from this thread was made to a local // NUMA node. - UT_ASSERT(std::any_of(localNodes.begin(), localNodes.end(), - [&allocNodeObj](hwloc_obj_t node) { - return node == allocNodeObj; - })); + ASSERT_TRUE(std::any_of(localNodes.begin(), localNodes.end(), + [&allocNodeObj](hwloc_obj_t node) { + return node == allocNodeObj; + })); ret = umfMemoryProviderFree(hProvider, ptr, size); - UT_ASSERTeq(ret, UMF_RESULT_SUCCESS); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); hwloc_topology_destroy(topology); }; From 0e094b71927e23a5d0a2b5762fa02d5d3c89f54a Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 26 Aug 2024 14:44:11 +0200 Subject: [PATCH 060/352] Change the name of the install dependencies step in fastbuild fix #629 --- .github/workflows/fast.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/fast.yml b/.github/workflows/fast.yml index 3bf8e5248..1e980c3e2 100644 --- a/.github/workflows/fast.yml +++ b/.github/workflows/fast.yml @@ -70,18 +70,18 @@ jobs: vcpkgDirectory: ${{env.BUILD_DIR}}/vcpkg vcpkgJsonGlob: '**/vcpkg.json' - - name: Install dependencies + - name: Install dependencies (windows-latest) if: matrix.os == 'windows-latest' run: vcpkg install shell: pwsh # Specifies PowerShell as the shell for running the script. - - name: Install apt packages (ubuntu-latest) + - name: Install dependencies (ubuntu-latest) if: matrix.os == 'ubuntu-latest' run: | sudo apt-get update sudo apt-get install -y cmake libjemalloc-dev libhwloc-dev libnuma-dev libtbb-dev - - name: Install apt packages (ubuntu-20.04) + - name: Install dependencies (ubuntu-20.04) if: matrix.os == 'ubuntu-20.04' run: | sudo apt-get update From 50f1d7cd21257772777c9adff26c7109810ed787 Mon Sep 17 00:00:00 2001 From: Rafal Rudnicki Date: Mon, 26 Aug 2024 14:54:30 +0200 Subject: [PATCH 061/352] use *_DLL_DIRS env --- CMakeLists.txt | 6 +++--- cmake/FindJEMALLOC.cmake | 2 +- cmake/FindTBB.cmake | 2 +- examples/cmake/FindLIBHWLOC.cmake | 2 +- examples/cmake/FindTBB.cmake | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dfe433c7f..57477daac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -120,7 +120,7 @@ else() # add PATH to DLL on Windows set(DLL_PATH_LIST - "${DLL_PATH_LIST};PATH=path_list_append:${LIBHWLOC_LIBRARY_DIRS}/../bin" + "${DLL_PATH_LIST};PATH=path_list_append:${LIBHWLOC_DLL_DIRS}" ) elseif(WINDOWS) include(FetchContent) @@ -322,7 +322,7 @@ endif() if(TBB_FOUND OR TBB_LIBRARY_DIRS) # add PATH to DLL on Windows set(DLL_PATH_LIST - "${DLL_PATH_LIST};PATH=path_list_append:${TBB_LIBRARY_DIRS}/../bin") + "${DLL_PATH_LIST};PATH=path_list_append:${TBB_DLL_DIRS}") set(UMF_POOL_SCALABLE_ENABLED TRUE) else() message( @@ -339,7 +339,7 @@ if(UMF_BUILD_LIBUMF_POOL_JEMALLOC) endif() # add PATH to DLL on Windows set(DLL_PATH_LIST - "${DLL_PATH_LIST};PATH=path_list_append:${JEMALLOC_LIBRARY_DIRS}/../bin" + "${DLL_PATH_LIST};PATH=path_list_append:${JEMALLOC_DLL_DIRS}" ) endif() diff --git a/cmake/FindJEMALLOC.cmake b/cmake/FindJEMALLOC.cmake index f01301d25..89d488ecc 100644 --- a/cmake/FindJEMALLOC.cmake +++ b/cmake/FindJEMALLOC.cmake @@ -28,7 +28,7 @@ else() endif() if(WINDOWS) - find_file(JEMALLOC_DLL NAMES "bin/jemalloc.dll") + find_file(JEMALLOC_DLL NAMES "bin/jemalloc.dll" "jemalloc.dll") get_filename_component(JEMALLOC_DLL_DIR ${JEMALLOC_DLL} DIRECTORY) set(JEMALLOC_DLL_DIRS ${JEMALLOC_DLL_DIR}) endif() diff --git a/cmake/FindTBB.cmake b/cmake/FindTBB.cmake index 8aa6289ef..6536e8c4a 100644 --- a/cmake/FindTBB.cmake +++ b/cmake/FindTBB.cmake @@ -26,7 +26,7 @@ else() endif() if(WINDOWS) - find_file(TBB_DLL NAMES "bin/tbbmalloc.dll") + find_file(TBB_DLL NAMES "bin/tbbmalloc.dll" "tbbmalloc.dll") get_filename_component(TBB_DLL_DIR ${TBB_DLL} DIRECTORY) set(TBB_DLL_DIRS ${TBB_DLL_DIR}) endif() diff --git a/examples/cmake/FindLIBHWLOC.cmake b/examples/cmake/FindLIBHWLOC.cmake index f4e33417a..698946829 100644 --- a/examples/cmake/FindLIBHWLOC.cmake +++ b/examples/cmake/FindLIBHWLOC.cmake @@ -38,7 +38,7 @@ try_run( RUN_OUTPUT_VARIABLE LIBHWLOC_API_VERSION) if(WINDOWS) - find_file(LIBHWLOC_DLL NAMES "bin/hwloc-15.dll" "bin/libhwloc-15.dll") + find_file(LIBHWLOC_DLL NAMES "bin/hwloc-15.dll" "bin/libhwloc-15.dll" "hwloc-15.dll" "libhwloc-15.dll") get_filename_component(LIBHWLOC_DLL_DIR ${LIBHWLOC_DLL} DIRECTORY) set(LIBHWLOC_DLL_DIRS ${LIBHWLOC_DLL_DIR}) endif() diff --git a/examples/cmake/FindTBB.cmake b/examples/cmake/FindTBB.cmake index 8aa6289ef..6536e8c4a 100644 --- a/examples/cmake/FindTBB.cmake +++ b/examples/cmake/FindTBB.cmake @@ -26,7 +26,7 @@ else() endif() if(WINDOWS) - find_file(TBB_DLL NAMES "bin/tbbmalloc.dll") + find_file(TBB_DLL NAMES "bin/tbbmalloc.dll" "tbbmalloc.dll") get_filename_component(TBB_DLL_DIR ${TBB_DLL} DIRECTORY) set(TBB_DLL_DIRS ${TBB_DLL_DIR}) endif() From 7a8c1d60bc1e39fbef096e10fd7342664bc3ba5f Mon Sep 17 00:00:00 2001 From: Rafal Rudnicki Date: Mon, 26 Aug 2024 14:54:51 +0200 Subject: [PATCH 062/352] add custom hwloc lib name --- .github/workflows/basic.yml | 50 +++++++++++++++++++++++++++++++ CMakeLists.txt | 13 ++++---- cmake/FindLIBHWLOC.cmake | 5 ++-- examples/cmake/FindLIBHWLOC.cmake | 3 +- src/CMakeLists.txt | 4 +-- 5 files changed, 64 insertions(+), 11 deletions(-) diff --git a/.github/workflows/basic.yml b/.github/workflows/basic.yml index 30ab2e600..168dca7fb 100644 --- a/.github/workflows/basic.yml +++ b/.github/workflows/basic.yml @@ -348,6 +348,56 @@ jobs: -DUMF_TESTS_FAIL_ON_SKIP=ON -DUMF_LINK_HWLOC_STATICALLY=ON + - name: Build UMF + run: cmake --build ${{env.BUILD_DIR}} --config ${{matrix.build_type}} -j $Env:NUMBER_OF_PROCESSORS -v + + - name: Run tests + working-directory: ${{env.BUILD_DIR}} + run: ctest -C ${{matrix.build_type}} --output-on-failure --test-dir test + + windows-dynamic_mingw_hwloc: + env: + HWLOC_PACKAGE_NAME: hwloc-win64-build-2.10.0 + TBB_PACKAGE_NAME: oneapi-tbb-2021.12.0 + TBB_LIB_DIR: lib\intel64\vc14 + TBB_BIN_DIR: redist\intel64\vc14 + + name: "Windows dynamic UMF + mingw libhwloc" + strategy: + matrix: + build_type: [Release] + + runs-on: 'windows-2022' + + steps: + - name: Checkout + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + + - name: Get hwloc from official repo (mingw version) + run: | + Invoke-WebRequest -Uri https://download.open-mpi.org/release/hwloc/v2.10/${{env.HWLOC_PACKAGE_NAME}}.zip -OutFile ${{github.workspace}}\${{env.HWLOC_PACKAGE_NAME}}.zip -TimeoutSec 360 + Expand-Archive ${{github.workspace}}\${{env.HWLOC_PACKAGE_NAME}}.zip -DestinationPath ${{github.workspace}} + + - name: Get TBB from github + run: | + Invoke-WebRequest -Uri https://github.com/oneapi-src/oneTBB/releases/download/v2021.12.0/${{env.TBB_PACKAGE_NAME}}-win.zip -OutFile "${{github.workspace}}\${{env.TBB_PACKAGE_NAME}}-win.zip" -TimeoutSec 360 + Expand-Archive "${{github.workspace}}\${{env.TBB_PACKAGE_NAME}}-win.zip" -DestinationPath ${{github.workspace}} + + - name: Configure build + run: > + cmake + -B ${{env.BUILD_DIR}} + -DCMAKE_INSTALL_PREFIX="${{env.INSTL_DIR}}" + -DCMAKE_PREFIX_PATH="${{github.workspace}}\${{env.HWLOC_PACKAGE_NAME}};${{github.workspace}}\${{env.TBB_PACKAGE_NAME}};${{github.workspace}}\${{env.TBB_PACKAGE_NAME}}\${{env.TBB_LIB_DIR}};${{github.workspace}}\${{env.TBB_PACKAGE_NAME}}\${{env.TBB_BIN_DIR}}" + -DUMF_BUILD_SHARED_LIBRARY=ON + -DUMF_BUILD_EXAMPLES=ON + -DUMF_FORMAT_CODE_STYLE=OFF + -DUMF_DEVELOPER_MODE=ON + -DUMF_TESTS_FAIL_ON_SKIP=ON + -DUMF_HWLOC_NAME=libhwloc + - name: Build UMF run: cmake --build ${{env.BUILD_DIR}} --config ${{matrix.build_type}} -j $Env:NUMBER_OF_PROCESSORS diff --git a/CMakeLists.txt b/CMakeLists.txt index 57477daac..b7da82033 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,6 +59,10 @@ option( option(UMF_FORMAT_CODE_STYLE "Add clang, cmake, and black -format-check and -format-apply targets" OFF) +set(UMF_HWLOC_NAME + "hwloc" + CACHE STRING "Custom name for hwloc library w/o extension") + # Only a part of skips is treated as a failure now. TODO: extend to all tests option(UMF_TESTS_FAIL_ON_SKIP "Treat skips in tests as fail" OFF) option(UMF_USE_ASAN "Enable AddressSanitizer checks" OFF) @@ -120,8 +124,7 @@ else() # add PATH to DLL on Windows set(DLL_PATH_LIST - "${DLL_PATH_LIST};PATH=path_list_append:${LIBHWLOC_DLL_DIRS}" - ) + "${DLL_PATH_LIST};PATH=path_list_append:${LIBHWLOC_DLL_DIRS}") elseif(WINDOWS) include(FetchContent) set(HWLOC_ENABLE_TESTING OFF) @@ -321,8 +324,7 @@ if(NOT TBB_FOUND) endif() if(TBB_FOUND OR TBB_LIBRARY_DIRS) # add PATH to DLL on Windows - set(DLL_PATH_LIST - "${DLL_PATH_LIST};PATH=path_list_append:${TBB_DLL_DIRS}") + set(DLL_PATH_LIST "${DLL_PATH_LIST};PATH=path_list_append:${TBB_DLL_DIRS}") set(UMF_POOL_SCALABLE_ENABLED TRUE) else() message( @@ -339,8 +341,7 @@ if(UMF_BUILD_LIBUMF_POOL_JEMALLOC) endif() # add PATH to DLL on Windows set(DLL_PATH_LIST - "${DLL_PATH_LIST};PATH=path_list_append:${JEMALLOC_DLL_DIRS}" - ) + "${DLL_PATH_LIST};PATH=path_list_append:${JEMALLOC_DLL_DIRS}") endif() if(WINDOWS) diff --git a/cmake/FindLIBHWLOC.cmake b/cmake/FindLIBHWLOC.cmake index f4e33417a..a7c9201a0 100644 --- a/cmake/FindLIBHWLOC.cmake +++ b/cmake/FindLIBHWLOC.cmake @@ -4,7 +4,7 @@ message(STATUS "Checking for module 'libhwloc' using find_library()") -find_library(LIBHWLOC_LIBRARY NAMES libhwloc hwloc) +find_library(LIBHWLOC_LIBRARY NAMES ${UMF_HWLOC_NAME}) set(LIBHWLOC_LIBRARIES ${LIBHWLOC_LIBRARY}) get_filename_component(LIBHWLOC_LIB_DIR ${LIBHWLOC_LIBRARIES} DIRECTORY) @@ -38,7 +38,8 @@ try_run( RUN_OUTPUT_VARIABLE LIBHWLOC_API_VERSION) if(WINDOWS) - find_file(LIBHWLOC_DLL NAMES "bin/hwloc-15.dll" "bin/libhwloc-15.dll") + find_file(LIBHWLOC_DLL NAMES "bin/${UMF_HWLOC_NAME}-15.dll" + "${UMF_HWLOC_NAME}-15.dll") get_filename_component(LIBHWLOC_DLL_DIR ${LIBHWLOC_DLL} DIRECTORY) set(LIBHWLOC_DLL_DIRS ${LIBHWLOC_DLL_DIR}) endif() diff --git a/examples/cmake/FindLIBHWLOC.cmake b/examples/cmake/FindLIBHWLOC.cmake index 698946829..aa7620bc2 100644 --- a/examples/cmake/FindLIBHWLOC.cmake +++ b/examples/cmake/FindLIBHWLOC.cmake @@ -38,7 +38,8 @@ try_run( RUN_OUTPUT_VARIABLE LIBHWLOC_API_VERSION) if(WINDOWS) - find_file(LIBHWLOC_DLL NAMES "bin/hwloc-15.dll" "bin/libhwloc-15.dll" "hwloc-15.dll" "libhwloc-15.dll") + find_file(LIBHWLOC_DLL NAMES "bin/hwloc-15.dll" "bin/libhwloc-15.dll" + "hwloc-15.dll" "libhwloc-15.dll") get_filename_component(LIBHWLOC_DLL_DIR ${LIBHWLOC_DLL} DIRECTORY) set(LIBHWLOC_DLL_DIRS ${LIBHWLOC_DLL_DIR}) endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3b407f7f2..c702a4c19 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -154,7 +154,7 @@ endif() if(UMF_BUILD_SHARED_LIBRARY) if(NOT UMF_DISABLE_HWLOC) - set(HWLOC_LIB hwloc) + set(HWLOC_LIB ${UMF_HWLOC_NAME}) endif() add_umf_library( NAME umf @@ -184,7 +184,7 @@ if(UMF_DISABLE_HWLOC) endif() if(UMF_LINK_HWLOC_STATICALLY) - add_dependencies(umf hwloc) + add_dependencies(umf ${UMF_HWLOC_NAME}) endif() target_link_directories(umf PRIVATE ${UMF_PRIVATE_LIBRARY_DIRS}) From 0d57f6971558066d11d82c31168474c4fa946e83 Mon Sep 17 00:00:00 2001 From: Igor Chorazewicz Date: Fri, 30 Aug 2024 02:16:06 +0200 Subject: [PATCH 063/352] L0 provider: do not accept device handle for HOST memory type and do not call zeDeviceGetProperties for HOST provider. Also, add extra checks for parameters. --- src/provider/provider_level_zero.c | 61 ++++++++++++------ test/providers/level_zero_helpers.cpp | 12 +++- test/providers/provider_level_zero.cpp | 89 +++++++++++++++++++++++++- 3 files changed, 140 insertions(+), 22 deletions(-) diff --git a/src/provider/provider_level_zero.c b/src/provider/provider_level_zero.c index 42d0783a1..1b4911980 100644 --- a/src/provider/provider_level_zero.c +++ b/src/provider/provider_level_zero.c @@ -133,6 +133,20 @@ umf_result_t ze_memory_provider_initialize(void *params, void **provider) { level_zero_memory_provider_params_t *ze_params = (level_zero_memory_provider_params_t *)params; + if (!ze_params->level_zero_context_handle) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + if ((ze_params->memory_type == UMF_MEMORY_TYPE_HOST) == + (bool)ze_params->level_zero_device_handle) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + if ((bool)ze_params->resident_device_count != + (bool)ze_params->resident_device_handles) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + util_init_once(&ze_is_initialized, init_ze_global_state); if (Init_ze_global_state_failed) { LOG_ERR("Loading Level Zero symbols failed"); @@ -149,12 +163,17 @@ umf_result_t ze_memory_provider_initialize(void *params, void **provider) { ze_provider->device = ze_params->level_zero_device_handle; ze_provider->memory_type = (ze_memory_type_t)ze_params->memory_type; - umf_result_t ret = ze2umf_result(g_ze_ops.zeDeviceGetProperties( - ze_provider->device, &ze_provider->device_properties)); + if (ze_provider->device) { + umf_result_t ret = ze2umf_result(g_ze_ops.zeDeviceGetProperties( + ze_provider->device, &ze_provider->device_properties)); - if (ret != UMF_RESULT_SUCCESS) { - umf_ba_global_free(ze_provider); - return ret; + if (ret != UMF_RESULT_SUCCESS) { + umf_ba_global_free(ze_provider); + return ret; + } + } else { + memset(&ze_provider->device_properties, 0, + sizeof(ze_provider->device_properties)); } *provider = ze_provider; @@ -173,6 +192,18 @@ void ze_memory_provider_finalize(void *provider) { memcpy(&ze_is_initialized, &is_initialized, sizeof(ze_is_initialized)); } +static bool use_relaxed_allocation(ze_memory_provider_t *ze_provider, + size_t size) { + assert(ze_provider->device); + assert(ze_provider->device_properties.maxMemAllocSize > 0); + return size > ze_provider->device_properties.maxMemAllocSize; +} + +static ze_relaxed_allocation_limits_exp_desc_t relaxed_device_allocation_desc = + {.stype = ZE_STRUCTURE_TYPE_RELAXED_ALLOCATION_LIMITS_EXP_DESC, + .pNext = NULL, + .flags = ZE_RELAXED_ALLOCATION_LIMITS_EXP_FLAG_MAX_SIZE}; + static umf_result_t ze_memory_provider_alloc(void *provider, size_t size, size_t alignment, void **resultPtr) { @@ -181,16 +212,6 @@ static umf_result_t ze_memory_provider_alloc(void *provider, size_t size, ze_memory_provider_t *ze_provider = (ze_memory_provider_t *)provider; - bool useRelaxedAllocationFlag = - size > ze_provider->device_properties.maxMemAllocSize; - ze_relaxed_allocation_limits_exp_desc_t relaxed_desc = { - .stype = ZE_STRUCTURE_TYPE_RELAXED_ALLOCATION_LIMITS_EXP_DESC, - .pNext = NULL, - .flags = 0}; - if (useRelaxedAllocationFlag) { - relaxed_desc.flags = ZE_RELAXED_ALLOCATION_LIMITS_EXP_FLAG_MAX_SIZE; - } - ze_result_t ze_result = ZE_RESULT_SUCCESS; switch (ze_provider->memory_type) { case UMF_MEMORY_TYPE_HOST: { @@ -204,8 +225,10 @@ static umf_result_t ze_memory_provider_alloc(void *provider, size_t size, } case UMF_MEMORY_TYPE_DEVICE: { ze_device_mem_alloc_desc_t dev_desc = { - .stype = ZE_STRUCTURE_TYPE_HOST_MEM_ALLOC_DESC, - .pNext = useRelaxedAllocationFlag ? &relaxed_desc : NULL, + .stype = ZE_STRUCTURE_TYPE_DEVICE_MEM_ALLOC_DESC, + .pNext = use_relaxed_allocation(ze_provider, size) + ? &relaxed_device_allocation_desc + : NULL, .flags = 0, .ordinal = 0 // TODO }; @@ -221,7 +244,9 @@ static umf_result_t ze_memory_provider_alloc(void *provider, size_t size, .flags = 0}; ze_device_mem_alloc_desc_t dev_desc = { .stype = ZE_STRUCTURE_TYPE_DEVICE_MEM_ALLOC_DESC, - .pNext = useRelaxedAllocationFlag ? &relaxed_desc : NULL, + .pNext = use_relaxed_allocation(ze_provider, size) + ? &relaxed_device_allocation_desc + : NULL, .flags = 0, .ordinal = 0 // TODO }; diff --git a/test/providers/level_zero_helpers.cpp b/test/providers/level_zero_helpers.cpp index 067bf6a15..06b3ae56e 100644 --- a/test/providers/level_zero_helpers.cpp +++ b/test/providers/level_zero_helpers.cpp @@ -668,8 +668,8 @@ int init_level_zero() { level_zero_memory_provider_params_t create_level_zero_prov_params(umf_usm_memory_type_t memory_type) { - level_zero_memory_provider_params_t params = {NULL, NULL, - UMF_MEMORY_TYPE_UNKNOWN}; + level_zero_memory_provider_params_t params = { + NULL, NULL, UMF_MEMORY_TYPE_UNKNOWN, NULL, 0}; uint32_t driver_idx = 0; ze_driver_handle_t hDriver; ze_device_handle_t hDevice; @@ -701,7 +701,13 @@ create_level_zero_prov_params(umf_usm_memory_type_t memory_type) { } params.level_zero_context_handle = hContext; - params.level_zero_device_handle = hDevice; + + if (memory_type == UMF_MEMORY_TYPE_HOST) { + params.level_zero_device_handle = NULL; + } else { + params.level_zero_device_handle = hDevice; + } + params.memory_type = memory_type; return params; diff --git a/test/providers/provider_level_zero.cpp b/test/providers/provider_level_zero.cpp index ae5ece59c..f1312a770 100644 --- a/test/providers/provider_level_zero.cpp +++ b/test/providers/provider_level_zero.cpp @@ -19,6 +19,89 @@ using umf_test::test; using namespace umf_test; +struct LevelZeroProviderInit + : public test, + public ::testing::WithParamInterface {}; + +INSTANTIATE_TEST_SUITE_P(, LevelZeroProviderInit, + ::testing::Values(UMF_MEMORY_TYPE_HOST, + UMF_MEMORY_TYPE_DEVICE, + UMF_MEMORY_TYPE_SHARED)); + +TEST_P(LevelZeroProviderInit, FailNullContext) { + umf_memory_provider_ops_t *ops = umfLevelZeroMemoryProviderOps(); + ASSERT_NE(ops, nullptr); + + auto memory_type = GetParam(); + + level_zero_memory_provider_params_t params = {nullptr, nullptr, memory_type, + nullptr, 0}; + + umf_memory_provider_handle_t provider = nullptr; + umf_result_t result = umfMemoryProviderCreate(ops, ¶ms, &provider); + ASSERT_EQ(result, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} + +TEST_P(LevelZeroProviderInit, FailNullDevice) { + if (GetParam() == UMF_MEMORY_TYPE_HOST) { + GTEST_SKIP() << "Host memory does not require device handle"; + } + + umf_memory_provider_ops_t *ops = umfLevelZeroMemoryProviderOps(); + ASSERT_NE(ops, nullptr); + + auto memory_type = GetParam(); + auto params = create_level_zero_prov_params(memory_type); + params.level_zero_device_handle = nullptr; + + umf_memory_provider_handle_t provider = nullptr; + umf_result_t result = umfMemoryProviderCreate(ops, ¶ms, &provider); + ASSERT_EQ(result, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} + +TEST_F(test, FailNonNullDevice) { + umf_memory_provider_ops_t *ops = umfLevelZeroMemoryProviderOps(); + ASSERT_NE(ops, nullptr); + + auto memory_type = UMF_MEMORY_TYPE_HOST; + + // prepare params for device to get non-null device handle + auto params = create_level_zero_prov_params(UMF_MEMORY_TYPE_DEVICE); + params.memory_type = memory_type; + + umf_memory_provider_handle_t provider = nullptr; + umf_result_t result = umfMemoryProviderCreate(ops, ¶ms, &provider); + ASSERT_EQ(result, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} + +TEST_F(test, FailMismatchedResidentHandlesCount) { + umf_memory_provider_ops_t *ops = umfLevelZeroMemoryProviderOps(); + ASSERT_NE(ops, nullptr); + + auto memory_type = UMF_MEMORY_TYPE_DEVICE; + + auto params = create_level_zero_prov_params(memory_type); + params.resident_device_count = 99; + + umf_memory_provider_handle_t provider = nullptr; + umf_result_t result = umfMemoryProviderCreate(ops, ¶ms, &provider); + ASSERT_EQ(result, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} + +TEST_F(test, FailMismatchedResidentHandlesPtr) { + umf_memory_provider_ops_t *ops = umfLevelZeroMemoryProviderOps(); + ASSERT_NE(ops, nullptr); + + auto memory_type = UMF_MEMORY_TYPE_DEVICE; + + auto params = create_level_zero_prov_params(memory_type); + params.resident_device_handles = ¶ms.level_zero_device_handle; + + umf_memory_provider_handle_t provider = nullptr; + umf_result_t result = umfMemoryProviderCreate(ops, ¶ms, &provider); + ASSERT_EQ(result, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} + class LevelZeroMemoryAccessor : public MemoryAccessor { public: LevelZeroMemoryAccessor(ze_context_handle_t hContext, @@ -61,7 +144,11 @@ struct umfLevelZeroProviderTest hDevice = (ze_device_handle_t)params.level_zero_device_handle; hContext = (ze_context_handle_t)params.level_zero_context_handle; - ASSERT_NE(hDevice, nullptr); + if (params.memory_type == UMF_MEMORY_TYPE_HOST) { + ASSERT_EQ(hDevice, nullptr); + } else { + ASSERT_NE(hDevice, nullptr); + } ASSERT_NE(hContext, nullptr); switch (params.memory_type) { From becd2442930ad8cfa1ccbf661cc4a6fe21a87750 Mon Sep 17 00:00:00 2001 From: Agata Momot Date: Thu, 22 Aug 2024 15:22:19 +0200 Subject: [PATCH 064/352] fix: replace UT_ASSERTs with GTEST asserts Ref. #569 --- test/memspaces/memspace_fixtures.hpp | 3 +- test/memspaces/memspace_helpers.hpp | 6 ++-- test/memspaces/memspace_host_all.cpp | 47 ++++++++++++++-------------- 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/test/memspaces/memspace_fixtures.hpp b/test/memspaces/memspace_fixtures.hpp index 52f21c934..68089dd8b 100644 --- a/test/memspaces/memspace_fixtures.hpp +++ b/test/memspaces/memspace_fixtures.hpp @@ -183,7 +183,8 @@ TEST_P(memspaceProviderTest, allocLocalMt) { int mode = -1; std::vector boundNodeIds; size_t allocNodeId = SIZE_MAX; - getAllocationPolicy(ptr, maxNodeId, mode, boundNodeIds, allocNodeId); + ASSERT_NO_FATAL_FAILURE(getAllocationPolicy(ptr, maxNodeId, mode, + boundNodeIds, allocNodeId)); // Get the CPUs associated with the specified NUMA node. hwloc_obj_t allocNodeObj = diff --git a/test/memspaces/memspace_helpers.hpp b/test/memspaces/memspace_helpers.hpp index 1adee2607..5385e5344 100644 --- a/test/memspaces/memspace_helpers.hpp +++ b/test/memspaces/memspace_helpers.hpp @@ -36,10 +36,10 @@ void getAllocationPolicy(void *ptr, unsigned long maxNodeId, int &mode, // Get policy and the nodes associated with this policy. int ret = get_mempolicy(&memMode, memNodeMasks.data(), nrUlongs * bitsPerUlong, ptr, MPOL_F_ADDR); - UT_ASSERTeq(ret, 0); + ASSERT_EQ(ret, 0); mode = memMode; - UT_ASSERTeq(boundNodeIds.size(), 0); + ASSERT_EQ(boundNodeIds.size(), 0); for (size_t i = 0; i <= maxNodeId; i++) { const size_t memNodeMaskIdx = ((i + bitsPerUlong) / bitsPerUlong) - 1; const auto &memNodeMask = memNodeMasks.at(memNodeMaskIdx); @@ -52,7 +52,7 @@ void getAllocationPolicy(void *ptr, unsigned long maxNodeId, int &mode, // Get the node that allocated the memory at 'ptr'. int nodeId = -1; ret = get_mempolicy(&nodeId, nullptr, 0, ptr, MPOL_F_ADDR | MPOL_F_NODE); - UT_ASSERTeq(ret, 0); + ASSERT_EQ(ret, 0); allocNodeId = static_cast(nodeId); } diff --git a/test/memspaces/memspace_host_all.cpp b/test/memspaces/memspace_host_all.cpp index 64cb210b2..6e61c6bdc 100644 --- a/test/memspaces/memspace_host_all.cpp +++ b/test/memspaces/memspace_host_all.cpp @@ -51,17 +51,18 @@ struct memspaceHostAllProviderTest : ::memspaceHostAllTest { TEST_F(numaNodesTest, memspaceGet) { umf_const_memspace_handle_t hMemspace = umfMemspaceHostAllGet(); - UT_ASSERTne(hMemspace, nullptr); + ASSERT_NE(hMemspace, nullptr); // Confirm that the HOST ALL memspace is composed of all available NUMA nodes. - UT_ASSERTeq(hMemspace->size, nodeIds.size()); + ASSERT_EQ(hMemspace->size, nodeIds.size()); for (size_t i = 0; i < hMemspace->size; i++) { // NUMA memory target internally casts the config directly into priv. // TODO: Use the memory target API when it becomes available. struct umf_numa_memtarget_config_t *numaTargetCfg = (struct umf_numa_memtarget_config_t *)hMemspace->nodes[i]->priv; - UT_ASSERT(std::find(nodeIds.begin(), nodeIds.end(), - numaTargetCfg->physical_id) != nodeIds.end()); + ASSERT_NE(std::find(nodeIds.begin(), nodeIds.end(), + numaTargetCfg->physical_id), + nodeIds.end()); } } @@ -69,8 +70,8 @@ TEST_F(memspaceHostAllTest, providerFromHostAllMemspace) { umf_memory_provider_handle_t hProvider = nullptr; umf_result_t ret = umfMemoryProviderCreateFromMemspace(hMemspace, nullptr, &hProvider); - UT_ASSERTeq(ret, UMF_RESULT_SUCCESS); - UT_ASSERTne(hProvider, nullptr); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(hProvider, nullptr); umfMemoryProviderDestroy(hProvider); } @@ -81,13 +82,13 @@ TEST_F(memspaceHostAllProviderTest, allocFree) { size_t alignment = 0; umf_result_t ret = umfMemoryProviderAlloc(hProvider, size, alignment, &ptr); - UT_ASSERTeq(ret, UMF_RESULT_SUCCESS); - UT_ASSERTne(ptr, nullptr); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(ptr, nullptr); memset(ptr, 0xFF, size); ret = umfMemoryProviderFree(hProvider, ptr, size); - UT_ASSERTeq(ret, UMF_RESULT_SUCCESS); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); } TEST_F(memspaceHostAllProviderTest, hostAllDefaults) { @@ -96,7 +97,7 @@ TEST_F(memspaceHostAllProviderTest, hostAllDefaults) { // default kernel path (no mbind). umf_const_memspace_handle_t hMemspace = umfMemspaceHostAllGet(); - UT_ASSERTne(hMemspace, nullptr); + ASSERT_NE(hMemspace, nullptr); umf_memory_provider_handle_t hProvider = nullptr; umf_result_t ret = umfMemoryProviderCreateFromMemspace( @@ -110,14 +111,14 @@ TEST_F(memspaceHostAllProviderTest, hostAllDefaults) { size_t alignment = 0; ret = umfMemoryProviderAlloc(hProvider, size, alignment, &ptr1); - UT_ASSERTeq(ret, UMF_RESULT_SUCCESS); - UT_ASSERTne(ptr1, nullptr); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(ptr1, nullptr); memset(ptr1, 0xFF, size); // Create single allocation using mmap void *ptr2 = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - UT_ASSERTne(ptr2, nullptr); + ASSERT_NE(ptr2, nullptr); memset(ptr2, 0xFF, size); // Compare UMF and kernel default allocation policy @@ -127,28 +128,28 @@ TEST_F(memspaceHostAllProviderTest, hostAllDefaults) { int ret2 = get_mempolicy(&memMode1, nodemask1->maskp, nodemask1->size, ptr1, MPOL_F_ADDR); - UT_ASSERTeq(ret2, 0); + ASSERT_EQ(ret2, 0); ret2 = get_mempolicy(&memMode2, nodemask2->maskp, nodemask2->size, ptr2, MPOL_F_ADDR); - UT_ASSERTeq(ret2, 0); - UT_ASSERTeq(memMode1, memMode2); - UT_ASSERTeq(nodemask1->size, nodemask2->size); - UT_ASSERTeq(numa_bitmask_equal(nodemask1, nodemask2), 1); + ASSERT_EQ(ret2, 0); + ASSERT_EQ(memMode1, memMode2); + ASSERT_EQ(nodemask1->size, nodemask2->size); + ASSERT_EQ(numa_bitmask_equal(nodemask1, nodemask2), 1); int nodeId1 = -1, nodeId2 = -1; ret2 = get_mempolicy(&nodeId1, nullptr, 0, ptr1, MPOL_F_ADDR | MPOL_F_NODE); - UT_ASSERTeq(ret2, 0); + ASSERT_EQ(ret2, 0); ret2 = get_mempolicy(&nodeId2, nullptr, 0, ptr2, MPOL_F_ADDR | MPOL_F_NODE); - UT_ASSERTeq(ret2, 0); - UT_ASSERTeq(nodeId1, nodeId2); + ASSERT_EQ(ret2, 0); + ASSERT_EQ(nodeId1, nodeId2); numa_free_nodemask(nodemask2); numa_free_nodemask(nodemask1); ret2 = munmap(ptr2, size); - UT_ASSERTeq(ret2, 0); + ASSERT_EQ(ret2, 0); ret = umfMemoryProviderFree(hProvider, ptr1, size); - UT_ASSERTeq(ret, UMF_RESULT_SUCCESS); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); umfMemoryProviderDestroy(hProvider); } From 72e22a95f7b8a932e4eebb49e31435abaefd3b06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20=C5=9Alusarczyk?= Date: Thu, 29 Aug 2024 16:32:27 +0200 Subject: [PATCH 065/352] Fix compilation of syscall_memfd_secret for SLES --- src/provider/provider_os_memory_linux.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/provider/provider_os_memory_linux.c b/src/provider/provider_os_memory_linux.c index fd0e3ab97..e9fd53790 100644 --- a/src/provider/provider_os_memory_linux.c +++ b/src/provider/provider_os_memory_linux.c @@ -80,7 +80,8 @@ static int syscall_memfd_secret(void) { int fd = -1; #ifdef __NR_memfd_secret // SYS_memfd_secret is supported since Linux 5.14 - fd = syscall(SYS_memfd_secret, 0); + // not using SYS_memfd_secret as SLES does not define it + fd = syscall(__NR_memfd_secret, 0); if (fd == -1) { LOG_PERR("memfd_secret() failed"); } @@ -95,7 +96,8 @@ static int syscall_memfd_create(void) { int fd = -1; #ifdef __NR_memfd_create // SYS_memfd_create is supported since Linux 3.17, glibc 2.27 - fd = syscall(SYS_memfd_create, "anon_fd_name", 0); + // not using SYS_memfd_create for consistency with syscall_memfd_secret + fd = syscall(__NR_memfd_create, "anon_fd_name", 0); if (fd == -1) { LOG_PERR("memfd_create() failed"); } From 13acb6fd97f9836a2f6ebc9e8bde2494a1d2a460 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Tue, 3 Sep 2024 12:59:05 +0200 Subject: [PATCH 066/352] Fix umf_standalone_examples test Install UMF into a new directory created inside CMAKE_CURRENT_BINARY_DIR. Fixes: #674 Signed-off-by: Lukasz Dorau --- test/CMakeLists.txt | 5 +++-- test/test_examples.sh | 25 ++++++++++++++----------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 962d1e126..f2078303f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -440,13 +440,14 @@ if(LINUX ) endif() - if(NOT UMF_DISABLE_HWLOC) + if(EXAMPLES AND NOT UMF_DISABLE_HWLOC) add_test( NAME umf_standalone_examples COMMAND ${UMF_CMAKE_SOURCE_DIR}/test/test_examples.sh ${UMF_CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} - ${CMAKE_INSTALL_PREFIX} ${EXAMPLES} + ${CMAKE_CURRENT_BINARY_DIR}/umf_standalone_examples/install-dir + "${CMAKE_INSTALL_PREFIX}" ${EXAMPLES} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) endif() endif() diff --git a/test/test_examples.sh b/test/test_examples.sh index 469cd9c10..8941f4e8a 100755 --- a/test/test_examples.sh +++ b/test/test_examples.sh @@ -8,37 +8,39 @@ set -e SOURCE_DIR=$1 BUILD_DIR=$2 INSTALL_DIR=$3 +CMAKE_INSTALL_PREFIX=$4 echo "Running: $0 $*" function print_usage() { echo "$(basename $0) - test all examples standalone" - echo "Usage: $(basename $0) " + echo "Usage: $(basename $0) " } -if [ "$3" == "" ]; then +if [ "$5" == "" ]; then print_usage echo -e "Error: too few arguments\n" exit 1 fi -if [ "$4" == "" ]; then - print_usage - echo "No examples to run!" - exit 0 -fi - if [ ! -f $SOURCE_DIR/README.md ]; then echo -e "error: incorrect : $SOURCE_DIR\n" print_usage exit 1 fi +mkdir -p ${INSTALL_DIR}/${CMAKE_INSTALL_PREFIX} + SOURCE_DIR=$(realpath $SOURCE_DIR) BUILD_DIR=$(realpath $BUILD_DIR) INSTALL_DIR=$(realpath $INSTALL_DIR) -shift 3 +echo "SOURCE_DIR=$SOURCE_DIR" +echo "BUILD_DIR=$BUILD_DIR" +echo "CMAKE_INSTALL_PREFIX=$CMAKE_INSTALL_PREFIX" +echo "INSTALL_DIR=$INSTALL_DIR" + +shift 4 EXAMPLES="$*" echo "Examples to run: $EXAMPLES" echo @@ -46,8 +48,9 @@ echo cd ${BUILD_DIR} echo "DIR=$(pwd)" +echo "Installing UMF into the directory: ${INSTALL_DIR}/${CMAKE_INSTALL_PREFIX}" set -x -make -j$(nproc) install +make DESTDIR=$INSTALL_DIR -j$(nproc) install set +x for ex in $EXAMPLES; do @@ -67,7 +70,7 @@ for ex in $EXAMPLES; do rm -rf $BLD_DIR mkdir -p $BLD_DIR cd $BLD_DIR - CMAKE_PREFIX_PATH="$INSTALL_DIR" cmake $SRC_DIR + CMAKE_PREFIX_PATH="${INSTALL_DIR}/${CMAKE_INSTALL_PREFIX}" cmake $SRC_DIR make -j$(nproc) ctest --output-on-failure set +x From 184eef1df5f06cc6f1f1d755572c0163f1eea858 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Tue, 3 Sep 2024 16:59:52 +0200 Subject: [PATCH 067/352] tests: fix warning 'maybe-uninitialized' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Found on Ubuntu 23.10 on gcc 13.2.0: warning: ‘nodeId’ may be used uninitialized [-Wmaybe-uninitialized] Fix other places for unity, setting it to -1. --- test/memspaces/memspace_highest_capacity.cpp | 3 +-- test/provider_os_memory_multiple_numa_nodes.cpp | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/test/memspaces/memspace_highest_capacity.cpp b/test/memspaces/memspace_highest_capacity.cpp index 872865251..59ee61649 100644 --- a/test/memspaces/memspace_highest_capacity.cpp +++ b/test/memspaces/memspace_highest_capacity.cpp @@ -60,8 +60,7 @@ TEST_F(memspaceHighestCapacityProviderTest, highestCapacityVerify) { memset(ptr, 0, alloc_size); ASSERT_EQ(ret, UMF_RESULT_SUCCESS); - int nodeId; - + int nodeId = -1; ASSERT_NO_FATAL_FAILURE(getNumaNodeByPtr(ptr, &nodeId)); ASSERT_TRUE(std::any_of(maxCapacityNodes.begin(), maxCapacityNodes.end(), diff --git a/test/provider_os_memory_multiple_numa_nodes.cpp b/test/provider_os_memory_multiple_numa_nodes.cpp index fd1f44d5b..5048f92f5 100644 --- a/test/provider_os_memory_multiple_numa_nodes.cpp +++ b/test/provider_os_memory_multiple_numa_nodes.cpp @@ -373,7 +373,7 @@ TEST_F(testNuma, checkModeInterleave) { // Test where each page will be allocated. // Get the first numa node for ptr; Each next page is expected to be on next nodes. - int index = 0; + int index = -1; ASSERT_NO_FATAL_FAILURE(getNumaNodeByPtr(ptr, &index)); for (size_t i = 1; i < (size_t)pages_num; i++) { index = (index + 1) % numa_nodes.size(); @@ -417,7 +417,7 @@ TEST_F(testNuma, checkModeInterleaveCustomPartSize) { memset(ptr, 0xFF, size); // Test where each page will be allocated. // Get the first numa node for ptr; Each next part is expected to be on next nodes. - int index = 0; + int index = -1; ASSERT_NO_FATAL_FAILURE(getNumaNodeByPtr(ptr, &index)); for (size_t i = 0; i < (size_t)part_num; i++) { for (size_t j = 0; j < part_size; j += page_size) { @@ -636,7 +636,7 @@ TEST_F(testNuma, checkModeBindOnAllNodes) { // 'ptr' must point to an initialized value before retrieving its numa node memset(ptr, 0xFF, alloc_size); - int node; + int node = -1; ASSERT_NO_FATAL_FAILURE(getNumaNodeByPtr(ptr, &node)); unsigned retrieved_numa_node_number = (unsigned)node; From f680732596927eaa7ffd54389d9006eed67b9058 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 4 Sep 2024 09:22:52 +0200 Subject: [PATCH 068/352] Do not run benchmarks in the proxy_lib CI Do not run benchmarks in the proxy_lib CI, since it takes about 4 minutes to run the umf-bench-ubench benchmark. Benchmarks are run in a separate workflow. Signed-off-by: Lukasz Dorau --- .github/workflows/proxy_lib.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/proxy_lib.yml b/.github/workflows/proxy_lib.yml index 80ac75e89..678b40eff 100644 --- a/.github/workflows/proxy_lib.yml +++ b/.github/workflows/proxy_lib.yml @@ -44,7 +44,7 @@ jobs: -DCMAKE_C_COMPILER=${{matrix.compiler.c}} -DCMAKE_CXX_COMPILER=${{matrix.compiler.cxx}} -DUMF_BUILD_SHARED_LIBRARY=ON - -DUMF_BUILD_BENCHMARKS=ON + -DUMF_BUILD_BENCHMARKS=OFF -DUMF_BUILD_TESTS=ON -DUMF_FORMAT_CODE_STYLE=OFF -DUMF_DEVELOPER_MODE=OFF From df4a497563a424e12ba40655e7e8bcf3c81b8933 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Wed, 4 Sep 2024 10:18:24 +0200 Subject: [PATCH 069/352] [CMake] Update comments for L0 loader fetching and use proper CACHE variable type - PATH to dir with headers. --- examples/gpu_shared_memory/CMakeLists.txt | 2 +- examples/ipc_level_zero/CMakeLists.txt | 2 +- src/CMakeLists.txt | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/examples/gpu_shared_memory/CMakeLists.txt b/examples/gpu_shared_memory/CMakeLists.txt index 259b47d08..c6db26e25 100644 --- a/examples/gpu_shared_memory/CMakeLists.txt +++ b/examples/gpu_shared_memory/CMakeLists.txt @@ -28,7 +28,7 @@ set(LEVEL_ZERO_LOADER_TAG v1.16.1) message( STATUS - "Installing level-zero ${LEVEL_ZERO_LOADER_TAG} from ${LEVEL_ZERO_LOADER_REPO} ..." + "Fetching L0 loader (${LEVEL_ZERO_LOADER_TAG}) from ${LEVEL_ZERO_LOADER_REPO} ..." ) FetchContent_Declare( diff --git a/examples/ipc_level_zero/CMakeLists.txt b/examples/ipc_level_zero/CMakeLists.txt index e38adf25f..cbc05a0a9 100644 --- a/examples/ipc_level_zero/CMakeLists.txt +++ b/examples/ipc_level_zero/CMakeLists.txt @@ -28,7 +28,7 @@ set(LEVEL_ZERO_LOADER_TAG v1.16.1) message( STATUS - "Installing level-zero ${LEVEL_ZERO_LOADER_TAG} from ${LEVEL_ZERO_LOADER_REPO} ..." + "Fetching L0 loader (${LEVEL_ZERO_LOADER_TAG}) from ${LEVEL_ZERO_LOADER_REPO} ..." ) FetchContent_Declare( diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e9cdbc715..db83c17e8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -6,13 +6,15 @@ include(${UMF_CMAKE_SOURCE_DIR}/cmake/helpers.cmake) set(UMF_LEVEL_ZERO_INCLUDE_DIR "" - CACHE FILEPATH "Directory containing the Level Zero Headers") + CACHE PATH "Directory containing the Level Zero Headers") # Compile definitions for UMF library. # # TODO: Cleanup the compile definitions across all the CMake files set(UMF_COMMON_COMPILE_DEFINITIONS UMF_VERSION=${UMF_VERSION}) +# Only fetch L0 loader if needed (L0 provider and GPU tests are ON), and not +# already provided by the user (via setting UMF_LEVEL_ZERO_INCLUDE_DIR). if(UMF_BUILD_LEVEL_ZERO_PROVIDER AND (UMF_BUILD_GPU_TESTS OR (NOT UMF_LEVEL_ZERO_INCLUDE_DIR))) include(FetchContent) @@ -22,7 +24,7 @@ if(UMF_BUILD_LEVEL_ZERO_PROVIDER AND (UMF_BUILD_GPU_TESTS message( STATUS - "Installing level-zero ${LEVEL_ZERO_LOADER_TAG} from ${LEVEL_ZERO_LOADER_REPO} ..." + "Fetching L0 loader (${LEVEL_ZERO_LOADER_TAG}) from ${LEVEL_ZERO_LOADER_REPO} ..." ) FetchContent_Declare( From 973df7a9b3dc08229b2c3fb43e21472e62fe6ba5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Wed, 4 Sep 2024 20:11:14 +0200 Subject: [PATCH 070/352] [CMake] Bump L0 loader version to the latest one it's aligned with version used in UR. --- examples/gpu_shared_memory/CMakeLists.txt | 2 +- examples/ipc_level_zero/CMakeLists.txt | 2 +- src/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/gpu_shared_memory/CMakeLists.txt b/examples/gpu_shared_memory/CMakeLists.txt index c6db26e25..659d22397 100644 --- a/examples/gpu_shared_memory/CMakeLists.txt +++ b/examples/gpu_shared_memory/CMakeLists.txt @@ -24,7 +24,7 @@ endif() include(FetchContent) set(LEVEL_ZERO_LOADER_REPO "https://github.com/oneapi-src/level-zero.git") -set(LEVEL_ZERO_LOADER_TAG v1.16.1) +set(LEVEL_ZERO_LOADER_TAG v1.17.39) message( STATUS diff --git a/examples/ipc_level_zero/CMakeLists.txt b/examples/ipc_level_zero/CMakeLists.txt index cbc05a0a9..18b9f542e 100644 --- a/examples/ipc_level_zero/CMakeLists.txt +++ b/examples/ipc_level_zero/CMakeLists.txt @@ -24,7 +24,7 @@ endif() include(FetchContent) set(LEVEL_ZERO_LOADER_REPO "https://github.com/oneapi-src/level-zero.git") -set(LEVEL_ZERO_LOADER_TAG v1.16.1) +set(LEVEL_ZERO_LOADER_TAG v1.17.39) message( STATUS diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index db83c17e8..bab0cba46 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -20,7 +20,7 @@ if(UMF_BUILD_LEVEL_ZERO_PROVIDER AND (UMF_BUILD_GPU_TESTS include(FetchContent) set(LEVEL_ZERO_LOADER_REPO "https://github.com/oneapi-src/level-zero.git") - set(LEVEL_ZERO_LOADER_TAG v1.16.1) + set(LEVEL_ZERO_LOADER_TAG v1.17.39) message( STATUS From 0b6d1b7a0c115d86e163aeca2f534bf8b505b3be Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Thu, 5 Sep 2024 10:36:01 +0200 Subject: [PATCH 071/352] Run setvars.sh also before building for icpx compiler Run setvars.sh also before building for icpx compiler. It fixes the following warnings: /usr/bin/ld: warning: libsvml.so, needed by ../lib/libumf.so.0.9.0, not found (try using -rpath or -rpath-link) /usr/bin/ld: warning: libirng.so, needed by ../lib/libumf.so.0.9.0, not found (try using -rpath or -rpath-link) /usr/bin/ld: warning: libimf.so, needed by ../lib/libumf.so.0.9.0, not found (try using -rpath or -rpath-link) /usr/bin/ld: warning: libintlc.so.5, needed by ../lib/libumf.so.0.9.0, not found (try using -rpath or -rpath-link) Also unify the next command in the same way. Signed-off-by: Lukasz Dorau --- .github/workflows/basic.yml | 8 +++++--- .github/workflows/sanitizers.yml | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.github/workflows/basic.yml b/.github/workflows/basic.yml index 168dca7fb..232f96869 100644 --- a/.github/workflows/basic.yml +++ b/.github/workflows/basic.yml @@ -158,12 +158,14 @@ jobs: -DUMF_LINK_HWLOC_STATICALLY=${{matrix.link_hwloc_statically}} - name: Build UMF - run: cmake --build ${{env.BUILD_DIR}} -j $(nproc) + run: | + ${{ matrix.compiler.cxx == 'icpx' && '. /opt/intel/oneapi/setvars.sh' || true }} + cmake --build ${{env.BUILD_DIR}} -j $(nproc) - name: Run tests working-directory: ${{env.BUILD_DIR}} - run: > - ${{ matrix.compiler.cxx == 'icpx' && '. /opt/intel/oneapi/setvars.sh &&' || ''}} + run: | + ${{ matrix.compiler.cxx == 'icpx' && '. /opt/intel/oneapi/setvars.sh' || true }} ctest --output-on-failure --test-dir test - name: Remove the installation directory diff --git a/.github/workflows/sanitizers.yml b/.github/workflows/sanitizers.yml index 2ca712543..2a09f60fe 100644 --- a/.github/workflows/sanitizers.yml +++ b/.github/workflows/sanitizers.yml @@ -66,12 +66,14 @@ jobs: -DUMF_TESTS_FAIL_ON_SKIP=ON - name: Build UMF - run: cmake --build ${{env.BUILD_DIR}} -j $(nproc) + run: | + ${{ matrix.compiler.cxx == 'icpx' && '. /opt/intel/oneapi/setvars.sh' || true }} + cmake --build ${{env.BUILD_DIR}} -j $(nproc) - name: Run tests working-directory: ${{env.BUILD_DIR}} - run: > - ${{ matrix.compiler.cxx == 'icpx' && '. /opt/intel/oneapi/setvars.sh &&' || ''}} + run: | + ${{ matrix.compiler.cxx == 'icpx' && '. /opt/intel/oneapi/setvars.sh' || true }} ctest --output-on-failure windows-build: From 674f4e22ece47ad1c6a663bf80cba3b5a8f2d902 Mon Sep 17 00:00:00 2001 From: Nicolas Miller Date: Fri, 6 Sep 2024 09:48:37 +0100 Subject: [PATCH 072/352] Fix hwloc patch application on windows Windows `cmd.exe` doesn't have a `true` command, `(exit 0)` will do the same thing but it will work on both linux and windows. This issue only shows up on Windows and not on a first build, since when building the first time the patch applies cleanly so the `||` branch is not taken, but then when rebuilding the patch doens't apply and the command errors out in the `||` branch. --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 57fb1d967..df2e10c16 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -135,7 +135,7 @@ else() apply ${PROJECT_SOURCE_DIR}/cmake/fix_coverity_issues.patch || - true) + (exit 0)) message( STATUS @@ -165,7 +165,7 @@ else() apply ${PROJECT_SOURCE_DIR}/cmake/fix_coverity_issues.patch || - true) + (exit 0)) message( STATUS From 1de757e868742fe9aa99c925909ff4c285c059c9 Mon Sep 17 00:00:00 2001 From: Nicolas Miller Date: Fri, 6 Sep 2024 10:02:46 +0100 Subject: [PATCH 073/352] Fix includes in memspace test fixtures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This file uses `std::find` and `std::any_of` which are part of the `` header, but it wasn't including it. When building with gcc 14 this caused build issues such as: ``` memspace_fixtures.hpp:204:26: error: ‘any_of’ is not a member of ‘std’ ``` With this patch adding the include building UMF with gcc 14 works fine. --- test/memspaces/memspace_fixtures.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/test/memspaces/memspace_fixtures.hpp b/test/memspaces/memspace_fixtures.hpp index 52f21c934..879ad0739 100644 --- a/test/memspaces/memspace_fixtures.hpp +++ b/test/memspaces/memspace_fixtures.hpp @@ -5,6 +5,7 @@ #ifndef UMF_TEST_MEMSPACE_FIXTURES_HPP #define UMF_TEST_MEMSPACE_FIXTURES_HPP +#include #include #include #include From c509c489d7ae0f56562d0afb983b8c1400df50f9 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Fri, 6 Sep 2024 12:15:04 +0200 Subject: [PATCH 074/352] Fix comparing strings in bash Signed-off-by: Lukasz Dorau --- test/test_examples.sh | 2 +- test/test_valgrind.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_examples.sh b/test/test_examples.sh index 8941f4e8a..1d7e93ee1 100755 --- a/test/test_examples.sh +++ b/test/test_examples.sh @@ -17,7 +17,7 @@ function print_usage() { echo "Usage: $(basename $0) " } -if [ "$5" == "" ]; then +if [ "$5" = "" ]; then print_usage echo -e "Error: too few arguments\n" exit 1 diff --git a/test/test_valgrind.sh b/test/test_valgrind.sh index ef314b3f7..240e4b3f3 100755 --- a/test/test_valgrind.sh +++ b/test/test_valgrind.sh @@ -20,7 +20,7 @@ if ! valgrind --version > /dev/null; then exit 1 fi -if [ "$3" == "" ]; then +if [ "$3" = "" ]; then echo -e "error: too few arguments\n" print_usage exit 1 From 6a74f1b13d90beebf9349f4f8f920f97fe438e45 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Fri, 6 Sep 2024 15:16:10 +0200 Subject: [PATCH 075/352] Fix a typo in critnib.c Signed-off-by: Lukasz Dorau --- src/critnib/critnib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/critnib/critnib.c b/src/critnib/critnib.c index c8ee202e8..965ca03b9 100644 --- a/src/critnib/critnib.c +++ b/src/critnib/critnib.c @@ -315,7 +315,7 @@ static struct critnib_leaf *alloc_leaf(struct critnib *__restrict c) { } /* - * crinib_insert -- write a key:value pair to the critnib structure + * critnib_insert -- write a key:value pair to the critnib structure * * Returns: * • 0 on success From a9158753bb37f60b67cde8357077c9450e1d44df Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Fri, 6 Sep 2024 15:21:04 +0200 Subject: [PATCH 076/352] Add RAVL tree for Coarse Provider Add RAVL tree for Coarse Provider. The code of RAVL tree comes from https://github.com/pmem/pmdk Signed-off-by: Lukasz Dorau --- src/CMakeLists.txt | 1 + src/ravl/ravl.c | 551 +++++++++++++++++++++++++++++++++++++++++++++ src/ravl/ravl.h | 63 ++++++ 3 files changed, 615 insertions(+) create mode 100644 src/ravl/ravl.c create mode 100644 src/ravl/ravl.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e9cdbc715..558663082 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -84,6 +84,7 @@ set(UMF_SOURCES memspace.c provider/provider_tracking.c critnib/critnib.c + ravl/ravl.c pool/pool_proxy.c pool/pool_scalable.c) diff --git a/src/ravl/ravl.c b/src/ravl/ravl.c new file mode 100644 index 000000000..52602f889 --- /dev/null +++ b/src/ravl/ravl.c @@ -0,0 +1,551 @@ +/* + * + * Copyright (C) 2018-2024 Intel Corporation + * + * Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + * + */ + +/* + * ravl.c -- implementation of a RAVL tree + * https://sidsen.azurewebsites.net//papers/ravl-trees-journal.pdf + */ + +#include "ravl.h" +#include "../src/utils/utils_common.h" +#include "../src/utils/utils_concurrency.h" +#include "assert.h" + +#include +#include +#include +#include + +#define RAVL_DEFAULT_DATA_SIZE (sizeof(void *)) + +enum ravl_slot_type { + RAVL_LEFT, + RAVL_RIGHT, + + MAX_SLOTS, + + RAVL_ROOT +}; + +struct ravl_node { + struct ravl_node *parent; + struct ravl_node *slots[MAX_SLOTS]; + int32_t rank; /* cannot be greater than height of the subtree */ + int32_t pointer_based; + char data[]; +}; + +struct ravl { + struct ravl_node *root; + ravl_compare *compare; + size_t data_size; +}; + +/* + * ravl_new -- creates a new ravl tree instance + */ +struct ravl *ravl_new_sized(ravl_compare *compare, size_t data_size) { + struct ravl *r = malloc(sizeof(*r)); + if (r == NULL) { + return NULL; + } + + r->compare = compare; + r->root = NULL; + r->data_size = data_size; + + return r; +} + +/* + * ravl_new -- creates a new tree that stores data pointers + */ +struct ravl *ravl_new(ravl_compare *compare) { + return ravl_new_sized(compare, RAVL_DEFAULT_DATA_SIZE); +} + +/* + * ravl_clear_node -- (internal) recursively clears the given subtree, + * calls callback in an in-order fashion. Optionally frees the given node. + */ +static void ravl_foreach_node(struct ravl_node *n, ravl_cb cb, void *arg, + int free_node) { + if (n == NULL) { + return; + } + + ravl_foreach_node(n->slots[RAVL_LEFT], cb, arg, free_node); + if (cb) { + cb((void *)n->data, arg); + } + ravl_foreach_node(n->slots[RAVL_RIGHT], cb, arg, free_node); + + if (free_node) { + free(n); + } +} + +/* + * ravl_clear -- clears the entire tree, starting from the root + */ +void ravl_clear(struct ravl *ravl) { + ravl_foreach_node(ravl->root, NULL, NULL, 1); + ravl->root = NULL; +} + +/* + * ravl_delete_cb -- clears and deletes the given ravl instance, calls callback + */ +void ravl_delete_cb(struct ravl *ravl, ravl_cb cb, void *arg) { + ravl_foreach_node(ravl->root, cb, arg, 1); + free(ravl); +} + +/* + * ravl_delete -- clears and deletes the given ravl instance + */ +void ravl_delete(struct ravl *ravl) { ravl_delete_cb(ravl, NULL, NULL); } + +/* + * ravl_foreach -- traverses the entire tree, calling callback for every node + */ +void ravl_foreach(struct ravl *ravl, ravl_cb cb, void *arg) { + ravl_foreach_node(ravl->root, cb, arg, 0); +} + +/* + * ravl_empty -- checks whether the given tree is empty + */ +int ravl_empty(struct ravl *ravl) { return ravl->root == NULL; } + +/* + * ravl_node_insert_constructor -- node data constructor for ravl_insert + */ +static void ravl_node_insert_constructor(void *data, size_t data_size, + const void *arg) { + /* suppress unused-parameter errors */ + (void)data_size; + + /* copy only the 'arg' pointer */ + memcpy(data, &arg, sizeof(arg)); +} + +/* + * ravl_node_copy_constructor -- node data constructor for ravl_emplace_copy + */ +static void ravl_node_copy_constructor(void *data, size_t data_size, + const void *arg) { + memcpy(data, arg, data_size); +} + +/* + * ravl_new_node -- (internal) allocates and initializes a new node + */ +static struct ravl_node *ravl_new_node(struct ravl *ravl, ravl_constr constr, + const void *arg) { + struct ravl_node *n = malloc(sizeof(*n) + ravl->data_size); + if (n == NULL) { + return NULL; + } + + n->parent = NULL; + n->slots[RAVL_LEFT] = NULL; + n->slots[RAVL_RIGHT] = NULL; + n->rank = 0; + n->pointer_based = constr == ravl_node_insert_constructor; + constr(n->data, ravl->data_size, arg); + + return n; +} + +/* + * ravl_slot_opposite -- (internal) returns the opposite slot type, cannot be + * called for root type + */ +static enum ravl_slot_type ravl_slot_opposite(enum ravl_slot_type t) { + assert(t != RAVL_ROOT); + + return t == RAVL_LEFT ? RAVL_RIGHT : RAVL_LEFT; +} + +/* + * ravl_node_slot_type -- (internal) returns the type of the given node: + * left child, right child or root + */ +static enum ravl_slot_type ravl_node_slot_type(struct ravl_node *n) { + if (n->parent == NULL) { + return RAVL_ROOT; + } + + return n->parent->slots[RAVL_LEFT] == n ? RAVL_LEFT : RAVL_RIGHT; +} + +/* + * ravl_node_sibling -- (internal) returns the sibling of the given node, + * NULL if the node is root (has no parent) + */ +static struct ravl_node *ravl_node_sibling(struct ravl_node *n) { + enum ravl_slot_type t = ravl_node_slot_type(n); + if (t == RAVL_ROOT) { + return NULL; + } + + return n->parent->slots[t == RAVL_LEFT ? RAVL_RIGHT : RAVL_LEFT]; +} + +/* + * ravl_node_ref -- (internal) returns the pointer to the memory location in + * which the given node resides + */ +static struct ravl_node **ravl_node_ref(struct ravl *ravl, + struct ravl_node *n) { + enum ravl_slot_type t = ravl_node_slot_type(n); + + return t == RAVL_ROOT ? &ravl->root : &n->parent->slots[t]; +} + +/* + * ravl_rotate -- (internal) performs a rotation around a given node + * + * The node n swaps place with its parent. If n is right child, parent becomes + * the left child of n, otherwise parent becomes right child of n. + */ +static void ravl_rotate(struct ravl *ravl, struct ravl_node *n) { + assert(n->parent != NULL); + struct ravl_node *p = n->parent; + struct ravl_node **pref = ravl_node_ref(ravl, p); + + enum ravl_slot_type t = ravl_node_slot_type(n); + enum ravl_slot_type t_opposite = ravl_slot_opposite(t); + + n->parent = p->parent; + p->parent = n; + *pref = n; + + if ((p->slots[t] = n->slots[t_opposite]) != NULL) { + p->slots[t]->parent = p; + } + n->slots[t_opposite] = p; +} + +/* + * ravl_node_rank -- (internal) returns the rank of the node + * + * For the purpose of balancing, NULL nodes have rank -1. + */ +static int ravl_node_rank(struct ravl_node *n) { + return n == NULL ? -1 : n->rank; +} + +/* + * ravl_node_rank_difference_parent -- (internal) returns the rank different + * between parent node p and its child n + * + * Every rank difference must be positive. + * + * Either of these can be NULL. + */ +static int ravl_node_rank_difference_parent(struct ravl_node *p, + struct ravl_node *n) { + return ravl_node_rank(p) - ravl_node_rank(n); +} + +/* + * ravl_node_rank_difference - (internal) returns the rank difference between + * parent and its child + * + * Can be used to check if a given node is an i-child. + */ +static int ravl_node_rank_difference(struct ravl_node *n) { + return ravl_node_rank_difference_parent(n->parent, n); +} + +/* + * ravl_node_is_i_j -- (internal) checks if a given node is strictly i,j-node + */ +static int ravl_node_is_i_j(struct ravl_node *n, int i, int j) { + return (ravl_node_rank_difference_parent(n, n->slots[RAVL_LEFT]) == i && + ravl_node_rank_difference_parent(n, n->slots[RAVL_RIGHT]) == j); +} + +/* + * ravl_node_is -- (internal) checks if a given node is i,j-node or j,i-node + */ +static int ravl_node_is(struct ravl_node *n, int i, int j) { + return ravl_node_is_i_j(n, i, j) || ravl_node_is_i_j(n, j, i); +} + +/* + * ravl_node_promote -- promotes a given node by increasing its rank + */ +static void ravl_node_promote(struct ravl_node *n) { n->rank += 1; } + +/* + * ravl_node_promote -- demotes a given node by increasing its rank + */ +static void ravl_node_demote(struct ravl_node *n) { + assert(n->rank > 0); + n->rank -= 1; +} + +/* + * ravl_balance -- balances the tree after insert + * + * This function must restore the invariant that every rank + * difference is positive. + */ +static void ravl_balance(struct ravl *ravl, struct ravl_node *n) { + /* walk up the tree, promoting nodes */ + while (n->parent && ravl_node_is(n->parent, 0, 1)) { + ravl_node_promote(n->parent); + n = n->parent; + } + + /* + * Either the rank rule holds or n is a 0-child whose sibling is an + * i-child with i > 1. + */ + struct ravl_node *s = ravl_node_sibling(n); + if (!(ravl_node_rank_difference(n) == 0 && + ravl_node_rank_difference_parent(n->parent, s) > 1)) { + return; + } + + struct ravl_node *y = n->parent; + /* if n is a left child, let z be n's right child and vice versa */ + enum ravl_slot_type t = ravl_slot_opposite(ravl_node_slot_type(n)); + struct ravl_node *z = n->slots[t]; + + if (z == NULL || ravl_node_rank_difference(z) == 2) { + ravl_rotate(ravl, n); + ravl_node_demote(y); + } else if (ravl_node_rank_difference(z) == 1) { + ravl_rotate(ravl, z); + ravl_rotate(ravl, z); + ravl_node_promote(z); + ravl_node_demote(n); + ravl_node_demote(y); + } +} + +/* + * ravl_insert -- insert data into the tree + */ +int ravl_insert(struct ravl *ravl, const void *data) { + return ravl_emplace(ravl, ravl_node_insert_constructor, data); +} + +/* + * ravl_insert -- copy construct data inside of a new tree node + */ +int ravl_emplace_copy(struct ravl *ravl, const void *data) { + return ravl_emplace(ravl, ravl_node_copy_constructor, data); +} + +/* + * ravl_emplace -- construct data inside of a new tree node + */ +int ravl_emplace(struct ravl *ravl, ravl_constr constr, const void *arg) { + struct ravl_node *n = ravl_new_node(ravl, constr, arg); + if (n == NULL) { + return -1; + } + + /* walk down the tree and insert the new node into a missing slot */ + struct ravl_node **dstp = &ravl->root; + struct ravl_node *dst = NULL; + while (*dstp != NULL) { + dst = (*dstp); + int cmp_result = ravl->compare(ravl_data(n), ravl_data(dst)); + if (cmp_result == 0) { + goto error_duplicate; + } + + dstp = &dst->slots[cmp_result > 0]; + } + n->parent = dst; + *dstp = n; + + ravl_balance(ravl, n); + + return 0; + +error_duplicate: + errno = EEXIST; + free(n); + return -1; +} + +/* + * ravl_node_type_most -- (internal) returns left-most or right-most node in + * the subtree + */ +static struct ravl_node *ravl_node_type_most(struct ravl_node *n, + enum ravl_slot_type t) { + while (n->slots[t] != NULL) { + n = n->slots[t]; + } + + return n; +} + +/* + * ravl_node_cessor -- (internal) returns the successor or predecessor of the + * node + */ +static struct ravl_node *ravl_node_cessor(struct ravl_node *n, + enum ravl_slot_type t) { + /* + * If t child is present, we are looking for t-opposite-most node + * in t child subtree + */ + if (n->slots[t]) { + return ravl_node_type_most(n->slots[t], ravl_slot_opposite(t)); + } + + /* otherwise get the first parent on the t path */ + while (n->parent != NULL && n == n->parent->slots[t]) { + n = n->parent; + } + + return n->parent; +} + +/* + * ravl_node_successor -- returns node's successor + * + * It's the first node larger than n. + */ +struct ravl_node *ravl_node_successor(struct ravl_node *n) { + return ravl_node_cessor(n, RAVL_RIGHT); +} + +/* + * ravl_node_predecessor -- returns node's successor + * + * It's the first node smaller than n. + */ +struct ravl_node *ravl_node_predecessor(struct ravl_node *n) { + return ravl_node_cessor(n, RAVL_LEFT); +} + +/* + * ravl_predicate_holds -- (internal) verifies the given predicate for + * the current node in the search path + * + * If the predicate holds for the given node or a node that can be directly + * derived from it, returns 1. Otherwise returns 0. + */ +static int ravl_predicate_holds(int result, struct ravl_node **ret, + struct ravl_node *n, + enum ravl_predicate flags) { + if (flags & RAVL_PREDICATE_EQUAL) { + if (result == 0) { + *ret = n; + return 1; + } + } + if (flags & RAVL_PREDICATE_GREATER) { + if (result < 0) { /* data < n->data */ + *ret = n; + return 0; + } else if (result == 0) { + *ret = ravl_node_successor(n); + return 1; + } + } + if (flags & RAVL_PREDICATE_LESS) { + if (result > 0) { /* data > n->data */ + *ret = n; + return 0; + } else if (result == 0) { + *ret = ravl_node_predecessor(n); + return 1; + } + } + + return 0; +} + +/* + * ravl_find -- searches for the node in the tree + */ +struct ravl_node *ravl_find(struct ravl *ravl, const void *data, + enum ravl_predicate flags) { + struct ravl_node *r = NULL; + struct ravl_node *n = ravl->root; + while (n) { + int result = ravl->compare(data, ravl_data(n)); + if (ravl_predicate_holds(result, &r, n, flags)) { + return r; + } + + n = n->slots[result > 0]; + } + + return r; +} + +/* + * ravl_remove -- removes the given node from the tree + */ +void ravl_remove(struct ravl *ravl, struct ravl_node *n) { + if (n->slots[RAVL_LEFT] != NULL && n->slots[RAVL_RIGHT] != NULL) { + /* if both children are present, remove the successor instead */ + struct ravl_node *s = ravl_node_successor(n); + memcpy(n->data, s->data, ravl->data_size); + + ravl_remove(ravl, s); + } else { + /* swap n with the child that may exist */ + struct ravl_node *r = + n->slots[RAVL_LEFT] ? n->slots[RAVL_LEFT] : n->slots[RAVL_RIGHT]; + if (r != NULL) { + r->parent = n->parent; + } + + *ravl_node_ref(ravl, n) = r; + free(n); + } +} + +/* + * ravl_data -- returns the data contained within the node + */ +void *ravl_data(struct ravl_node *node) { + if (node->pointer_based) { + void *data; + memcpy(&data, node->data, sizeof(void *)); + return data; + } else { + return (void *)node->data; + } +} + +/* + * ravl_first -- returns first (left-most) node in the tree + */ +struct ravl_node *ravl_first(struct ravl *ravl) { + if (ravl->root) { + return ravl_node_type_most(ravl->root, RAVL_LEFT); + } + + return NULL; +} + +/* + * ravl_last -- returns last (right-most) node in the tree + */ +struct ravl_node *ravl_last(struct ravl *ravl) { + if (ravl->root) { + return ravl_node_type_most(ravl->root, RAVL_RIGHT); + } + + return NULL; +} diff --git a/src/ravl/ravl.h b/src/ravl/ravl.h new file mode 100644 index 000000000..ae84d5a56 --- /dev/null +++ b/src/ravl/ravl.h @@ -0,0 +1,63 @@ +/* + * + * Copyright (C) 2018-2024 Intel Corporation + * + * Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + * + */ + +/* + * ravl.h -- internal definitions for ravl tree + */ + +#ifndef UMF_RAVL_H +#define UMF_RAVL_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct ravl; +struct ravl_node; + +enum ravl_predicate { + RAVL_PREDICATE_EQUAL = 1 << 0, + RAVL_PREDICATE_GREATER = 1 << 1, + RAVL_PREDICATE_LESS = 1 << 2, + RAVL_PREDICATE_LESS_EQUAL = RAVL_PREDICATE_EQUAL | RAVL_PREDICATE_LESS, + RAVL_PREDICATE_GREATER_EQUAL = + RAVL_PREDICATE_EQUAL | RAVL_PREDICATE_GREATER, +}; + +typedef int ravl_compare(const void *lhs, const void *rhs); +typedef void ravl_cb(void *data, void *arg); +typedef void ravl_constr(void *data, size_t data_size, const void *arg); + +struct ravl *ravl_new(ravl_compare *compare); +struct ravl *ravl_new_sized(ravl_compare *compare, size_t data_size); +void ravl_delete(struct ravl *ravl); +void ravl_delete_cb(struct ravl *ravl, ravl_cb cb, void *arg); +void ravl_foreach(struct ravl *ravl, ravl_cb cb, void *arg); +int ravl_empty(struct ravl *ravl); +void ravl_clear(struct ravl *ravl); +int ravl_insert(struct ravl *ravl, const void *data); +int ravl_emplace(struct ravl *ravl, ravl_constr constr, const void *arg); +int ravl_emplace_copy(struct ravl *ravl, const void *data); + +struct ravl_node *ravl_find(struct ravl *ravl, const void *data, + enum ravl_predicate predicate_flags); +struct ravl_node *ravl_first(struct ravl *ravl); +struct ravl_node *ravl_last(struct ravl *ravl); +void *ravl_data(struct ravl_node *node); +void ravl_remove(struct ravl *ravl, struct ravl_node *node); +struct ravl_node *ravl_node_successor(struct ravl_node *n); +struct ravl_node *ravl_node_predecessor(struct ravl_node *n); + +#ifdef __cplusplus +} +#endif + +#endif /* UMF_RAVL_H */ From 347feaad6a723ee91f424b0936340826c9b133ee Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Tue, 10 Sep 2024 10:27:57 +0200 Subject: [PATCH 077/352] Remove definitions of NAME_MAX Remove definitions of NAME_MAX since it is defined in limits.h. Signed-off-by: Lukasz Dorau --- src/provider/provider_os_memory_internal.h | 9 +++++++-- src/proxy_lib/proxy_lib.c | 3 +-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/provider/provider_os_memory_internal.h b/src/provider/provider_os_memory_internal.h index 81d729d27..b9a863f0d 100644 --- a/src/provider/provider_os_memory_internal.h +++ b/src/provider/provider_os_memory_internal.h @@ -8,6 +8,13 @@ #ifndef UMF_OS_MEMORY_PROVIDER_INTERNAL_H #define UMF_OS_MEMORY_PROVIDER_INTERNAL_H +#include + +#if defined(_WIN32) && !defined(NAME_MAX) +#include +#define NAME_MAX _MAX_FNAME +#endif /* defined(_WIN32) && !defined(NAME_MAX) */ + #include #include "critnib.h" @@ -24,8 +31,6 @@ typedef enum umf_purge_advise_t { UMF_PURGE_FORCE, } umf_purge_advise_t; -#define NAME_MAX 255 - typedef struct os_memory_provider_t { unsigned protection; // combination of OS-specific protection flags unsigned visibility; // memory visibility mode diff --git a/src/proxy_lib/proxy_lib.c b/src/proxy_lib/proxy_lib.c index 6c3ffa272..4819313d1 100644 --- a/src/proxy_lib/proxy_lib.c +++ b/src/proxy_lib/proxy_lib.c @@ -38,6 +38,7 @@ #endif #include +#include #include #include @@ -113,7 +114,6 @@ void proxy_lib_create_common(void) { umf_result_t umf_result; #ifndef _WIN32 -#define NAME_MAX 255 char shm_name[NAME_MAX]; if (util_env_var_has_str("UMF_PROXY", "page.disposition=shared-fd")) { @@ -136,7 +136,6 @@ void proxy_lib_create_common(void) { "named shared memory: %s", os_params.shm_name); } -#undef NAME_MAX #endif umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), &os_params, From 40a388d02f86b28bfccb449aa04affe61f33bd55 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Tue, 10 Sep 2024 11:07:11 +0200 Subject: [PATCH 078/352] Fix Coverity issues in RAVL tree Fix Coverity issues in RAVL tree: - 468502 Dereference after null check - 462949 Overflowed return value Signed-off-by: Lukasz Dorau --- src/ravl/ravl.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ravl/ravl.c b/src/ravl/ravl.c index 52602f889..fa2a81baf 100644 --- a/src/ravl/ravl.c +++ b/src/ravl/ravl.c @@ -253,7 +253,10 @@ static int ravl_node_rank(struct ravl_node *n) { */ static int ravl_node_rank_difference_parent(struct ravl_node *p, struct ravl_node *n) { - return ravl_node_rank(p) - ravl_node_rank(n); + int rv = ravl_node_rank(p) - ravl_node_rank(n); + // assert to check integer overflow + assert(rv < ravl_node_rank(p)); + return rv; } /* @@ -330,6 +333,7 @@ static void ravl_balance(struct ravl *ravl, struct ravl_node *n) { ravl_rotate(ravl, z); ravl_node_promote(z); ravl_node_demote(n); + assert(y != NULL); ravl_node_demote(y); } } From 225e1192772930ec30d57e3884313f26e2fa1725 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Tue, 10 Sep 2024 11:38:28 +0200 Subject: [PATCH 079/352] Remove the warning message of the base allocator Remove the warning message of the base allocator. This situation can happen often and it is nothing wrong, so this message just spams the debug output. Signed-off-by: Lukasz Dorau --- src/base_alloc/base_alloc_global.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/base_alloc/base_alloc_global.c b/src/base_alloc/base_alloc_global.c index b5660d440..12a93fd8b 100644 --- a/src/base_alloc/base_alloc_global.c +++ b/src/base_alloc/base_alloc_global.c @@ -164,9 +164,6 @@ void *umf_ba_global_aligned_alloc(size_t size, size_t alignment) { int ac_index = size_to_idx(size); if (ac_index >= NUM_ALLOCATION_CLASSES) { - LOG_WARN("base_alloc: allocation size (%zu) larger than the biggest " - "allocation class. Falling back to OS memory allocation.", - size); return add_metadata_and_align(ba_os_alloc(size), size, alignment); } From 44dc69a97f0c9427b96a165cc291be30a19fb21f Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Mon, 9 Sep 2024 16:56:41 +0200 Subject: [PATCH 080/352] Refactor IPC tests --- test/ipcFixtures.hpp | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/test/ipcFixtures.hpp b/test/ipcFixtures.hpp index 1eb7865e3..317bdf3bf 100644 --- a/test/ipcFixtures.hpp +++ b/test/ipcFixtures.hpp @@ -52,11 +52,8 @@ using ipcTestParams = struct umfIpcTest : umf_test::test, ::testing::WithParamInterface { - umfIpcTest() : pool(nullptr, nullptr) {} - void SetUp() override { - test::SetUp(); - this->pool = makePool(); - } + umfIpcTest() {} + void SetUp() override { test::SetUp(); } void TearDown() override { test::TearDown(); } @@ -74,7 +71,9 @@ struct umfIpcTest : umf_test::test, auto trace = [](void *trace_context, const char *name) { stats_type *stat = static_cast(trace_context); - if (std::strcmp(name, "get_ipc_handle") == 0) { + if (std::strcmp(name, "alloc") == 0) { + ++stat->allocCount; + } else if (std::strcmp(name, "get_ipc_handle") == 0) { ++stat->getCount; } else if (std::strcmp(name, "put_ipc_handle") == 0) { ++stat->putCount; @@ -98,15 +97,17 @@ struct umfIpcTest : umf_test::test, } struct stats_type { + std::atomic allocCount; std::atomic getCount; std::atomic putCount; std::atomic openCount; std::atomic closeCount; - stats_type() : getCount(0), putCount(0), openCount(0), closeCount(0) {} + stats_type() + : allocCount(0), getCount(0), putCount(0), openCount(0), + closeCount(0) {} }; - umf::pool_unique_handle_t pool; static constexpr int NTHREADS = 10; stats_type stat; MemoryAccessor *memAccessor = nullptr; @@ -114,6 +115,8 @@ struct umfIpcTest : umf_test::test, TEST_P(umfIpcTest, GetIPCHandleSize) { size_t size = 0; + umf::pool_unique_handle_t pool = makePool(); + umf_result_t ret = umfPoolGetIPCHandleSize(pool.get(), &size); EXPECT_EQ(ret, UMF_RESULT_SUCCESS); EXPECT_GT(size, 0); @@ -122,6 +125,7 @@ TEST_P(umfIpcTest, GetIPCHandleSize) { TEST_P(umfIpcTest, BasicFlow) { constexpr size_t SIZE = 100; std::vector expected_data(SIZE); + umf::pool_unique_handle_t pool = makePool(); int *ptr = (int *)umfPoolMalloc(pool.get(), SIZE * sizeof(int)); EXPECT_NE(ptr, nullptr); @@ -172,6 +176,7 @@ TEST_P(umfIpcTest, BasicFlow) { ret = umfPoolFree(pool.get(), ptr); EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + pool.reset(nullptr); EXPECT_EQ(stat.getCount, 1); EXPECT_EQ(stat.putCount, stat.getCount); // TODO: enale check below once cache for open IPC handles is implemented @@ -183,6 +188,8 @@ TEST_P(umfIpcTest, ConcurrentGetPutHandles) { std::vector ptrs; constexpr size_t ALLOC_SIZE = 100; constexpr size_t NUM_POINTERS = 100; + umf::pool_unique_handle_t pool = makePool(); + for (size_t i = 0; i < NUM_POINTERS; ++i) { void *ptr = umfPoolMalloc(pool.get(), ALLOC_SIZE); EXPECT_NE(ptr, nullptr); @@ -221,8 +228,7 @@ TEST_P(umfIpcTest, ConcurrentGetPutHandles) { EXPECT_EQ(ret, UMF_RESULT_SUCCESS); } - EXPECT_GE(stat.getCount, NUM_POINTERS); - EXPECT_LE(stat.getCount, NUM_POINTERS * NTHREADS); + pool.reset(nullptr); EXPECT_EQ(stat.putCount, stat.getCount); } @@ -230,6 +236,8 @@ TEST_P(umfIpcTest, ConcurrentOpenCloseHandles) { std::vector ptrs; constexpr size_t ALLOC_SIZE = 100; constexpr size_t NUM_POINTERS = 100; + umf::pool_unique_handle_t pool = makePool(); + for (size_t i = 0; i < NUM_POINTERS; ++i) { void *ptr = umfPoolMalloc(pool.get(), ALLOC_SIZE); EXPECT_NE(ptr, nullptr); @@ -249,8 +257,8 @@ TEST_P(umfIpcTest, ConcurrentOpenCloseHandles) { umf_test::syncthreads_barrier syncthreads(NTHREADS); - auto openHandlesFn = [this, &ipcHandles, &openedIpcHandles, - &syncthreads](size_t tid) { + auto openHandlesFn = [this, &ipcHandles, &openedIpcHandles, &syncthreads, + &pool](size_t tid) { syncthreads(); for (auto ipcHandle : ipcHandles) { void *ptr; @@ -282,6 +290,11 @@ TEST_P(umfIpcTest, ConcurrentOpenCloseHandles) { EXPECT_EQ(ret, UMF_RESULT_SUCCESS); } + pool.reset(nullptr); + EXPECT_EQ(stat.getCount, stat.allocCount); + EXPECT_EQ(stat.putCount, stat.getCount); + // TODO: enale check below once cache for open IPC handles is implemented + // EXPECT_EQ(stat.openCount, stat.allocCount); EXPECT_EQ(stat.openCount, stat.closeCount); } From e4c61f1a622be032a821de9202a5d827174467e7 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Tue, 10 Sep 2024 17:34:05 +0200 Subject: [PATCH 081/352] Refactor providerCreateExt() in tests of OS memory provider Signed-off-by: Lukasz Dorau --- test/provider_os_memory.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/test/provider_os_memory.cpp b/test/provider_os_memory.cpp index 5b9de43fa..57403e1d0 100644 --- a/test/provider_os_memory.cpp +++ b/test/provider_os_memory.cpp @@ -43,17 +43,18 @@ static int compare_native_error_str(const char *message, int error) { using providerCreateExtParams = std::tuple; -umf::provider_unique_handle_t -providerCreateExt(providerCreateExtParams params) { +static void providerCreateExt(providerCreateExtParams params, + umf::provider_unique_handle_t *handle) { umf_memory_provider_handle_t hProvider = nullptr; auto [provider_ops, provider_params] = params; auto ret = umfMemoryProviderCreate(provider_ops, provider_params, &hProvider); - EXPECT_EQ(ret, UMF_RESULT_SUCCESS); - EXPECT_NE(hProvider, nullptr); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(hProvider, nullptr); - return umf::provider_unique_handle_t(hProvider, &umfMemoryProviderDestroy); + *handle = + umf::provider_unique_handle_t(hProvider, &umfMemoryProviderDestroy); } struct umfProviderTest @@ -61,10 +62,10 @@ struct umfProviderTest ::testing::WithParamInterface { void SetUp() override { test::SetUp(); - provider = providerCreateExt(this->GetParam()); + providerCreateExt(this->GetParam(), &provider); umf_result_t umf_result = umfMemoryProviderGetMinPageSize(provider.get(), NULL, &page_size); - EXPECT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); page_plus_64 = page_size + 64; } From dd4121560dc17d6a4c212b1570e87c59de8dfd0c Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 11 Sep 2024 08:56:32 +0200 Subject: [PATCH 082/352] Fix assert in ravl_node_rank_difference_parent() Fix assert in ravl_node_rank_difference_parent(). ravl_node_rank() do not have to be positive - it can return (-1), so the assert has to be corrected. For example: if ravl_node_rank(p) = 0 and ravl_node_rank(n) = -1, then rv = 1. Ref: #717 Signed-off-by: Lukasz Dorau --- src/ravl/ravl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ravl/ravl.c b/src/ravl/ravl.c index fa2a81baf..0bd4d59bc 100644 --- a/src/ravl/ravl.c +++ b/src/ravl/ravl.c @@ -255,7 +255,8 @@ static int ravl_node_rank_difference_parent(struct ravl_node *p, struct ravl_node *n) { int rv = ravl_node_rank(p) - ravl_node_rank(n); // assert to check integer overflow - assert(rv < ravl_node_rank(p)); + // ravl_node_rank(x) is >= -1 + assert(rv <= ravl_node_rank(p) + 1); return rv; } From a31792557bd69e59a6662f6a7a2fd95c28d53434 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Mon, 9 Sep 2024 16:57:44 +0200 Subject: [PATCH 083/352] Check input parameter in umfGetIPCHandle function --- src/ipc.c | 5 +++++ test/ipcFixtures.hpp | 25 +++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/ipc.c b/src/ipc.c index b266004f3..f7497b340 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -51,6 +51,11 @@ umf_result_t umfPoolGetIPCHandleSize(umf_memory_pool_handle_t hPool, umf_result_t umfGetIPCHandle(const void *ptr, umf_ipc_handle_t *umfIPCHandle, size_t *size) { + if (ptr == NULL || umfIPCHandle == NULL || size == NULL) { + LOG_ERR("invalid argument."); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + size_t ipcHandleSize = 0; umf_alloc_info_t allocInfo; umf_result_t ret = umfMemoryTrackerGetAllocInfo(ptr, &allocInfo); diff --git a/test/ipcFixtures.hpp b/test/ipcFixtures.hpp index 317bdf3bf..ce16e8f79 100644 --- a/test/ipcFixtures.hpp +++ b/test/ipcFixtures.hpp @@ -122,6 +122,31 @@ TEST_P(umfIpcTest, GetIPCHandleSize) { EXPECT_GT(size, 0); } +TEST_P(umfIpcTest, GetIPCHandleInvalidArgs) { + constexpr size_t SIZE = 100; + umf_ipc_handle_t ipcHandle = nullptr; + size_t handleSize = 0; + umf_result_t ret = umfGetIPCHandle(nullptr, &ipcHandle, &handleSize); + EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + void *ptr = (void *)0xBAD; + ret = umfGetIPCHandle(ptr, &ipcHandle, &handleSize); + EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + umf::pool_unique_handle_t pool = makePool(); + ptr = umfPoolMalloc(pool.get(), SIZE); + EXPECT_NE(ptr, nullptr); + + ret = umfGetIPCHandle(ptr, nullptr, &handleSize); + EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + ret = umfGetIPCHandle(ptr, &ipcHandle, nullptr); + EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + ret = umfFree(ptr); + EXPECT_EQ(ret, UMF_RESULT_SUCCESS); +} + TEST_P(umfIpcTest, BasicFlow) { constexpr size_t SIZE = 100; std::vector expected_data(SIZE); From 9d1b51bc016a3330b6a95f540405f81fcaa546c4 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Mon, 9 Sep 2024 17:24:27 +0200 Subject: [PATCH 084/352] Enable IPC tests for OS provider with disjoint pool --- test/CMakeLists.txt | 6 ++++++ test/provider_os_memory.cpp | 33 +++++++++++++++++++++++++++++++++ test/test_valgrind.sh | 3 +++ 3 files changed, 42 insertions(+) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f2078303f..0d51643de 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -186,6 +186,12 @@ if(LINUX AND (NOT UMF_DISABLE_HWLOC)) # OS-specific functions are implemented NAME provider_os_memory SRCS provider_os_memory.cpp LIBS ${UMF_UTILS_FOR_TEST}) + if(UMF_BUILD_LIBUMF_POOL_DISJOINT) + target_compile_definitions(umf_test-provider_os_memory + PRIVATE UMF_POOL_DISJOINT_ENABLED=1) + target_link_libraries(umf_test-provider_os_memory PRIVATE disjoint_pool) + endif() + add_umf_test( NAME provider_os_memory_multiple_numa_nodes SRCS provider_os_memory_multiple_numa_nodes.cpp diff --git a/test/provider_os_memory.cpp b/test/provider_os_memory.cpp index 5b9de43fa..24bb1d922 100644 --- a/test/provider_os_memory.cpp +++ b/test/provider_os_memory.cpp @@ -5,8 +5,10 @@ #include "base.hpp" #include "cpp_helpers.hpp" +#include "ipcFixtures.hpp" #include +#include #include using umf_test::test; @@ -326,3 +328,34 @@ TEST_P(umfProviderTest, purge_force_INVALID_POINTER) { verify_last_native_error(provider.get(), UMF_OS_RESULT_ERROR_PURGE_FORCE_FAILED); } + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(umfIpcTest); + +umf_os_memory_provider_params_t osMemoryProviderParamsShared() { + auto params = umfOsMemoryProviderParamsDefault(); + params.visibility = UMF_MEM_MAP_SHARED; + return params; +} +auto os_params = osMemoryProviderParamsShared(); + +HostMemoryAccessor hostAccessor; + +umf_disjoint_pool_params_t disjointPoolParams() { + umf_disjoint_pool_params_t params = umfDisjointPoolParamsDefault(); + params.SlabMinSize = 4096; + params.MaxPoolableSize = 4096; + params.Capacity = 4; + params.MinBucketSize = 64; + return params; +} +umf_disjoint_pool_params_t disjointParams = disjointPoolParams(); + +static std::vector ipcTestParamsList = { +#if (defined UMF_POOL_DISJOINT_ENABLED) + {umfDisjointPoolOps(), &disjointParams, umfOsMemoryProviderOps(), + &os_params, &hostAccessor}, +#endif +}; + +INSTANTIATE_TEST_SUITE_P(osProviderTest, umfIpcTest, + ::testing::ValuesIn(ipcTestParamsList)); diff --git a/test/test_valgrind.sh b/test/test_valgrind.sh index 240e4b3f3..ea4e155fb 100755 --- a/test/test_valgrind.sh +++ b/test/test_valgrind.sh @@ -91,6 +91,9 @@ for test in $(ls -1 umf_test-*); do umf_test-memspace_host_all) FILTER='--gtest_filter="-*allocsSpreadAcrossAllNumaNodes"' ;; + umf_test-provider_os_memory) + FILTER='--gtest_filter="-osProviderTest/umfIpcTest*"' + ;; umf_test-provider_os_memory_config) FILTER='--gtest_filter="-*protection_flag_none:*protection_flag_read:*providerConfigTestNumaMode*"' ;; From fecc3075b6d0d5b0b3a5e1c61a1fa79436f1af42 Mon Sep 17 00:00:00 2001 From: Martin Morrison-Grant Date: Wed, 11 Sep 2024 16:43:47 +0100 Subject: [PATCH 085/352] Update CMake warning when libhwloc is not found to inform user about UMF_DISABLE_HWLOC flag. --- cmake/FindLIBHWLOC.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/FindLIBHWLOC.cmake b/cmake/FindLIBHWLOC.cmake index a7c9201a0..8d7998f8d 100644 --- a/cmake/FindLIBHWLOC.cmake +++ b/cmake/FindLIBHWLOC.cmake @@ -67,7 +67,8 @@ if(LIBHWLOC_LIBRARY) endif() else() set(MSG_NOT_FOUND - "libhwloc NOT found (set CMAKE_PREFIX_PATH to point the location)") + "libhwloc NOT found (set CMAKE_PREFIX_PATH to point the location or disable with -DUMF_DISABLE_HWLOC=ON)" + ) if(LIBHWLOC_FIND_REQUIRED) message(FATAL_ERROR ${MSG_NOT_FOUND}) else() From 0b29930370d4e0e14f0829615a09f85128f39a34 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Wed, 11 Sep 2024 18:34:03 +0200 Subject: [PATCH 086/352] Fix comment in trackingCloseIpcHandle function --- src/provider/provider_tracking.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/provider/provider_tracking.c b/src/provider/provider_tracking.c index adbe3515b..726f7d4e8 100644 --- a/src/provider/provider_tracking.c +++ b/src/provider/provider_tracking.c @@ -622,7 +622,7 @@ static umf_result_t trackingCloseIpcHandle(void *provider, void *ptr, umf_tracking_memory_provider_t *p = (umf_tracking_memory_provider_t *)provider; - // umfMemoryTrackerRemove should be called before umfMemoryProviderFree + // umfMemoryTrackerRemove should be called before umfMemoryProviderCloseIPCHandle // to avoid a race condition. If the order would be different, other thread // could allocate the memory at address `ptr` before a call to umfMemoryTrackerRemove // resulting in inconsistent state. From 99f562b30317a17f539b9382d60aa7e8ad486d0b Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 11 Sep 2024 10:43:40 +0200 Subject: [PATCH 087/352] Add devdax memory provider Signed-off-by: Lukasz Dorau --- CMakeLists.txt | 3 + README.md | 16 + .../umf/providers/provider_devdax_memory.h | 58 ++ scripts/docs_config/api.rst | 8 + src/CMakeLists.txt | 1 + src/provider/provider_devdax_memory.c | 523 ++++++++++++++++++ .../provider_devdax_memory_internal.h | 32 ++ src/provider/provider_os_memory_internal.h | 4 + src/provider/provider_os_memory_linux.c | 24 + src/provider/provider_os_memory_macosx.c | 8 + src/provider/provider_os_memory_posix.c | 39 ++ src/provider/provider_os_memory_windows.c | 15 + src/utils/utils_common.c | 16 + src/utils/utils_common.h | 4 + test/CMakeLists.txt | 4 + test/provider_devdax_memory.cpp | 390 +++++++++++++ 16 files changed, 1145 insertions(+) create mode 100644 include/umf/providers/provider_devdax_memory.h create mode 100644 src/provider/provider_devdax_memory.c create mode 100644 src/provider/provider_devdax_memory_internal.h create mode 100644 test/provider_devdax_memory.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index df2e10c16..2ceb75368 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -419,6 +419,9 @@ endif() if(NOT UMF_DISABLE_HWLOC) add_optional_symbol(umfOsMemoryProviderOps) + if(LINUX) + add_optional_symbol(umfDevDaxMemoryProviderOps) + endif() endif() add_subdirectory(src) diff --git a/README.md b/README.md index 0004f0923..64894ecf2 100644 --- a/README.md +++ b/README.md @@ -172,6 +172,22 @@ Additionally, required for tests: 5) Required packages: - liblevel-zero-dev (Linux) or level-zero-sdk (Windows) +#### DevDax memory provider (Linux only) + +A memory provider that provides memory from a device DAX (a character device file /dev/daxX.Y). +It can be used when large memory mappings are needed. + +The DevDax memory provider does not support the free operation +(`umfMemoryProviderFree()` always returns `UMF_RESULT_ERROR_NOT_SUPPORTED`), +so it should be used with a pool manager that will take over +the managing of the provided memory - for example the jemalloc pool +with the `disable_provider_free` parameter set to true. + +##### Requirements + +1) Linux OS +2) A character device file /dev/daxX.Y created in the OS. + ### Memory pool managers #### Proxy pool (part of libumf) diff --git a/include/umf/providers/provider_devdax_memory.h b/include/umf/providers/provider_devdax_memory.h new file mode 100644 index 000000000..113d38372 --- /dev/null +++ b/include/umf/providers/provider_devdax_memory.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 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_DEVDAX_MEMORY_PROVIDER_H +#define UMF_DEVDAX_MEMORY_PROVIDER_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/// @cond +#define UMF_DEVDAX_RESULTS_START_FROM 2000 +/// @endcond + +/// @brief Memory provider settings struct +typedef struct umf_devdax_memory_provider_params_t { + /// path of the device DAX + char *path; + /// size of the device DAX in bytes + size_t size; + /// combination of 'umf_mem_protection_flags_t' flags + unsigned protection; +} umf_devdax_memory_provider_params_t; + +/// @brief Devdax Memory Provider operation results +typedef enum umf_devdax_memory_provider_native_error { + UMF_DEVDAX_RESULT_SUCCESS = UMF_DEVDAX_RESULTS_START_FROM, ///< Success + UMF_DEVDAX_RESULT_ERROR_ALLOC_FAILED, ///< Memory allocation failed + UMF_DEVDAX_RESULT_ERROR_ADDRESS_NOT_ALIGNED, ///< Allocated address is not aligned + UMF_DEVDAX_RESULT_ERROR_FREE_FAILED, ///< Memory deallocation failed + UMF_DEVDAX_RESULT_ERROR_PURGE_FORCE_FAILED, ///< Force purging failed +} umf_devdax_memory_provider_native_error_t; + +umf_memory_provider_ops_t *umfDevDaxMemoryProviderOps(void); + +/// @brief Create default params for the devdax memory provider +static inline umf_devdax_memory_provider_params_t +umfDevDaxMemoryProviderParamsDefault(char *path, size_t size) { + umf_devdax_memory_provider_params_t params = { + path, /* path of the device DAX */ + size, /* size of the device DAX in bytes */ + UMF_PROTECTION_READ | UMF_PROTECTION_WRITE, /* protection */ + }; + + return params; +} + +#ifdef __cplusplus +} +#endif + +#endif /* UMF_DEVDAX_MEMORY_PROVIDER_H */ diff --git a/scripts/docs_config/api.rst b/scripts/docs_config/api.rst index ea0912785..5e39361e1 100644 --- a/scripts/docs_config/api.rst +++ b/scripts/docs_config/api.rst @@ -96,6 +96,14 @@ A memory provider that provides memory from L0 device. .. doxygenfile:: provider_level_zero.h :sections: define enum typedef func var +DevDax Memory Provider +------------------------------------------ + +A memory provider that provides memory from a device DAX (a character device file /dev/daxX.Y). + +.. doxygenfile:: provider_devdax_memory.h + :sections: define enum typedef func var + Memspace ========================================== diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 839bb8bd2..00aeb8a47 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -101,6 +101,7 @@ set(UMF_SOURCES_MACOSX libumf_linux.c) set(UMF_SOURCES_WINDOWS libumf_windows.c) set(UMF_SOURCES_COMMON_LINUX_MACOSX + provider/provider_devdax_memory.c provider/provider_os_memory.c provider/provider_os_memory_posix.c memtargets/memtarget_numa.c diff --git a/src/provider/provider_devdax_memory.c b/src/provider/provider_devdax_memory.c new file mode 100644 index 000000000..68f2689d8 --- /dev/null +++ b/src/provider/provider_devdax_memory.c @@ -0,0 +1,523 @@ +/* + * Copyright (C) 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 "provider_devdax_memory_internal.h" +#include "provider_os_memory_internal.h" +#include "utils_common.h" +#include "utils_concurrency.h" +#include "utils_log.h" + +#include +#include +#include + +#define NODESET_STR_BUF_LEN 1024 + +#define TLS_MSG_BUF_LEN 1024 + +typedef struct devdax_last_native_error_t { + int32_t native_error; + int errno_value; + char msg_buff[TLS_MSG_BUF_LEN]; +} devdax_last_native_error_t; + +static __TLS devdax_last_native_error_t TLS_last_native_error; + +// helper values used only in the Native_error_str array +#define _UMF_DEVDAX_RESULT_SUCCESS \ + (UMF_DEVDAX_RESULT_SUCCESS - UMF_DEVDAX_RESULT_SUCCESS) +#define _UMF_DEVDAX_RESULT_ERROR_ALLOC_FAILED \ + (UMF_DEVDAX_RESULT_ERROR_ALLOC_FAILED - UMF_DEVDAX_RESULT_SUCCESS) +#define _UMF_DEVDAX_RESULT_ERROR_ADDRESS_NOT_ALIGNED \ + (UMF_DEVDAX_RESULT_ERROR_ADDRESS_NOT_ALIGNED - UMF_DEVDAX_RESULT_SUCCESS) +#define _UMF_DEVDAX_RESULT_ERROR_FREE_FAILED \ + (UMF_DEVDAX_RESULT_ERROR_FREE_FAILED - UMF_DEVDAX_RESULT_SUCCESS) +#define _UMF_DEVDAX_RESULT_ERROR_PURGE_FORCE_FAILED \ + (UMF_DEVDAX_RESULT_ERROR_PURGE_FORCE_FAILED - UMF_DEVDAX_RESULT_SUCCESS) + +static const char *Native_error_str[] = { + [_UMF_DEVDAX_RESULT_SUCCESS] = "success", + [_UMF_DEVDAX_RESULT_ERROR_ALLOC_FAILED] = "memory allocation failed", + [_UMF_DEVDAX_RESULT_ERROR_ADDRESS_NOT_ALIGNED] = + "allocated address is not aligned", + [_UMF_DEVDAX_RESULT_ERROR_FREE_FAILED] = "memory deallocation failed", + [_UMF_DEVDAX_RESULT_ERROR_PURGE_FORCE_FAILED] = "force purging failed", +}; + +static void devdax_store_last_native_error(int32_t native_error, + int errno_value) { + TLS_last_native_error.native_error = native_error; + TLS_last_native_error.errno_value = errno_value; +} + +static umf_result_t +devdax_translate_params(umf_devdax_memory_provider_params_t *in_params, + devdax_memory_provider_t *provider) { + umf_result_t result; + + result = os_translate_mem_protection_flags(in_params->protection, + &provider->protection); + if (result != UMF_RESULT_SUCCESS) { + LOG_ERR("incorrect memory protection flags: %u", in_params->protection); + return result; + } + + return UMF_RESULT_SUCCESS; +} + +static umf_result_t devdax_initialize(void *params, void **provider) { + umf_result_t ret; + + if (provider == NULL || params == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + umf_devdax_memory_provider_params_t *in_params = + (umf_devdax_memory_provider_params_t *)params; + + if (in_params->path == NULL) { + LOG_ERR("devdax path is missing"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + if (in_params->size == 0) { + LOG_ERR("devdax size is 0"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + devdax_memory_provider_t *devdax_provider = + umf_ba_global_alloc(sizeof(*devdax_provider)); + if (!devdax_provider) { + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + memset(devdax_provider, 0, sizeof(*devdax_provider)); + + ret = devdax_translate_params(in_params, devdax_provider); + if (ret != UMF_RESULT_SUCCESS) { + goto err_free_devdax_provider; + } + + devdax_provider->size = in_params->size; + if (util_copy_path(in_params->path, devdax_provider->path, PATH_MAX)) { + goto err_free_devdax_provider; + } + + int fd = os_devdax_open(in_params->path); + if (fd == -1) { + LOG_ERR("cannot open the device DAX: %s", in_params->path); + ret = UMF_RESULT_ERROR_INVALID_ARGUMENT; + goto err_free_devdax_provider; + } + + devdax_provider->base = os_devdax_mmap(NULL, devdax_provider->size, + devdax_provider->protection, fd); + utils_close_fd(fd); + if (devdax_provider->base == NULL) { + LOG_PDEBUG("devdax memory mapping failed (path=%s, size=%zu)", + in_params->path, devdax_provider->size); + ret = UMF_RESULT_ERROR_UNKNOWN; + goto err_free_devdax_provider; + } + + LOG_DEBUG("devdax memory mapped (path=%s, size=%zu, addr=%p)", + in_params->path, devdax_provider->size, devdax_provider->base); + + if (util_mutex_init(&devdax_provider->lock) == NULL) { + LOG_ERR("lock init failed"); + ret = UMF_RESULT_ERROR_UNKNOWN; + goto err_unmap_devdax; + } + + *provider = devdax_provider; + + return UMF_RESULT_SUCCESS; + +err_unmap_devdax: + os_munmap(devdax_provider->base, devdax_provider->size); +err_free_devdax_provider: + umf_ba_global_free(devdax_provider); + return ret; +} + +static void devdax_finalize(void *provider) { + if (provider == NULL) { + assert(0); + return; + } + + devdax_memory_provider_t *devdax_provider = provider; + util_mutex_destroy_not_free(&devdax_provider->lock); + os_munmap(devdax_provider->base, devdax_provider->size); + umf_ba_global_free(devdax_provider); +} + +static int devdax_alloc_aligned(size_t length, size_t alignment, void *base, + size_t size, os_mutex_t *lock, void **out_addr, + size_t *offset) { + assert(out_addr); + + if (util_mutex_lock(lock)) { + LOG_ERR("locking file offset failed"); + return -1; + } + + uintptr_t ptr = (uintptr_t)base + *offset; + uintptr_t rest_of_div = alignment ? (ptr % alignment) : 0; + + if (alignment > 0 && rest_of_div > 0) { + ptr += alignment - rest_of_div; + } + + size_t new_offset = ptr - (uintptr_t)base + length; + + if (new_offset > size) { + util_mutex_unlock(lock); + LOG_ERR("cannot allocate more memory than the device DAX size: %zu", + size); + return -1; + } + + *offset = new_offset; + *out_addr = (void *)ptr; + + util_mutex_unlock(lock); + + return 0; +} + +static umf_result_t devdax_alloc(void *provider, size_t size, size_t alignment, + void **resultPtr) { + int ret; + + if (provider == NULL || resultPtr == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + // alignment must be a power of two and a multiple of sizeof(void *) + if (alignment && + ((alignment & (alignment - 1)) || (alignment % sizeof(void *)))) { + LOG_ERR("wrong alignment: %zu (not a power of 2 or a multiple of " + "sizeof(void *))", + alignment); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + devdax_memory_provider_t *devdax_provider = + (devdax_memory_provider_t *)provider; + + void *addr = NULL; + errno = 0; + ret = devdax_alloc_aligned(size, alignment, devdax_provider->base, + devdax_provider->size, &devdax_provider->lock, + &addr, &devdax_provider->offset); + if (ret) { + devdax_store_last_native_error(UMF_DEVDAX_RESULT_ERROR_ALLOC_FAILED, 0); + LOG_ERR("memory allocation failed"); + return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; + } + + *resultPtr = addr; + + return UMF_RESULT_SUCCESS; +} + +// free() is not supported +static umf_result_t devdax_free(void *provider, void *ptr, size_t size) { + (void)provider; // unused + (void)ptr; // unused + (void)size; // unused + + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + +static void devdax_get_last_native_error(void *provider, const char **ppMessage, + int32_t *pError) { + (void)provider; // unused + + if (ppMessage == NULL || pError == NULL) { + assert(0); + return; + } + + *pError = TLS_last_native_error.native_error; + if (TLS_last_native_error.errno_value == 0) { + *ppMessage = Native_error_str[*pError - UMF_DEVDAX_RESULT_SUCCESS]; + return; + } + + const char *msg; + size_t len; + size_t pos = 0; + + msg = Native_error_str[*pError - UMF_DEVDAX_RESULT_SUCCESS]; + len = strlen(msg); + memcpy(TLS_last_native_error.msg_buff + pos, msg, len + 1); + pos += len; + + msg = ": "; + len = strlen(msg); + memcpy(TLS_last_native_error.msg_buff + pos, msg, len + 1); + pos += len; + + os_strerror(TLS_last_native_error.errno_value, + TLS_last_native_error.msg_buff + pos, TLS_MSG_BUF_LEN - pos); + + *ppMessage = TLS_last_native_error.msg_buff; +} + +static umf_result_t devdax_get_recommended_page_size(void *provider, + size_t size, + size_t *page_size) { + (void)size; // unused + + if (provider == NULL || page_size == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + *page_size = os_get_page_size(); + + return UMF_RESULT_SUCCESS; +} + +static umf_result_t devdax_get_min_page_size(void *provider, void *ptr, + size_t *page_size) { + (void)ptr; // unused + + return devdax_get_recommended_page_size(provider, 0, page_size); +} + +static umf_result_t devdax_purge_lazy(void *provider, void *ptr, size_t size) { + (void)provider; // unused + (void)ptr; // unused + (void)size; // unused + // purge_lazy is unsupported in case of the devdax memory provider, + // because the MADV_FREE operation can be applied + // only to private anonymous pages (see madvise(2)). + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + +static umf_result_t devdax_purge_force(void *provider, void *ptr, size_t size) { + if (provider == NULL || ptr == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + errno = 0; + if (os_purge(ptr, size, UMF_PURGE_FORCE)) { + devdax_store_last_native_error( + UMF_DEVDAX_RESULT_ERROR_PURGE_FORCE_FAILED, errno); + LOG_PERR("force purging failed"); + return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; + } + return UMF_RESULT_SUCCESS; +} + +static const char *devdax_get_name(void *provider) { + (void)provider; // unused + return "DEVDAX"; +} + +static umf_result_t devdax_allocation_split(void *provider, void *ptr, + size_t totalSize, + size_t firstSize) { + (void)provider; + (void)ptr; + (void)totalSize; + (void)firstSize; + + return UMF_RESULT_SUCCESS; +} + +static umf_result_t devdax_allocation_merge(void *provider, void *lowPtr, + void *highPtr, size_t totalSize) { + (void)provider; + + if ((uintptr_t)highPtr <= (uintptr_t)lowPtr) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + if ((uintptr_t)highPtr - (uintptr_t)lowPtr <= totalSize) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + return UMF_RESULT_SUCCESS; +} + +typedef struct devdax_ipc_data_t { + char dd_path[PATH_MAX]; // path to the /dev/dax + size_t dd_size; // size of the /dev/dax + size_t offset; // offset of the data +} devdax_ipc_data_t; + +static umf_result_t devdax_get_ipc_handle_size(void *provider, size_t *size) { + if (provider == NULL || size == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + *size = sizeof(devdax_ipc_data_t); + + return UMF_RESULT_SUCCESS; +} + +static umf_result_t devdax_get_ipc_handle(void *provider, const void *ptr, + size_t size, void *providerIpcData) { + (void)size; // unused + + if (provider == NULL || ptr == NULL || providerIpcData == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + devdax_memory_provider_t *devdax_provider = + (devdax_memory_provider_t *)provider; + + devdax_ipc_data_t *devdax_ipc_data = (devdax_ipc_data_t *)providerIpcData; + devdax_ipc_data->offset = + (size_t)((uintptr_t)ptr - (uintptr_t)devdax_provider->base); + strncpy(devdax_ipc_data->dd_path, devdax_provider->path, PATH_MAX - 1); + devdax_ipc_data->dd_path[PATH_MAX - 1] = '\0'; + devdax_ipc_data->dd_size = devdax_provider->size; + + return UMF_RESULT_SUCCESS; +} + +static umf_result_t devdax_put_ipc_handle(void *provider, + void *providerIpcData) { + if (provider == NULL || providerIpcData == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + devdax_memory_provider_t *devdax_provider = + (devdax_memory_provider_t *)provider; + devdax_ipc_data_t *devdax_ipc_data = (devdax_ipc_data_t *)providerIpcData; + + // verify the path of the /dev/dax + if (strncmp(devdax_ipc_data->dd_path, devdax_provider->path, PATH_MAX)) { + LOG_ERR("devdax path mismatch (local: %s, ipc: %s)", + devdax_provider->path, devdax_ipc_data->dd_path); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + // verify the size of the /dev/dax + if (devdax_ipc_data->dd_size != devdax_provider->size) { + LOG_ERR("devdax size mismatch (local: %zu, ipc: %zu)", + devdax_provider->size, devdax_ipc_data->dd_size); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + return UMF_RESULT_SUCCESS; +} + +static umf_result_t devdax_open_ipc_handle(void *provider, + void *providerIpcData, void **ptr) { + if (provider == NULL || providerIpcData == NULL || ptr == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + devdax_memory_provider_t *devdax_provider = + (devdax_memory_provider_t *)provider; + devdax_ipc_data_t *devdax_ipc_data = (devdax_ipc_data_t *)providerIpcData; + + // verify it is the same devdax - first verify the path + if (strncmp(devdax_ipc_data->dd_path, devdax_provider->path, PATH_MAX)) { + LOG_ERR("devdax path mismatch (local: %s, ipc: %s)", + devdax_provider->path, devdax_ipc_data->dd_path); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + // verify the size of the /dev/dax + if (devdax_ipc_data->dd_size != devdax_provider->size) { + LOG_ERR("devdax size mismatch (local: %zu, ipc: %zu)", + devdax_provider->size, devdax_ipc_data->dd_size); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + umf_result_t ret = UMF_RESULT_SUCCESS; + int fd = os_devdax_open(devdax_provider->path); + if (fd <= 0) { + LOG_PERR("opening a devdax (%s) failed", devdax_provider->path); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + char *base = os_devdax_mmap(NULL, devdax_provider->size, + devdax_provider->protection, fd); + if (base == NULL) { + devdax_store_last_native_error(UMF_DEVDAX_RESULT_ERROR_ALLOC_FAILED, + errno); + LOG_PERR("devdax mapping failed (path: %s, size: %zu, protection: %i, " + "fd: %i)", + devdax_provider->path, devdax_provider->size, + devdax_provider->protection, fd); + ret = UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; + } + + LOG_DEBUG("devdax mapped (path: %s, size: %zu, protection: %i, fd: %i, " + "offset: %zu)", + devdax_provider->path, devdax_provider->size, + devdax_provider->protection, fd, devdax_ipc_data->offset); + + (void)utils_close_fd(fd); + + *ptr = base + devdax_ipc_data->offset; + + return ret; +} + +static umf_result_t devdax_close_ipc_handle(void *provider, void *ptr, + size_t size) { + if (provider == NULL || ptr == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + devdax_memory_provider_t *devdax_provider = + (devdax_memory_provider_t *)provider; + + errno = 0; + int ret = os_munmap(devdax_provider->base, devdax_provider->size); + // ignore error when size == 0 + if (ret && (size > 0)) { + devdax_store_last_native_error(UMF_DEVDAX_RESULT_ERROR_FREE_FAILED, + errno); + LOG_PERR("memory unmapping failed"); + + return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; + } + + return UMF_RESULT_SUCCESS; +} + +static umf_memory_provider_ops_t UMF_DEVDAX_MEMORY_PROVIDER_OPS = { + .version = UMF_VERSION_CURRENT, + .initialize = devdax_initialize, + .finalize = devdax_finalize, + .alloc = devdax_alloc, + .free = devdax_free, + .get_last_native_error = devdax_get_last_native_error, + .get_recommended_page_size = devdax_get_recommended_page_size, + .get_min_page_size = devdax_get_min_page_size, + .get_name = devdax_get_name, + .ext.purge_lazy = devdax_purge_lazy, + .ext.purge_force = devdax_purge_force, + .ext.allocation_merge = devdax_allocation_merge, + .ext.allocation_split = devdax_allocation_split, + .ipc.get_ipc_handle_size = devdax_get_ipc_handle_size, + .ipc.get_ipc_handle = devdax_get_ipc_handle, + .ipc.put_ipc_handle = devdax_put_ipc_handle, + .ipc.open_ipc_handle = devdax_open_ipc_handle, + .ipc.close_ipc_handle = devdax_close_ipc_handle}; + +umf_memory_provider_ops_t *umfDevDaxMemoryProviderOps(void) { + return &UMF_DEVDAX_MEMORY_PROVIDER_OPS; +} diff --git a/src/provider/provider_devdax_memory_internal.h b/src/provider/provider_devdax_memory_internal.h new file mode 100644 index 000000000..981089e08 --- /dev/null +++ b/src/provider/provider_devdax_memory_internal.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 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_DEVDAX_MEMORY_PROVIDER_INTERNAL_H +#define UMF_DEVDAX_MEMORY_PROVIDER_INTERNAL_H + +#include + +#include "utils_concurrency.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct devdax_memory_provider_t { + char path[PATH_MAX]; // a path to the device DAX + size_t size; // size of the file used for memory mapping + void *base; // base address of memory mapping + size_t offset; // offset in the file used for memory mapping + os_mutex_t lock; // lock of ptr and offset + unsigned protection; // combination of OS-specific protection flags +} devdax_memory_provider_t; + +#ifdef __cplusplus +} +#endif + +#endif /* UMF_DEVDAX_MEMORY_PROVIDER_INTERNAL_H */ diff --git a/src/provider/provider_os_memory_internal.h b/src/provider/provider_os_memory_internal.h index b9a863f0d..e3bf4002c 100644 --- a/src/provider/provider_os_memory_internal.h +++ b/src/provider/provider_os_memory_internal.h @@ -97,6 +97,8 @@ int os_set_file_size(int fd, size_t size); void *os_mmap(void *hint_addr, size_t length, int prot, int flag, int fd, size_t fd_offset); +void *os_devdax_mmap(void *hint_addr, size_t length, int prot, int fd); + int os_munmap(void *addr, size_t length); int os_purge(void *addr, size_t length, int advice); @@ -105,6 +107,8 @@ size_t os_get_page_size(void); void os_strerror(int errnum, char *buf, size_t buflen); +int os_devdax_open(const char *path); + #ifdef __cplusplus } #endif diff --git a/src/provider/provider_os_memory_linux.c b/src/provider/provider_os_memory_linux.c index e9fd53790..a472dd4b7 100644 --- a/src/provider/provider_os_memory_linux.c +++ b/src/provider/provider_os_memory_linux.c @@ -154,3 +154,27 @@ int os_set_file_size(int fd, size_t size) { } return ret; } + +/* + * MMap a /dev/dax device. + * First try to mmap with (MAP_SHARED_VALIDATE | MAP_SYNC) flags + * which allows flushing from the user-space. If MAP_SYNC fails + * try to mmap with MAP_SHARED flag (without MAP_SYNC). + */ +void *os_devdax_mmap(void *hint_addr, size_t length, int prot, int fd) { + void *ptr = + os_mmap(hint_addr, length, prot, MAP_SHARED_VALIDATE | MAP_SYNC, fd, 0); + if (ptr) { + LOG_DEBUG( + "devdax mapped with the (MAP_SHARED_VALIDATE | MAP_SYNC) flags"); + return ptr; + } + + ptr = os_mmap(hint_addr, length, prot, MAP_SHARED, fd, 0); + if (ptr) { + LOG_DEBUG("devdax mapped with the MAP_SHARED flag"); + return ptr; + } + + return NULL; +} diff --git a/src/provider/provider_os_memory_macosx.c b/src/provider/provider_os_memory_macosx.c index 0075ece64..87bae1b0e 100644 --- a/src/provider/provider_os_memory_macosx.c +++ b/src/provider/provider_os_memory_macosx.c @@ -59,3 +59,11 @@ int os_set_file_size(int fd, size_t size) { (void)size; // unused return 0; // ignored on MacOSX } + +void *os_devdax_mmap(void *hint_addr, size_t length, int prot, int fd) { + (void)hint_addr; // unused + (void)length; // unused + (void)prot; // unused + (void)fd; // unused + return NULL; // not supported on Windows +} diff --git a/src/provider/provider_os_memory_posix.c b/src/provider/provider_os_memory_posix.c index 9308f6a18..63f38cca3 100644 --- a/src/provider/provider_os_memory_posix.c +++ b/src/provider/provider_os_memory_posix.c @@ -6,10 +6,13 @@ */ #include +#include #include #include #include +#include #include +#include #include #include @@ -106,3 +109,39 @@ void os_strerror(int errnum, char *buf, size_t buflen) { LOG_PERR("Retrieving error code description failed"); } } + +// open a devdax +int os_devdax_open(const char *path) { + if (path == NULL) { + LOG_ERR("empty path"); + return -1; + } + + if (strstr(path, "/dev/dax") != path) { + LOG_ERR("path of the file \"%s\" does not start with \"/dev/dax\"", + path); + return -1; + } + + int fd = open(path, O_RDWR); + if (fd == -1) { + LOG_PERR("cannot open the file: %s", path); + return -1; + } + + struct stat statbuf; + int ret = stat(path, &statbuf); + if (ret) { + LOG_PERR("stat(%s) failed", path); + close(fd); + return -1; + } + + if (!S_ISCHR(statbuf.st_mode)) { + LOG_ERR("file %s is not a character device", path); + close(fd); + return -1; + } + + return fd; +} diff --git a/src/provider/provider_os_memory_windows.c b/src/provider/provider_os_memory_windows.c index 994f4d53c..f9232fb66 100644 --- a/src/provider/provider_os_memory_windows.c +++ b/src/provider/provider_os_memory_windows.c @@ -111,6 +111,14 @@ void *os_mmap(void *hint_addr, size_t length, int prot, int flag, int fd, return VirtualAlloc(hint_addr, length, MEM_RESERVE | MEM_COMMIT, prot); } +void *os_devdax_mmap(void *hint_addr, size_t length, int prot, int fd) { + (void)hint_addr; // unused + (void)length; // unused + (void)prot; // unused + (void)fd; // unused + return NULL; // not supported on Windows +} + int os_munmap(void *addr, size_t length) { // If VirtualFree() succeeds, the return value is nonzero. // If VirtualFree() fails, the return value is 0 (zero). @@ -151,3 +159,10 @@ size_t os_get_page_size(void) { void os_strerror(int errnum, char *buf, size_t buflen) { strerror_s(buf, buflen, errnum); } + +// open a devdax +int os_devdax_open(const char *path) { + (void)path; // unused + + return -1; +} diff --git a/src/utils/utils_common.c b/src/utils/utils_common.c index fc6bd58ef..e94126b33 100644 --- a/src/utils/utils_common.c +++ b/src/utils/utils_common.c @@ -75,3 +75,19 @@ const char *util_parse_var(const char *var, const char *option, return found; } + +int util_copy_path(const char *in_path, char out_path[], size_t path_max) { + // (- 1) because there should be a room for the terminating null byte ('\0') + size_t max_len = path_max - 1; + + if (strlen(in_path) > max_len) { + LOG_ERR("path of the %s file is longer than %zu bytes", in_path, + max_len); + return -1; + } + + strncpy(out_path, in_path, max_len); + out_path[path_max - 1] = '\0'; // the terminating null byte + + return 0; +} diff --git a/src/utils/utils_common.h b/src/utils/utils_common.h index 28579eb00..efef2c0c1 100644 --- a/src/utils/utils_common.h +++ b/src/utils/utils_common.h @@ -20,6 +20,8 @@ extern "C" { #endif +#define NAME_MAX 255 + #define DO_WHILE_EMPTY \ do { \ } while (0) @@ -85,6 +87,8 @@ int utils_close_fd(int fd); // obtain a duplicate of another process's file descriptor umf_result_t utils_duplicate_fd(int pid, int fd_in, int *fd_out); +int util_copy_path(const char *in_path, char out_path[], size_t path_max); + #ifdef __cplusplus } #endif diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0d51643de..262276c7d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -228,6 +228,10 @@ if(LINUX AND (NOT UMF_DISABLE_HWLOC)) # OS-specific functions are implemented NAME memtarget SRCS memspaces/memtarget.cpp LIBS ${LIBNUMA_LIBRARIES} ${LIBHWLOC_LIBRARIES}) + add_umf_test( + NAME provider_devdax_memory + SRCS provider_devdax_memory.cpp + LIBS ${UMF_UTILS_FOR_TEST}) if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND UMF_BUILD_FUZZTESTS) add_subdirectory(fuzz) endif() diff --git a/test/provider_devdax_memory.cpp b/test/provider_devdax_memory.cpp new file mode 100644 index 000000000..8b0f0360f --- /dev/null +++ b/test/provider_devdax_memory.cpp @@ -0,0 +1,390 @@ +// Copyright (C) 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 _WIN32 +#include +#include +#include +#endif + +#include "base.hpp" + +#include "cpp_helpers.hpp" + +#include +#include + +using umf_test::test; + +#define INVALID_PTR ((void *)0x01) + +#define ASSERT_IS_ALIGNED(ptr, alignment) \ + ASSERT_EQ(((uintptr_t)ptr % alignment), 0) + +typedef enum purge_t { + PURGE_NONE = 0, + PURGE_LAZY = 1, + PURGE_FORCE = 2, +} purge_t; + +static const char *Native_error_str[] = { + "success", // UMF_DEVDAX_RESULT_SUCCESS + "memory allocation failed", // UMF_DEVDAX_RESULT_ERROR_ALLOC_FAILED + "allocated address is not aligned", // UMF_DEVDAX_RESULT_ERROR_ADDRESS_NOT_ALIGNED + "memory deallocation failed", // UMF_DEVDAX_RESULT_ERROR_FREE_FAILED + "force purging failed", // UMF_DEVDAX_RESULT_ERROR_PURGE_FORCE_FAILED +}; + +// test helpers + +static int compare_native_error_str(const char *message, int error) { + const char *error_str = Native_error_str[error - UMF_DEVDAX_RESULT_SUCCESS]; + size_t len = strlen(error_str); + return strncmp(message, error_str, len); +} + +using providerCreateExtParams = std::tuple; + +static void providerCreateExt(providerCreateExtParams params, + umf::provider_unique_handle_t *handle) { + umf_memory_provider_handle_t hProvider = nullptr; + auto [provider_ops, provider_params] = params; + + auto ret = + umfMemoryProviderCreate(provider_ops, provider_params, &hProvider); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(hProvider, nullptr); + + *handle = + umf::provider_unique_handle_t(hProvider, &umfMemoryProviderDestroy); +} + +struct umfProviderTest + : umf_test::test, + ::testing::WithParamInterface { + void SetUp() override { + char *path = getenv("UMF_TESTS_DEVDAX_PATH"); + if (path == nullptr || path[0] == 0) { + GTEST_SKIP() << "Test skipped, UMF_TESTS_DEVDAX_PATH is not set"; + } + + char *size = getenv("UMF_TESTS_DEVDAX_SIZE"); + if (size == nullptr || size[0] == 0) { + GTEST_SKIP() << "Test skipped, UMF_TESTS_DEVDAX_SIZE is not set"; + } + + test::SetUp(); + providerCreateExt(this->GetParam(), &provider); + umf_result_t umf_result = umfMemoryProviderGetMinPageSize( + provider.get(), nullptr, &page_size); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + page_plus_64 = page_size + 64; + } + + void TearDown() override { test::TearDown(); } + + umf::provider_unique_handle_t provider; + size_t page_size; + size_t page_plus_64; +}; + +static void test_alloc_free_success(umf_memory_provider_handle_t provider, + size_t size, size_t alignment, + purge_t purge) { + void *ptr = nullptr; + + umf_result_t umf_result = + umfMemoryProviderAlloc(provider, size, alignment, &ptr); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(ptr, nullptr); + + memset(ptr, 0xFF, size); + + if (purge == PURGE_LAZY) { + umf_result = umfMemoryProviderPurgeLazy(provider, ptr, size); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); + } else if (purge == PURGE_FORCE) { + umf_result = umfMemoryProviderPurgeForce(provider, ptr, size); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + } + + umf_result = umfMemoryProviderFree(provider, ptr, size); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); +} + +static void verify_last_native_error(umf_memory_provider_handle_t provider, + int32_t err) { + const char *message; + int32_t error; + umfMemoryProviderGetLastNativeError(provider, &message, &error); + ASSERT_EQ(error, err); + ASSERT_EQ(compare_native_error_str(message, error), 0); +} + +static void test_alloc_failure(umf_memory_provider_handle_t provider, + size_t size, size_t alignment, + umf_result_t result, int32_t err) { + void *ptr = nullptr; + umf_result_t umf_result = + umfMemoryProviderAlloc(provider, size, alignment, &ptr); + ASSERT_EQ(umf_result, result); + ASSERT_EQ(ptr, nullptr); + + if (umf_result == UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC) { + verify_last_native_error(provider, err); + } +} + +// TESTS + +// Test checking if devdax was mapped with the MAP_SYNC flag: +// 1) Open and read the /proc/self/smaps file. +// 2) Look for the section of the devdax (the /dev/daxX.Y path). +// 3) Check if the VmFlags of the /dev/daxX.Y contains the "sf" flag +// marking that the devdax was mapped with the MAP_SYNC flag. +TEST_F(test, test_if_mapped_with_MAP_SYNC) { + umf_memory_provider_handle_t hProvider = nullptr; + umf_result_t umf_result; + + char *path = getenv("UMF_TESTS_DEVDAX_PATH"); + if (path == nullptr || path[0] == 0) { + GTEST_SKIP() << "Test skipped, UMF_TESTS_DEVDAX_PATH is not set"; + } + + char *size_str = getenv("UMF_TESTS_DEVDAX_SIZE"); + if (size_str == nullptr || size_str[0] == 0) { + GTEST_SKIP() << "Test skipped, UMF_TESTS_DEVDAX_SIZE is not set"; + } + + size_t size = atol(size_str); + auto params = umfDevDaxMemoryProviderParamsDefault(path, size); + + umf_result = umfMemoryProviderCreate(umfDevDaxMemoryProviderOps(), ¶ms, + &hProvider); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(hProvider, nullptr); + + char *buf; + umf_result = umfMemoryProviderAlloc(hProvider, size, 0, (void **)&buf); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(buf, nullptr); + memset(buf, 0, size); + + int fd = open("/proc/self/smaps", O_RDONLY); + ASSERT_NE(fd, -1); + + // number of bytes read from the file + ssize_t nbytes = 1; + // string starting from the path of the devdax + char *devdax = nullptr; + + // Read the "/proc/self/smaps" file + // until the path of the devdax is found + // or EOF is reached. + while (nbytes > 0 && devdax == nullptr) { + memset(buf, 0, nbytes); // erase previous data + nbytes = read(fd, buf, size); + // look for the path of the devdax + devdax = strstr(buf, path); + } + + // String starting from the "sf" flag + // marking that memory was mapped with the MAP_SYNC flag. + char *sf_flag = nullptr; + + if (devdax) { + // look for the "VmFlags:" string + char *VmFlags = strstr(devdax, "VmFlags:"); + if (VmFlags) { + // look for the EOL + char *eol = strstr(VmFlags, "\n"); + if (eol) { + // End the VmFlags string at EOL. + *eol = 0; + // Now the VmFlags string contains only one line with all VmFlags. + + // Look for the "sf" flag in VmFlags + // marking that memory was mapped + // with the MAP_SYNC flag. + sf_flag = strstr(VmFlags, "sf"); + } + } + } + + umf_result = umfMemoryProviderFree(hProvider, buf, size); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); + + umfMemoryProviderDestroy(hProvider); + + // fail test if the "sf" flag was not found + ASSERT_NE(sf_flag, nullptr); +} + +// positive tests using test_alloc_free_success + +auto defaultParams = umfDevDaxMemoryProviderParamsDefault( + getenv("UMF_TESTS_DEVDAX_PATH"), + atol(getenv("UMF_TESTS_DEVDAX_SIZE") ? getenv("UMF_TESTS_DEVDAX_SIZE") + : "0")); + +INSTANTIATE_TEST_SUITE_P(devdaxProviderTest, umfProviderTest, + ::testing::Values(providerCreateExtParams{ + umfDevDaxMemoryProviderOps(), &defaultParams})); + +TEST_P(umfProviderTest, create_destroy) {} + +TEST_P(umfProviderTest, alloc_page64_align_0) { + test_alloc_free_success(provider.get(), page_plus_64, 0, PURGE_NONE); +} + +TEST_P(umfProviderTest, alloc_page64_align_page_div_2) { + test_alloc_free_success(provider.get(), page_plus_64, page_size / 2, + PURGE_NONE); +} + +TEST_P(umfProviderTest, purge_lazy) { + test_alloc_free_success(provider.get(), page_plus_64, 0, PURGE_LAZY); +} + +TEST_P(umfProviderTest, purge_force) { + test_alloc_free_success(provider.get(), page_plus_64, 0, PURGE_FORCE); +} + +// negative tests using test_alloc_failure + +TEST_P(umfProviderTest, alloc_page64_align_page_minus_1_WRONG_ALIGNMENT_1) { + test_alloc_failure(provider.get(), page_plus_64, page_size - 1, + UMF_RESULT_ERROR_INVALID_ARGUMENT, 0); +} + +TEST_P(umfProviderTest, alloc_page64_align_one_half_pages_WRONG_ALIGNMENT_2) { + test_alloc_failure(provider.get(), page_plus_64, + page_size + (page_size / 2), + UMF_RESULT_ERROR_INVALID_ARGUMENT, 0); +} + +TEST_P(umfProviderTest, alloc_page64_WRONG_ALIGNMENT_3_pages) { + test_alloc_failure(provider.get(), page_plus_64, 3 * page_size, + UMF_RESULT_ERROR_INVALID_ARGUMENT, 0); +} + +TEST_P(umfProviderTest, alloc_3_pages_WRONG_ALIGNMENT_3_pages) { + test_alloc_failure(provider.get(), 3 * page_size, 3 * page_size, + UMF_RESULT_ERROR_INVALID_ARGUMENT, 0); +} + +TEST_P(umfProviderTest, alloc_WRONG_SIZE) { + test_alloc_failure(provider.get(), -1, 0, + UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC, + UMF_DEVDAX_RESULT_ERROR_ALLOC_FAILED); +} + +// other positive tests + +TEST_P(umfProviderTest, get_min_page_size) { + size_t min_page_size; + umf_result_t umf_result = umfMemoryProviderGetMinPageSize( + provider.get(), nullptr, &min_page_size); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_LE(min_page_size, page_size); +} + +TEST_P(umfProviderTest, get_recommended_page_size) { + size_t min_page_size; + umf_result_t umf_result = umfMemoryProviderGetMinPageSize( + provider.get(), nullptr, &min_page_size); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_LE(min_page_size, page_size); + + size_t recommended_page_size; + umf_result = umfMemoryProviderGetRecommendedPageSize( + provider.get(), 0, &recommended_page_size); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_GE(recommended_page_size, min_page_size); +} + +TEST_P(umfProviderTest, get_name) { + const char *name = umfMemoryProviderGetName(provider.get()); + ASSERT_STREQ(name, "DEVDAX"); +} + +TEST_P(umfProviderTest, free_size_0_ptr_not_null) { + umf_result_t umf_result = + umfMemoryProviderFree(provider.get(), INVALID_PTR, 0); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); +} + +TEST_P(umfProviderTest, free_NULL) { + umf_result_t umf_result = umfMemoryProviderFree(provider.get(), nullptr, 0); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); +} + +// other negative tests + +TEST_P(umfProviderTest, free_INVALID_POINTER_SIZE_GT_0) { + umf_result_t umf_result = + umfMemoryProviderFree(provider.get(), INVALID_PTR, page_plus_64); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); +} + +TEST_P(umfProviderTest, purge_lazy_INVALID_POINTER) { + umf_result_t umf_result = + umfMemoryProviderPurgeLazy(provider.get(), INVALID_PTR, 1); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); +} + +TEST_P(umfProviderTest, purge_force_INVALID_POINTER) { + umf_result_t umf_result = + umfMemoryProviderPurgeForce(provider.get(), INVALID_PTR, 1); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC); + + verify_last_native_error(provider.get(), + UMF_DEVDAX_RESULT_ERROR_PURGE_FORCE_FAILED); +} + +// negative tests + +TEST_F(test, create_empty_path) { + umf_memory_provider_handle_t hProvider = nullptr; + const char *path = ""; + auto wrong_params = + umfDevDaxMemoryProviderParamsDefault((char *)path, 4096); + auto ret = umfMemoryProviderCreate(umfDevDaxMemoryProviderOps(), + &wrong_params, &hProvider); + EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + EXPECT_EQ(hProvider, nullptr); +} + +TEST_F(test, create_wrong_path) { + umf_memory_provider_handle_t hProvider = nullptr; + const char *path = "/tmp/dev/dax0.0"; + auto wrong_params = + umfDevDaxMemoryProviderParamsDefault((char *)path, 4096); + auto ret = umfMemoryProviderCreate(umfDevDaxMemoryProviderOps(), + &wrong_params, &hProvider); + EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + EXPECT_EQ(hProvider, nullptr); +} + +TEST_F(test, create_wrong_path_not_exist) { + umf_memory_provider_handle_t hProvider = nullptr; + const char *path = "/dev/dax1.1"; + auto wrong_params = + umfDevDaxMemoryProviderParamsDefault((char *)path, 4096); + auto ret = umfMemoryProviderCreate(umfDevDaxMemoryProviderOps(), + &wrong_params, &hProvider); + EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + EXPECT_EQ(hProvider, nullptr); +} + +TEST_F(test, create_wrong_size_0) { + umf_memory_provider_handle_t hProvider = nullptr; + const char *path = "/dev/dax0.0"; + auto wrong_params = umfDevDaxMemoryProviderParamsDefault((char *)path, 0); + auto ret = umfMemoryProviderCreate(umfDevDaxMemoryProviderOps(), + &wrong_params, &hProvider); + EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + EXPECT_EQ(hProvider, nullptr); +} From 4d5f6a3887f34afaf0382bf8c7eb0c12d272f4af Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Tue, 3 Sep 2024 16:27:06 +0200 Subject: [PATCH 088/352] Add IPC test for devdax memory provider Signed-off-by: Lukasz Dorau --- test/CMakeLists.txt | 16 ++++++++++++ test/common/ipc_common.c | 14 ++++++----- test/ipc_devdax_prov.sh | 34 ++++++++++++++++++++++++++ test/ipc_devdax_prov_consumer.c | 43 +++++++++++++++++++++++++++++++++ test/ipc_devdax_prov_producer.c | 43 +++++++++++++++++++++++++++++++++ test/test_valgrind.sh | 4 +++ 6 files changed, 148 insertions(+), 6 deletions(-) create mode 100755 test/ipc_devdax_prov.sh create mode 100644 test/ipc_devdax_prov_consumer.c create mode 100644 test/ipc_devdax_prov_producer.c diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 262276c7d..be6d9ad7d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -350,6 +350,22 @@ if(LINUX) common/ipc_os_prov_common.c) add_umf_ipc_test(TEST ipc_os_prov_anon_fd) add_umf_ipc_test(TEST ipc_os_prov_shm) + + build_umf_test( + NAME + ipc_devdax_prov_consumer + SRCS + ipc_devdax_prov_consumer.c + common/ipc_common.c + common/ipc_os_prov_common.c) + build_umf_test( + NAME + ipc_devdax_prov_producer + SRCS + ipc_devdax_prov_producer.c + common/ipc_common.c + common/ipc_os_prov_common.c) + add_umf_ipc_test(TEST ipc_devdax_prov) endif() if(UMF_BUILD_GPU_TESTS AND UMF_BUILD_LEVEL_ZERO_PROVIDER) build_umf_test( diff --git a/test/common/ipc_common.c b/test/common/ipc_common.c index 7e08e79f0..18ce263d8 100644 --- a/test/common/ipc_common.c +++ b/test/common/ipc_common.c @@ -16,7 +16,6 @@ #define INET_ADDR "127.0.0.1" #define MSG_SIZE 1024 -#define RECV_BUFF_SIZE 1024 // consumer's response message #define CONSUMER_MSG \ @@ -111,7 +110,6 @@ int run_consumer(int port, umf_memory_provider_ops_t *provider_ops, void *provider_params, memcopy_callback_t memcopy_callback, void *memcopy_ctx) { char consumer_message[MSG_SIZE]; - char recv_buffer[RECV_BUFF_SIZE]; int producer_socket = -1; int ret = -1; umf_memory_provider_handle_t provider = NULL; @@ -138,16 +136,20 @@ int run_consumer(int port, umf_memory_provider_ops_t *provider_ops, goto err_umfMemoryProviderDestroy; } + // allocate the zeroed receive buffer + char *recv_buffer = calloc(1, IPC_handle_size); + if (!recv_buffer) { + fprintf(stderr, "[consumer] ERROR: out of memory\n"); + goto err_umfMemoryProviderDestroy; + } + producer_socket = consumer_connect(port); if (producer_socket < 0) { goto err_umfMemoryProviderDestroy; } - // zero the receive buffer - memset(recv_buffer, 0, RECV_BUFF_SIZE); - // receive a producer's message - ssize_t recv_len = recv(producer_socket, recv_buffer, RECV_BUFF_SIZE, 0); + ssize_t recv_len = recv(producer_socket, recv_buffer, IPC_handle_size, 0); if (recv_len < 0) { fprintf(stderr, "[consumer] ERROR: recv() failed\n"); goto err_close_producer_socket; diff --git a/test/ipc_devdax_prov.sh b/test/ipc_devdax_prov.sh new file mode 100755 index 000000000..7c5ba3675 --- /dev/null +++ b/test/ipc_devdax_prov.sh @@ -0,0 +1,34 @@ +# +# Copyright (C) 2024 Intel Corporation +# +# Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +#!/bin/bash + +set -e + +if [ "$UMF_TESTS_DEVDAX_PATH" = "" ]; then + echo "Test skipped, UMF_TESTS_DEVDAX_PATH is not set" + exit 0 +fi + +if [ "$UMF_TESTS_DEVDAX_SIZE" = "" ]; then + echo "Test skipped, UMF_TESTS_DEVDAX_SIZE is not set" + exit 0 +fi + +# port should be a number from the range <1024, 65535> +PORT=$(( 1024 + ( $$ % ( 65535 - 1024 )))) + +UMF_LOG_VAL="level:debug;flush:debug;output:stderr;pid:yes" + +echo "Starting ipc_devdax_prov CONSUMER on port $PORT ..." +UMF_LOG=$UMF_LOG_VAL ./umf_test-ipc_devdax_prov_consumer $PORT & + +echo "Waiting 1 sec ..." +sleep 1 + +echo "Starting ipc_devdax_prov PRODUCER on port $PORT ..." +UMF_LOG=$UMF_LOG_VAL ./umf_test-ipc_devdax_prov_producer $PORT diff --git a/test/ipc_devdax_prov_consumer.c b/test/ipc_devdax_prov_consumer.c new file mode 100644 index 000000000..05478e436 --- /dev/null +++ b/test/ipc_devdax_prov_consumer.c @@ -0,0 +1,43 @@ +/* + * Copyright (C) 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 "ipc_common.h" +#include "ipc_os_prov_common.h" + +int main(int argc, char *argv[]) { + if (argc < 2) { + fprintf(stderr, "usage: %s \n", argv[0]); + return -1; + } + + int port = atoi(argv[1]); + + char *path = getenv("UMF_TESTS_DEVDAX_PATH"); + if (path == NULL || path[0] == 0) { + fprintf(stderr, "Test skipped, UMF_TESTS_DEVDAX_PATH is not set\n"); + return 0; + } + + char *size = getenv("UMF_TESTS_DEVDAX_SIZE"); + if (size == NULL || size[0] == 0) { + fprintf(stderr, "Test skipped, UMF_TESTS_DEVDAX_SIZE is not set\n"); + return 0; + } + + umf_devdax_memory_provider_params_t devdax_params = + umfDevDaxMemoryProviderParamsDefault( + getenv("UMF_TESTS_DEVDAX_PATH"), + atol(getenv("UMF_TESTS_DEVDAX_SIZE"))); + + return run_consumer(port, umfDevDaxMemoryProviderOps(), &devdax_params, + memcopy, NULL); +} diff --git a/test/ipc_devdax_prov_producer.c b/test/ipc_devdax_prov_producer.c new file mode 100644 index 000000000..820d0fba9 --- /dev/null +++ b/test/ipc_devdax_prov_producer.c @@ -0,0 +1,43 @@ +/* + * Copyright (C) 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 "ipc_common.h" +#include "ipc_os_prov_common.h" + +int main(int argc, char *argv[]) { + if (argc < 2) { + fprintf(stderr, "usage: %s \n", argv[0]); + return -1; + } + + int port = atoi(argv[1]); + + char *path = getenv("UMF_TESTS_DEVDAX_PATH"); + if (path == NULL || path[0] == 0) { + fprintf(stderr, "Test skipped, UMF_TESTS_DEVDAX_PATH is not set\n"); + return 0; + } + + char *size = getenv("UMF_TESTS_DEVDAX_SIZE"); + if (size == NULL || size[0] == 0) { + fprintf(stderr, "Test skipped, UMF_TESTS_DEVDAX_SIZE is not set\n"); + return 0; + } + + umf_devdax_memory_provider_params_t devdax_params = + umfDevDaxMemoryProviderParamsDefault( + getenv("UMF_TESTS_DEVDAX_PATH"), + atol(getenv("UMF_TESTS_DEVDAX_SIZE"))); + + return run_producer(port, umfDevDaxMemoryProviderOps(), &devdax_params, + memcopy, NULL); +} diff --git a/test/test_valgrind.sh b/test/test_valgrind.sh index ea4e155fb..4c8a5633a 100755 --- a/test/test_valgrind.sh +++ b/test/test_valgrind.sh @@ -88,6 +88,10 @@ for test in $(ls -1 umf_test-*); do echo "- SKIPPED" continue; # skip testing helper binaries used by the ipc_os_prov_* tests ;; + umf_test-ipc_devdax_prov_*) + echo "- SKIPPED" + continue; # skip testing helper binaries used by the ipc_devdax_prov_* tests + ;; umf_test-memspace_host_all) FILTER='--gtest_filter="-*allocsSpreadAcrossAllNumaNodes"' ;; From 7654d792c76b0e6474a0d657590aa04236c7e1d2 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 11 Sep 2024 11:31:00 +0200 Subject: [PATCH 089/352] Add devdax CI workflow Signed-off-by: Lukasz Dorau --- .github/workflows/devdax.yml | 66 +++++++++++++++++++++++++++++++++++ .github/workflows/pr_push.yml | 3 ++ 2 files changed, 69 insertions(+) create mode 100644 .github/workflows/devdax.yml diff --git a/.github/workflows/devdax.yml b/.github/workflows/devdax.yml new file mode 100644 index 000000000..3f2b3afc9 --- /dev/null +++ b/.github/workflows/devdax.yml @@ -0,0 +1,66 @@ +# This workflow builds and tests the devdax memory provider. +# It requires a DAX device (e.g. /dev/dax0.0) configured in the OS. +# This DAX device should be specified using UMF_TESTS_DEVDAX_PATH and UMF_TESTS_DEVDAX_SIZE +# CI environment variables. + +name: DevDax + +on: [workflow_call] + +permissions: + contents: read + +env: + UMF_TESTS_DEVDAX_PATH : "/dev/dax0.0" + UMF_TESTS_DEVDAX_SIZE : 1054867456 + BUILD_DIR : "${{github.workspace}}/build" + INSTL_DIR : "${{github.workspace}}/../install-dir" + +jobs: + devdax: + name: Build + # run only on upstream; forks may not have a DAX device + if: github.repository == 'oneapi-src/unified-memory-framework' + strategy: + matrix: + build_type: [Debug, Release] + shared_library: ['ON', 'OFF'] + + runs-on: ["DSS-DEVDAX", "DSS-Ubuntu"] + steps: + - name: Check if the devdax exists + run: | + ndctl list -N --device-dax + ls -al ${{env.UMF_TESTS_DEVDAX_PATH}} + + - name: Checkout + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + + - name: Configure build + run: > + cmake + -B ${{env.BUILD_DIR}} + -DCMAKE_INSTALL_PREFIX="${{env.INSTL_DIR}}" + -DCMAKE_BUILD_TYPE=${{matrix.build_type}} + -DCMAKE_C_COMPILER=gcc + -DCMAKE_CXX_COMPILER=g++ + -DUMF_BUILD_SHARED_LIBRARY=${{matrix.shared_library}} + -DUMF_BUILD_BENCHMARKS=OFF + -DUMF_BUILD_TESTS=ON + -DUMF_BUILD_GPU_TESTS=OFF + -DUMF_BUILD_GPU_EXAMPLES=OFF + -DUMF_FORMAT_CODE_STYLE=OFF + -DUMF_DEVELOPER_MODE=ON + -DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON + -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON + -DUMF_BUILD_LEVEL_ZERO_PROVIDER=OFF + -DUMF_TESTS_FAIL_ON_SKIP=ON + + - name: Build UMF + run: cmake --build ${{env.BUILD_DIR}} --config ${{matrix.build_type}} -j $(nproc) + + - name: Run only devdax tests + working-directory: ${{env.BUILD_DIR}} + run: ctest -C ${{matrix.build_type}} -R devdax -V diff --git a/.github/workflows/pr_push.yml b/.github/workflows/pr_push.yml index c42d6e098..4c7a27c1d 100644 --- a/.github/workflows/pr_push.yml +++ b/.github/workflows/pr_push.yml @@ -85,6 +85,9 @@ jobs: name: Basic builds needs: [FastBuild] uses: ./.github/workflows/basic.yml + DevDax: + needs: [FastBuild] + uses: ./.github/workflows/devdax.yml Sanitizers: needs: [FastBuild] uses: ./.github/workflows/sanitizers.yml From 5ffb7138e3fe4614b67c447276ae5ece4333d82c Mon Sep 17 00:00:00 2001 From: Martin Morrison-Grant Date: Wed, 11 Sep 2024 17:39:06 +0100 Subject: [PATCH 090/352] Update docs for using formatting targets to make it more obvious about helper format-check and format-apply targets. --- CONTRIBUTING.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ec579c0be..48eb62579 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -89,10 +89,11 @@ $ cmake --build build --target format-apply # Remember to review introduced changes ``` -If you wish to use only `clang-format`, or `cmake-format`, or `black`, you can execute the corresponding -`clang-format-check` and `clang-format-apply` for C/C++ source files, or `cmake-format-check` and -`cmake-format-apply` for CMake files, or `black-format-check` and `black-format-apply` for Python -source files, respectively. +**NOTE**: The `format-check` and `format-apply` targets are only available if all of `clang-format`, +`cmake-format` and `black` are installed. Otherwise you can use them separately with: +- `clang-format-check` and `clang-format-apply` for C/C++ source files +- `cmake-format-check` and `cmake-format-apply` for CMake files +- `black-format-check` and `black-format-apply` for Python source files **NOTE**: We use specific versions of formatting tools to ensure consistency across the project. The required versions are: - clang-format version **15.0**, which can be installed with the command: `python -m pip install clang-format==15.0.7`. @@ -220,4 +221,4 @@ $ ctest $ apt install lcov $ lcov --capture --directory . --output-file coverage.info $ genhtml -o html_report coverage.info -``` \ No newline at end of file +``` From 730e1ce85aefb90bcc1f6e27179c5463fe1fe27d Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Fri, 13 Sep 2024 12:12:44 +0200 Subject: [PATCH 091/352] Remove excessive definition of NAME_MAX Signed-off-by: Lukasz Dorau --- src/utils/utils_common.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/utils/utils_common.h b/src/utils/utils_common.h index efef2c0c1..5a6fb87c0 100644 --- a/src/utils/utils_common.h +++ b/src/utils/utils_common.h @@ -20,8 +20,6 @@ extern "C" { #endif -#define NAME_MAX 255 - #define DO_WHILE_EMPTY \ do { \ } while (0) From 3796e6f8d97132c19995c50ed875d5903478005c Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 16 Sep 2024 09:26:32 +0200 Subject: [PATCH 092/352] Fix condition in devdax_open_ipc_handle() Fix condition in devdax_open_ipc_handle(). os_devdax_open() returns -1 on error. It fixes the Coverity issue no. 468935. Signed-off-by: Lukasz Dorau --- src/provider/provider_devdax_memory.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/provider/provider_devdax_memory.c b/src/provider/provider_devdax_memory.c index 68f2689d8..8d1c4bc9e 100644 --- a/src/provider/provider_devdax_memory.c +++ b/src/provider/provider_devdax_memory.c @@ -446,7 +446,7 @@ static umf_result_t devdax_open_ipc_handle(void *provider, umf_result_t ret = UMF_RESULT_SUCCESS; int fd = os_devdax_open(devdax_provider->path); - if (fd <= 0) { + if (fd == -1) { LOG_PERR("opening a devdax (%s) failed", devdax_provider->path); return UMF_RESULT_ERROR_INVALID_ARGUMENT; } From 17d13b783cb301bead0031f9414b3cfccb653769 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 16 Sep 2024 14:48:45 +0200 Subject: [PATCH 093/352] Fix two testNuma tests Fix two testNuma tests: - checkModeInterleave and - checkModeInterleaveCustomPartSize It fixes the Coverity issue no. 468463. Signed-off-by: Lukasz Dorau --- ...provider_os_memory_multiple_numa_nodes.cpp | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/test/provider_os_memory_multiple_numa_nodes.cpp b/test/provider_os_memory_multiple_numa_nodes.cpp index 5048f92f5..3359b003d 100644 --- a/test/provider_os_memory_multiple_numa_nodes.cpp +++ b/test/provider_os_memory_multiple_numa_nodes.cpp @@ -373,8 +373,19 @@ TEST_F(testNuma, checkModeInterleave) { // Test where each page will be allocated. // Get the first numa node for ptr; Each next page is expected to be on next nodes. + int node = -1; + ASSERT_NO_FATAL_FAILURE(getNumaNodeByPtr(ptr, &node)); + ASSERT_GE(node, 0); int index = -1; - ASSERT_NO_FATAL_FAILURE(getNumaNodeByPtr(ptr, &index)); + for (size_t i = 0; i < numa_nodes.size(); i++) { + if (numa_nodes[i] == (unsigned)node) { + index = i; + break; + } + } + ASSERT_GE(index, 0); + ASSERT_LT(index, numa_nodes.size()); + for (size_t i = 1; i < (size_t)pages_num; i++) { index = (index + 1) % numa_nodes.size(); EXPECT_NODE_EQ((char *)ptr + page_size * i, numa_nodes[index]); @@ -417,8 +428,19 @@ TEST_F(testNuma, checkModeInterleaveCustomPartSize) { memset(ptr, 0xFF, size); // Test where each page will be allocated. // Get the first numa node for ptr; Each next part is expected to be on next nodes. + int node = -1; + ASSERT_NO_FATAL_FAILURE(getNumaNodeByPtr(ptr, &node)); + ASSERT_GE(node, 0); int index = -1; - ASSERT_NO_FATAL_FAILURE(getNumaNodeByPtr(ptr, &index)); + for (size_t i = 0; i < numa_nodes.size(); i++) { + if (numa_nodes[i] == (unsigned)node) { + index = i; + break; + } + } + ASSERT_GE(index, 0); + ASSERT_LT(index, numa_nodes.size()); + for (size_t i = 0; i < (size_t)part_num; i++) { for (size_t j = 0; j < part_size; j += page_size) { ASSERT_NODE_EQ((char *)ptr + part_size * i + j, numa_nodes[index]); From b9f5778b1bcf49cd3395003269e1c07360abb99b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Plewa?= Date: Wed, 21 Aug 2024 14:44:33 +0200 Subject: [PATCH 094/352] add umfMemspace[New|TargetRemove|TargetAdd] --- include/umf/memspace.h | 33 ++++- src/libumf.def.in | 3 + src/libumf.map.in | 4 + src/memspace.c | 120 +++++++++++++++++ src/memtarget.c | 32 ++++- src/memtarget_internal.h | 6 +- src/memtarget_ops.h | 4 +- src/memtargets/memtarget_numa.c | 15 +++ test/CMakeLists.txt | 4 + test/common/numa_helpers.hpp | 187 ++++++++++++++++++++++++--- test/memspaces/memspace.cpp | 43 ++++++ test/memspaces/memspace_host_all.cpp | 91 +++++++++---- test/memspaces/memspace_numa.cpp | 117 +++++++++++++++-- 13 files changed, 604 insertions(+), 55 deletions(-) create mode 100644 test/memspaces/memspace.cpp diff --git a/include/umf/memspace.h b/include/umf/memspace.h index 10cf0417d..49eb5278e 100644 --- a/include/umf/memspace.h +++ b/include/umf/memspace.h @@ -1,6 +1,6 @@ /* * - * Copyright (C) 2023 Intel Corporation + * 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 @@ -85,6 +85,12 @@ umf_const_memspace_handle_t umfMemspaceHighestBandwidthGet(void); /// umf_const_memspace_handle_t umfMemspaceLowestLatencyGet(void); +/// \brief Creates new empty memspace, which can be populated with umfMemspaceMemtargetAdd() +/// \param hMemspace [out] handle to the newly created memspace +/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +/// +umf_result_t umfMemspaceNew(umf_memspace_handle_t *hMemspace); + /// \brief Returns number of memory targets in memspace. /// \param hMemspace handle to memspace /// \return number of memory targets in memspace @@ -100,6 +106,31 @@ umf_const_memtarget_handle_t umfMemspaceMemtargetGet(umf_const_memspace_handle_t hMemspace, unsigned targetNum); +/// \brief Adds memory target to memspace. +/// +/// \details +/// This function duplicates the memory target and then adds it to the memspace. +/// This means that original memtarget handle and the handle of the duplicated memtarget are different +/// and you cannot use it interchangeably. +/// You can use `umfMemspaceMemtargetGet()` to retrieve new handle. +/// +/// \param hMemspace handle to memspace +/// \param hMemtarget handle to memory target +/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +/// +umf_result_t umfMemspaceMemtargetAdd(umf_memspace_handle_t hMemspace, + umf_const_memtarget_handle_t hMemtarget); + +/// \brief Removes memory target from memspace. +/// +/// \param hMemspace handle to memspace +/// \param hMemtarget handle to memory target +/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +/// +umf_result_t +umfMemspaceMemtargetRemove(umf_memspace_handle_t hMemspace, + umf_const_memtarget_handle_t hMemtarget); + #ifdef __cplusplus } #endif diff --git a/src/libumf.def.in b/src/libumf.def.in index f69d7ac1a..8e2fe4b93 100644 --- a/src/libumf.def.in +++ b/src/libumf.def.in @@ -40,10 +40,13 @@ EXPORTS umfMempolicyDestroy umfMempolicySetCustomSplitPartitions umfMempolicySetInterleavePartSize + umfMemspaceNew umfMemspaceDestroy umfMemspaceMemtargetNum umfMemspaceMemtargetGet umfMemtargetGetCapacity + umfMemspaceMemtargetAdd + umfMemspaceMemtargetRemove umfMemtargetGetType umfOpenIPCHandle umfPoolAlignedMalloc diff --git a/src/libumf.map.in b/src/libumf.map.in index 09be6dfe9..c078b24c9 100644 --- a/src/libumf.map.in +++ b/src/libumf.map.in @@ -34,7 +34,11 @@ UMF_1.0 { umfMempolicyDestroy; umfMempolicySetCustomSplitPartitions; umfMempolicySetInterleavePartSize; + umfMemspaceNew; + umfMemspaceCreateFromNumaArray; umfMemspaceDestroy; + umfMemspaceMemtargetAdd; + umfMemspaceMemtargetRemove; umfMemspaceMemtargetNum; umfMemspaceMemtargetGet; umfMemtargetGetCapacity; diff --git a/src/memspace.c b/src/memspace.c index bce5fb6ee..f21ecbc4e 100644 --- a/src/memspace.c +++ b/src/memspace.c @@ -16,6 +16,7 @@ #include "memspace_internal.h" #include "memtarget_internal.h" #include "memtarget_ops.h" +#include "utils_log.h" #ifndef NDEBUG static umf_result_t @@ -60,6 +61,10 @@ umf_result_t umfPoolCreateFromMemspace(umf_const_memspace_handle_t memspace, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } + if (memspace->size == 0) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + void **privs = NULL; umf_result_t ret = memoryTargetHandlesToPriv(memspace, &privs); if (ret != UMF_RESULT_SUCCESS) { @@ -85,6 +90,10 @@ umfMemoryProviderCreateFromMemspace(umf_const_memspace_handle_t memspace, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } + if (memspace->size == 0) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + void **privs = NULL; umf_result_t ret = memoryTargetHandlesToPriv(memspace, &privs); if (ret != UMF_RESULT_SUCCESS) { @@ -102,6 +111,25 @@ umfMemoryProviderCreateFromMemspace(umf_const_memspace_handle_t memspace, return ret; } +umf_result_t umfMemspaceNew(umf_memspace_handle_t *hMemspace) { + if (!hMemspace) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + umf_memspace_handle_t memspace = + umf_ba_global_alloc(sizeof(struct umf_memspace_t)); + if (!memspace) { + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + memspace->size = 0; + memspace->nodes = NULL; + + *hMemspace = memspace; + + return UMF_RESULT_SUCCESS; +} + void umfMemspaceDestroy(umf_memspace_handle_t memspace) { assert(memspace); for (size_t i = 0; i < memspace->size; i++) { @@ -306,3 +334,95 @@ umfMemspaceMemtargetGet(umf_const_memspace_handle_t hMemspace, } return hMemspace->nodes[targetNum]; } + +umf_result_t umfMemspaceMemtargetAdd(umf_memspace_handle_t hMemspace, + umf_const_memtarget_handle_t hMemtarget) { + if (!hMemspace || !hMemtarget) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + for (size_t i = 0; i < hMemspace->size; i++) { + int cmp; + umf_result_t ret = + umfMemtargetCompare(hMemspace->nodes[i], hMemtarget, &cmp); + if (ret != UMF_RESULT_SUCCESS) { + return ret; + } + + if (cmp == 0) { + LOG_ERR("Memory target already exists in the memspace"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } else if (cmp < 0) { + LOG_ERR("You can't mix different memory target types in the same " + "memspace"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + } + + umf_memtarget_handle_t *newNodes = + umf_ba_global_alloc(sizeof(*newNodes) * (hMemspace->size + 1)); + if (!newNodes) { + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + for (size_t i = 0; i < hMemspace->size; i++) { + newNodes[i] = hMemspace->nodes[i]; + } + umf_memtarget_t *hMemtargetClone; + + umf_result_t ret = umfMemtargetClone(hMemtarget, &hMemtargetClone); + if (ret != UMF_RESULT_SUCCESS) { + umf_ba_global_free(newNodes); + return ret; + } + newNodes[hMemspace->size++] = hMemtargetClone; + + umf_ba_global_free(hMemspace->nodes); + hMemspace->nodes = newNodes; + return UMF_RESULT_SUCCESS; +} + +umf_result_t +umfMemspaceMemtargetRemove(umf_memspace_handle_t hMemspace, + umf_const_memtarget_handle_t hMemtarget) { + if (!hMemspace || !hMemtarget) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + unsigned i; + for (i = 0; i < hMemspace->size; i++) { + int cmp; + umf_result_t ret = + umfMemtargetCompare(hMemspace->nodes[i], hMemtarget, &cmp); + + if (ret != UMF_RESULT_SUCCESS) { + return ret; + } + + if (cmp == 0) { + break; + } + } + + if (i == hMemspace->size) { + LOG_ERR("Memory target not found in the memspace"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + umf_memtarget_handle_t *newNodes = + umf_ba_global_alloc(sizeof(*newNodes) * (hMemspace->size - 1)); + if (!newNodes) { + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + for (unsigned j = 0, z = 0; j < hMemspace->size; j++) { + if (j != i) { + newNodes[z++] = hMemspace->nodes[j]; + } + } + + umfMemtargetDestroy(hMemspace->nodes[i]); + umf_ba_global_free(hMemspace->nodes); + hMemspace->nodes = newNodes; + hMemspace->size--; + return UMF_RESULT_SUCCESS; +} diff --git a/src/memtarget.c b/src/memtarget.c index c85630769..a79ec2a6c 100644 --- a/src/memtarget.c +++ b/src/memtarget.c @@ -53,7 +53,7 @@ void umfMemtargetDestroy(umf_memtarget_handle_t memoryTarget) { umf_ba_global_free(memoryTarget); } -umf_result_t umfMemtargetClone(umf_memtarget_handle_t memoryTarget, +umf_result_t umfMemtargetClone(umf_const_memtarget_handle_t memoryTarget, umf_memtarget_handle_t *outHandle) { assert(memoryTarget); assert(outHandle); @@ -115,3 +115,33 @@ umf_result_t umfMemtargetGetType(umf_const_memtarget_handle_t memoryTarget, return memoryTarget->ops->get_type(memoryTarget->priv, type); } + +umf_result_t umfMemtargetCompare(umf_const_memtarget_handle_t a, + umf_const_memtarget_handle_t b, int *result) { + umf_memtarget_type_t typeA, typeB; + umf_result_t ret = umfMemtargetGetType(a, &typeA); + if (ret != UMF_RESULT_SUCCESS) { + return ret; + } + + ret = umfMemtargetGetType(b, &typeB); + if (ret != UMF_RESULT_SUCCESS) { + return ret; + } + + if (typeA != typeB) { + *result = -1; + return UMF_RESULT_SUCCESS; + } + + ret = a->ops->compare(a->priv, b->priv, result); + if (ret != UMF_RESULT_SUCCESS) { + return ret; + } + + if (*result) { + *result = 1; + } + + return UMF_RESULT_SUCCESS; +} diff --git a/src/memtarget_internal.h b/src/memtarget_internal.h index 2e1547e07..c5b9a61c5 100644 --- a/src/memtarget_internal.h +++ b/src/memtarget_internal.h @@ -28,7 +28,7 @@ umf_result_t umfMemtargetCreate(const umf_memtarget_ops_t *ops, void *params, umf_memtarget_handle_t *memoryTarget); void umfMemtargetDestroy(umf_memtarget_handle_t memoryTarget); -umf_result_t umfMemtargetClone(umf_memtarget_handle_t memoryTarget, +umf_result_t umfMemtargetClone(umf_const_memtarget_handle_t memoryTarget, umf_memtarget_handle_t *outHandle); umf_result_t umfMemtargetGetBandwidth(umf_memtarget_handle_t srcMemoryTarget, @@ -38,6 +38,10 @@ umf_result_t umfMemtargetGetLatency(umf_memtarget_handle_t srcMemoryTarget, umf_memtarget_handle_t dstMemoryTarget, size_t *latency); +/// return 0 if memtargets are equal, -1 if they are of different types, +/// and 1 if they are different targets of the same type +umf_result_t umfMemtargetCompare(umf_const_memtarget_handle_t a, + umf_const_memtarget_handle_t b, int *result); #ifdef __cplusplus } #endif diff --git a/src/memtarget_ops.h b/src/memtarget_ops.h index 08936fcde..43c66ce92 100644 --- a/src/memtarget_ops.h +++ b/src/memtarget_ops.h @@ -1,6 +1,6 @@ /* * - * Copyright (C) 2023 Intel Corporation + * 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 @@ -45,6 +45,8 @@ typedef struct umf_memtarget_ops_t { size_t *latency); umf_result_t (*get_type)(void *memoryTarget, umf_memtarget_type_t *type); + umf_result_t (*compare)(void *memTarget, void *otherMemTarget, int *result); + } umf_memtarget_ops_t; #ifdef __cplusplus diff --git a/src/memtargets/memtarget_numa.c b/src/memtargets/memtarget_numa.c index 32f9bf448..08be3f883 100644 --- a/src/memtargets/memtarget_numa.c +++ b/src/memtargets/memtarget_numa.c @@ -326,6 +326,20 @@ static umf_result_t numa_get_type(void *memTarget, umf_memtarget_type_t *type) { return UMF_RESULT_SUCCESS; } +static umf_result_t numa_compare(void *memTarget, void *otherMemTarget, + int *result) { + if (!memTarget || !otherMemTarget || !result) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + struct numa_memtarget_t *numaTarget = (struct numa_memtarget_t *)memTarget; + struct numa_memtarget_t *otherNumaTarget = + (struct numa_memtarget_t *)otherMemTarget; + + *result = numaTarget->physical_id != otherNumaTarget->physical_id; + return UMF_RESULT_SUCCESS; +} + struct umf_memtarget_ops_t UMF_MEMTARGET_NUMA_OPS = { .version = UMF_VERSION_CURRENT, .initialize = numa_initialize, @@ -336,5 +350,6 @@ struct umf_memtarget_ops_t UMF_MEMTARGET_NUMA_OPS = { .get_bandwidth = numa_get_bandwidth, .get_latency = numa_get_latency, .get_type = numa_get_type, + .compare = numa_compare, .memory_provider_create_from_memspace = numa_memory_provider_create_from_memspace}; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index be6d9ad7d..a72868c4f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -224,6 +224,10 @@ if(LINUX AND (NOT UMF_DISABLE_HWLOC)) # OS-specific functions are implemented NAME mempolicy SRCS memspaces/mempolicy.cpp LIBS ${LIBNUMA_LIBRARIES}) + add_umf_test( + NAME memspace + SRCS memspaces/memspace.cpp + LIBS ${LIBNUMA_LIBRARIES}) add_umf_test( NAME memtarget SRCS memspaces/memtarget.cpp diff --git a/test/common/numa_helpers.hpp b/test/common/numa_helpers.hpp index 7c0946de7..adcce9102 100644 --- a/test/common/numa_helpers.hpp +++ b/test/common/numa_helpers.hpp @@ -15,36 +15,191 @@ // returns the node where page starting at 'ptr' resides static inline void getNumaNodeByPtr(void *ptr, int *node) { - int nodeId; - int ret = - get_mempolicy(&nodeId, nullptr, 0, ptr, MPOL_F_ADDR | MPOL_F_NODE); + int ret = get_mempolicy(node, nullptr, 0, ptr, MPOL_F_ADDR | MPOL_F_NODE); ASSERT_EQ(ret, 0) << "get_mempolicy failed"; - ASSERT_GE(nodeId, 0) + ASSERT_GE(*node, 0) << "get_mempolicy returned nodeId < 0 - should never happen"; +} + +// returns the mode in which page starting at 'ptr' is bound +static inline void getBindModeByPtr(void *ptr, int *mode) { + int ret = get_mempolicy(mode, nullptr, 0, ptr, MPOL_F_ADDR); + + ASSERT_EQ(ret, 0) << "get_mempolicy failed"; +} + +// returns the mask in which page starting at 'ptr' is bound +static inline void getBindMaskByPtr(void *ptr, struct bitmask *mask) { + int ret = get_mempolicy(nullptr, mask->maskp, mask->size, ptr, MPOL_F_ADDR); - *node = nodeId; + ASSERT_EQ(ret, 0) << "get_mempolicy failed"; } -static inline void _assertNode(void *ptr, int nodeId, bool fatal) { - int node = -1; +// Internal do not use directly +#define _CUSTOMIZABLE_ASSERT(expr, fatal, eq) \ + do { \ + if (fatal) { \ + if (eq) { \ + ASSERT_TRUE(expr); \ + } else { \ + ASSERT_FALSE(expr); \ + } \ + } else { \ + if (eq) { \ + EXPECT_TRUE(expr); \ + } else { \ + EXPECT_FALSE(expr); \ + } \ + } \ + } while (0) + +// Internal do not use directly +static inline void _assertNode(void *ptr, int expected_node, bool fatal, + bool eq) { + int node; getNumaNodeByPtr(ptr, &node); if (testing::Test::HasFatalFailure()) { return; } - if (fatal) { - ASSERT_EQ(nodeId, node); - } else { - EXPECT_EQ(nodeId, node); + + _CUSTOMIZABLE_ASSERT(node == expected_node, fatal, eq); +} + +// Internal do not use directly +static inline void _assertNode(void *ptr, void *ptr2, bool fatal, bool eq) { + int node, node2; + + getNumaNodeByPtr(ptr, &node); + getNumaNodeByPtr(ptr2, &node2); + if (testing::Test::HasFatalFailure()) { + return; + } + + _CUSTOMIZABLE_ASSERT(node == node2, fatal, eq); +} + +// Internal do not use directly +static inline void _assertBindMode(void *ptr, int expected_mode, bool fatal, + bool eq) { + int mode; + + getBindModeByPtr(ptr, &mode); + if (testing::Test::HasFatalFailure()) { + return; + } + + _CUSTOMIZABLE_ASSERT(mode == expected_mode, fatal, eq); +} + +static inline void _assertBindMode(void *ptr, void *ptr2, bool fatal, bool eq) { + int mode, mode2; + + getBindModeByPtr(ptr, &mode); + getBindModeByPtr(ptr2, &mode2); + if (testing::Test::HasFatalFailure()) { + return; + } + + _CUSTOMIZABLE_ASSERT(mode == mode2, fatal, eq); +} + +// Internal do not use directly +static inline void _assertBindMask(void *ptr, struct bitmask *expected_mask, + bool fatal, bool eq) { + struct bitmask *mask = numa_allocate_nodemask(); + ASSERT_NE(mask, nullptr) << "numa_allocate_nodemask failed"; + + getBindMaskByPtr(ptr, mask); + if (testing::Test::HasFatalFailure()) { + return; } + + _CUSTOMIZABLE_ASSERT(numa_bitmask_equal(mask, expected_mask), fatal, eq); + + numa_free_nodemask(mask); } -//Asserts that given nodeId is equal to the node where given ptr resides -#define ASSERT_NODE_EQ(ptr, nodeId) \ - ASSERT_NO_FATAL_FAILURE(_assertNode(ptr, nodeId, true)) +// Internal do not use directly +static inline void _assertBindMask(void *ptr, void *ptr2, bool fatal, bool eq) { + struct bitmask *mask = numa_allocate_nodemask(); + ASSERT_NE(mask, nullptr) << "numa_allocate_nodemask failed"; + + getBindMaskByPtr(ptr, mask); + + struct bitmask *mask2 = numa_allocate_nodemask(); + ASSERT_NE(mask2, nullptr) << "numa_allocate_nodemask failed"; + + getBindMaskByPtr(ptr2, mask2); + + if (testing::Test::HasFatalFailure()) { + return; + } + + _CUSTOMIZABLE_ASSERT(numa_bitmask_equal(mask, mask2), fatal, eq); + + numa_free_nodemask(mask); + numa_free_nodemask(mask2); +} + +// Asserts that a memory page starting at 'ptr' is on the expected NUMA node, +// The target can be either a specific node or another pointer, in which case we compare nodes of both ptr. +#define ASSERT_NODE_EQ(ptr, target) \ + ASSERT_NO_FATAL_FAILURE(_assertNode(ptr, target, true, true)) + +// Asserts that a memory page starting at 'ptr' is not on the expected NUMA node, +// The target can be either a specific node or another pointer, in which case we compare nodes of both ptr. +#define ASSERT_NODE_NE(ptr, target) \ + ASSERT_NO_FATAL_FAILURE(_assertNode(ptr, target, true, false)) + +// Expects that a memory page starting at 'ptr' is on the expected NUMA node, +// Target can be either a node id or another pointer, in which case we compare nodes of both ptr. +#define EXPECT_NODE_EQ(ptr, target) \ + ASSERT_NO_FATAL_FAILURE(_assertNode(ptr, target, false, true)) + +// Expects that a memory page starting at 'ptr' is not on the expected NUMA node, +// Target can be either a node id or another pointer, in which case we compare nodes of both ptr. +#define EXPECT_NODE_NE(ptr, target) \ + ASSERT_NO_FATAL_FAILURE(_assertNode(ptr, target, false, false)) + +// Asserts that a memory page starting at 'ptr' is bound in the expected memory binding mode. +// The target can be either a specific mode or another pointer, in which case we compare the modes of both ptr. +#define ASSERT_BIND_MODE_EQ(ptr, target) \ + ASSERT_NO_FATAL_FAILURE(_assertBindMode(ptr, target, true, true)) +// Asserts that a memory page starting at 'ptr' is not bound in the expected memory binding mode. +// The target can be either a specific mode or another pointer, in which case we compare the modes of both ptr. +#define ASSERT_BIND_MODE_NE(ptr, target) \ + ASSERT_NO_FATAL_FAILURE(_assertBindMode(ptr, target, true, false)) + +// Expects that a memory page starting at 'ptr' is bound in the expected memory binding mode. +// The target can be either a specific mode or another pointer, in which case we compare the modes of both ptr. +#define EXPECT_BIND_MODE_EQ(ptr, target) \ + ASSERT_NO_FATAL_FAILURE(_assertBindMode(ptr, target, false, true)) + +// Expects that a memory page starting at 'ptr' is not bound in the expected memory binding mode. +// The target can be either a specific mode or another pointer, in which case we compare the modes of both ptr. +#define EXPECT_BIND_MODE_NE(ptr, target) \ + ASSERT_NO_FATAL_FAILURE(_assertBindMode(ptr, target, false, false)) + +// Asserts that the memory binding mask for the page starting at 'ptr' matches the expected mask. +// The target can be either a bitmask or another pointer, in which case we compare the masks of both ptr. +#define ASSERT_BIND_MASK_EQ(ptr, target) \ + ASSERT_NO_FATAL_FAILURE(_assertBindMask(ptr, target, true, true)) + +// Asserts that the memory binding mask for the page starting at 'ptr' does not match the expected mask. +// The target can be either a bitmask or another pointer, in which case we compare the masks of both ptr. +#define ASSERT_BIND_MASK_NE(ptr, target) \ + ASSERT_NO_FATAL_FAILURE(_assertBindMask(ptr, target, true, false)) + +// Expects that the memory binding mask for the page starting at 'ptr' matches the expected mask. +// The target can be either a bitmask or another pointer, in which case we compare the masks of both ptr. +#define EXPECT_BIND_MASK_EQ(ptr, target) \ + ASSERT_NO_FATAL_FAILURE(_assertBindMask(ptr, target, false, true)) -#define EXPECT_NODE_EQ(ptr, nodeId) \ - ASSERT_NO_FATAL_FAILURE(_assertNode(ptr, nodeId, false)) +// Expects that the memory binding mask for the page starting at 'ptr' does not match the expected mask. +// The target can be either a bitmask or another pointer, in which case we compare the masks of both ptr. +#define EXPECT_BIND_MASK_NE(ptr, target) \ + ASSERT_NO_FATAL_FAILURE(_assertBindMask(ptr, target, false, false)) #endif /* UMF_TEST_NUMA_HELPERS_HPP */ diff --git a/test/memspaces/memspace.cpp b/test/memspaces/memspace.cpp new file mode 100644 index 000000000..412c5beb7 --- /dev/null +++ b/test/memspaces/memspace.cpp @@ -0,0 +1,43 @@ +// Copyright (C) 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 "memspace_helpers.hpp" + +using umf_test::test; + +TEST_F(test, memspaceNewInvalid) { + auto ret = umfMemspaceNew(NULL); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} + +class emptyMemspace : public testing::Test { + public: + umf_memspace_handle_t memspace; + + void SetUp() override { + auto ret = umfMemspaceNew(&memspace); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(memspace, nullptr); + } + void TearDown() override { umfMemspaceDestroy(memspace); } +}; + +TEST_F(emptyMemspace, basic) { + size_t len = umfMemspaceMemtargetNum(memspace); + ASSERT_EQ(len, 0); +} + +TEST_F(emptyMemspace, create_pool) { + umf_memory_pool_handle_t pool = nullptr; + auto ret = umfPoolCreateFromMemspace(memspace, NULL, &pool); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + ASSERT_EQ(pool, nullptr); +} + +TEST_F(emptyMemspace, create_provider) { + umf_memory_provider_handle_t provider = nullptr; + auto ret = umfMemoryProviderCreateFromMemspace(memspace, NULL, &provider); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + ASSERT_EQ(provider, nullptr); +} diff --git a/test/memspaces/memspace_host_all.cpp b/test/memspaces/memspace_host_all.cpp index 6e61c6bdc..846bd5fe0 100644 --- a/test/memspaces/memspace_host_all.cpp +++ b/test/memspaces/memspace_host_all.cpp @@ -121,35 +121,72 @@ TEST_F(memspaceHostAllProviderTest, hostAllDefaults) { ASSERT_NE(ptr2, nullptr); memset(ptr2, 0xFF, size); - // Compare UMF and kernel default allocation policy - struct bitmask *nodemask1 = numa_allocate_nodemask(); - struct bitmask *nodemask2 = numa_allocate_nodemask(); - int memMode1 = -1, memMode2 = -1; - - int ret2 = get_mempolicy(&memMode1, nodemask1->maskp, nodemask1->size, ptr1, - MPOL_F_ADDR); - ASSERT_EQ(ret2, 0); - ret2 = get_mempolicy(&memMode2, nodemask2->maskp, nodemask2->size, ptr2, - MPOL_F_ADDR); - ASSERT_EQ(ret2, 0); - ASSERT_EQ(memMode1, memMode2); - ASSERT_EQ(nodemask1->size, nodemask2->size); - ASSERT_EQ(numa_bitmask_equal(nodemask1, nodemask2), 1); - - int nodeId1 = -1, nodeId2 = -1; - ret2 = get_mempolicy(&nodeId1, nullptr, 0, ptr1, MPOL_F_ADDR | MPOL_F_NODE); - ASSERT_EQ(ret2, 0); - ret2 = get_mempolicy(&nodeId2, nullptr, 0, ptr2, MPOL_F_ADDR | MPOL_F_NODE); - ASSERT_EQ(ret2, 0); - ASSERT_EQ(nodeId1, nodeId2); - - numa_free_nodemask(nodemask2); - numa_free_nodemask(nodemask1); - - ret2 = munmap(ptr2, size); - ASSERT_EQ(ret2, 0); + EXPECT_NODE_EQ(ptr1, ptr2); + EXPECT_BIND_MODE_EQ(ptr1, ptr2); + EXPECT_BIND_MASK_EQ(ptr1, ptr2); + + auto ret2 = munmap(ptr2, size); + UT_ASSERTeq(ret2, 0); ret = umfMemoryProviderFree(hProvider, ptr1, size); ASSERT_EQ(ret, UMF_RESULT_SUCCESS); umfMemoryProviderDestroy(hProvider); } + +TEST_F(memspaceHostAllProviderTest, HostAllVsCopy) { + umf_memspace_handle_t hMemspaceCopy = nullptr; + auto ret = umfMemspaceNew(&hMemspaceCopy); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(hMemspaceCopy, nullptr); + + for (size_t i = 0; i < umfMemspaceMemtargetNum(hMemspace); ++i) { + auto target = umfMemspaceMemtargetGet(hMemspace, i); + ASSERT_NE(target, nullptr); + + ret = umfMemspaceMemtargetAdd(hMemspaceCopy, target); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + } + + ASSERT_EQ(umfMemspaceMemtargetNum(hMemspace), + umfMemspaceMemtargetNum(hMemspaceCopy)); + + umf_memory_provider_handle_t hProvider1, hProvider2; + ret = umfMemoryProviderCreateFromMemspace(hMemspace, nullptr, &hProvider1); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(hProvider1, nullptr); + + ret = umfMemoryProviderCreateFromMemspace(hMemspaceCopy, nullptr, + &hProvider2); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(hProvider2, nullptr); + + void *ptr1, *ptr2; + ret = umfMemoryProviderAlloc(hProvider1, SIZE_4K, 0, &ptr1); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(ptr1, nullptr); + + ret = umfMemoryProviderAlloc(hProvider2, SIZE_4K, 0, &ptr2); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + memset(ptr1, 0xFF, SIZE_4K); + memset(ptr2, 0xFF, SIZE_4K); + + ASSERT_NODE_EQ(ptr1, ptr2); + // HostAll memspace bind memory in the unique way (MPOL_DEFAULT), + // but this works only for this specific memspaces, but not for it's copies. + ASSERT_BIND_MASK_NE(ptr1, ptr2); + ASSERT_BIND_MODE_NE(ptr1, ptr2); + + ASSERT_BIND_MODE_EQ(ptr1, MPOL_DEFAULT); + ASSERT_BIND_MODE_EQ(ptr2, MPOL_BIND); + + ret = umfMemoryProviderFree(hProvider1, ptr1, SIZE_4K); + UT_ASSERTeq(ret, UMF_RESULT_SUCCESS); + + ret = umfMemoryProviderFree(hProvider2, ptr2, SIZE_4K); + UT_ASSERTeq(ret, UMF_RESULT_SUCCESS); + + umfMemoryProviderDestroy(hProvider1); + umfMemoryProviderDestroy(hProvider2); + umfMemspaceDestroy(hMemspaceCopy); +} diff --git a/test/memspaces/memspace_numa.cpp b/test/memspaces/memspace_numa.cpp index 180efd9c2..0065f710f 100644 --- a/test/memspaces/memspace_numa.cpp +++ b/test/memspaces/memspace_numa.cpp @@ -6,6 +6,7 @@ #include "memspace_fixtures.hpp" #include "memspace_helpers.hpp" #include "memspace_internal.h" +#include "numa_helpers.hpp" #include #include @@ -104,20 +105,120 @@ TEST_F(memspaceNumaTest, providerFromNumaMemspace) { umfMemoryProviderDestroy(hProvider); } -TEST_F(numaNodesTest, memtargetsInvalid) { - umf_memspace_handle_t hMemspace = nullptr; +TEST_F(memspaceNumaTest, memtargetsInvalid) { EXPECT_EQ(umfMemspaceMemtargetNum(nullptr), 0); EXPECT_EQ(umfMemspaceMemtargetGet(nullptr, 0), nullptr); - umf_result_t ret = umfMemspaceCreateFromNumaArray( - nodeIds.data(), nodeIds.size(), &hMemspace); - ASSERT_EQ(ret, UMF_RESULT_SUCCESS); - ASSERT_NE(hMemspace, nullptr); - ASSERT_EQ(umfMemspaceMemtargetNum(hMemspace), nodeIds.size()); EXPECT_EQ(umfMemspaceMemtargetGet(hMemspace, nodeIds.size()), nullptr); +} - umfMemspaceDestroy(hMemspace); +TEST_F(memspaceNumaTest, memspaceCopyTarget) { + umf_memspace_handle_t hMemspaceCopy = nullptr; + auto ret = umfMemspaceNew(&hMemspaceCopy); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(hMemspaceCopy, nullptr); + + for (size_t i = 0; i < umfMemspaceMemtargetNum(hMemspace); ++i) { + auto target = umfMemspaceMemtargetGet(hMemspace, i); + ASSERT_NE(target, nullptr); + + ret = umfMemspaceMemtargetAdd(hMemspaceCopy, target); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + } + + ASSERT_EQ(umfMemspaceMemtargetNum(hMemspace), + umfMemspaceMemtargetNum(hMemspaceCopy)); + + umf_memory_provider_handle_t hProvider1, hProvider2; + ret = umfMemoryProviderCreateFromMemspace(hMemspace, nullptr, &hProvider1); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(hProvider1, nullptr); + + ret = umfMemoryProviderCreateFromMemspace(hMemspaceCopy, nullptr, + &hProvider2); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(hProvider2, nullptr); + + void *ptr1, *ptr2; + ret = umfMemoryProviderAlloc(hProvider1, SIZE_4K, 0, &ptr1); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(ptr1, nullptr); + + ret = umfMemoryProviderAlloc(hProvider2, SIZE_4K, 0, &ptr2); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + ASSERT_BIND_MASK_EQ(ptr1, ptr2); + ASSERT_BIND_MODE_EQ(ptr1, ptr2); + + ret = umfMemoryProviderFree(hProvider1, ptr1, SIZE_4K); + UT_ASSERTeq(ret, UMF_RESULT_SUCCESS); + + ret = umfMemoryProviderFree(hProvider2, ptr2, SIZE_4K); + UT_ASSERTeq(ret, UMF_RESULT_SUCCESS); + + umfMemoryProviderDestroy(hProvider1); + umfMemoryProviderDestroy(hProvider2); + umfMemspaceDestroy(hMemspaceCopy); +} + +TEST_F(memspaceNumaTest, memspaceDeleteTarget) { + if (numa_max_node() < 2) { + GTEST_SKIP() << "Not enough NUMA nodes to run test"; + } + + umf_memspace_handle_t hMemspaceCopy = nullptr; + auto ret = umfMemspaceNew(&hMemspaceCopy); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(hMemspaceCopy, nullptr); + + auto target = umfMemspaceMemtargetGet(hMemspace, 0); + ASSERT_NE(target, nullptr); + + ret = umfMemspaceMemtargetAdd(hMemspaceCopy, target); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + while (umfMemspaceMemtargetNum(hMemspace) > 1) { + auto target = umfMemspaceMemtargetGet(hMemspace, 1); + ASSERT_NE(target, nullptr); + + ret = umfMemspaceMemtargetRemove(hMemspace, target); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + } + + ASSERT_EQ(umfMemspaceMemtargetNum(hMemspace), + umfMemspaceMemtargetNum(hMemspaceCopy)); + + umf_memory_provider_handle_t hProvider1, hProvider2; + ret = umfMemoryProviderCreateFromMemspace(hMemspace, nullptr, &hProvider1); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(hProvider1, nullptr); + + ret = umfMemoryProviderCreateFromMemspace(hMemspaceCopy, nullptr, + &hProvider2); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(hProvider2, nullptr); + + void *ptr1, *ptr2; + ret = umfMemoryProviderAlloc(hProvider1, SIZE_4K, 0, &ptr1); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(ptr1, nullptr); + + ret = umfMemoryProviderAlloc(hProvider2, SIZE_4K, 0, &ptr2); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + ASSERT_BIND_MASK_EQ(ptr1, ptr2); + ASSERT_BIND_MODE_EQ(ptr1, ptr2); + + ret = umfMemoryProviderFree(hProvider1, ptr1, SIZE_4K); + UT_ASSERTeq(ret, UMF_RESULT_SUCCESS); + + ret = umfMemoryProviderFree(hProvider2, ptr2, SIZE_4K); + UT_ASSERTeq(ret, UMF_RESULT_SUCCESS); + + umfMemoryProviderDestroy(hProvider1); + umfMemoryProviderDestroy(hProvider2); + umfMemspaceDestroy(hMemspaceCopy); } TEST_F(memspaceNumaProviderTest, allocFree) { From a55e42e43fa804284537379802093d646c2ae85d Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 16 Sep 2024 19:11:44 +0200 Subject: [PATCH 095/352] Add file memory provider Signed-off-by: Lukasz Dorau --- CMakeLists.txt | 1 + README.md | 15 + include/umf/providers/provider_file_memory.h | 57 ++ scripts/docs_config/api.rst | 8 + src/CMakeLists.txt | 1 + src/provider/provider_file_memory.c | 644 +++++++++++++++++++ src/provider/provider_file_memory_internal.h | 50 ++ src/provider/provider_os_memory_internal.h | 6 + src/provider/provider_os_memory_linux.c | 9 +- src/provider/provider_os_memory_macosx.c | 8 + src/provider/provider_os_memory_posix.c | 33 + src/provider/provider_os_memory_windows.c | 22 + src/utils/utils_common.h | 2 + test/CMakeLists.txt | 4 + test/provider_devdax_memory.cpp | 3 - test/provider_file_memory.cpp | 341 ++++++++++ test/provider_os_memory.cpp | 4 +- 17 files changed, 1201 insertions(+), 7 deletions(-) create mode 100644 include/umf/providers/provider_file_memory.h create mode 100644 src/provider/provider_file_memory.c create mode 100644 src/provider/provider_file_memory_internal.h create mode 100644 test/provider_file_memory.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ceb75368..e54d1146e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -421,6 +421,7 @@ if(NOT UMF_DISABLE_HWLOC) add_optional_symbol(umfOsMemoryProviderOps) if(LINUX) add_optional_symbol(umfDevDaxMemoryProviderOps) + add_optional_symbol(umfFileMemoryProviderOps) endif() endif() diff --git a/README.md b/README.md index 64894ecf2..0c80bee12 100644 --- a/README.md +++ b/README.md @@ -188,6 +188,21 @@ with the `disable_provider_free` parameter set to true. 1) Linux OS 2) A character device file /dev/daxX.Y created in the OS. +#### File memory provider (Linux only yet) + +A memory provider that provides memory by mapping a regular, extendable file. + +The file memory provider does not support the free operation +(`umfMemoryProviderFree()` always returns `UMF_RESULT_ERROR_NOT_SUPPORTED`), +so it should be used with a pool manager that will take over +the managing of the provided memory - for example the jemalloc pool +with the `disable_provider_free` parameter set to true. + +##### Requirements + +1) Linux OS +2) A length of a path of a file to be mapped can be `PATH_MAX` (4096) characters at most. + ### Memory pool managers #### Proxy pool (part of libumf) diff --git a/include/umf/providers/provider_file_memory.h b/include/umf/providers/provider_file_memory.h new file mode 100644 index 000000000..4b5b59b81 --- /dev/null +++ b/include/umf/providers/provider_file_memory.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 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_FILE_MEMORY_PROVIDER_H +#define UMF_FILE_MEMORY_PROVIDER_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/// @cond +#define UMF_FILE_RESULTS_START_FROM 3000 +/// @endcond + +/// @brief Memory provider settings struct +typedef struct umf_file_memory_provider_params_t { + /// a path to the file (of maximum length PATH_MAX characters) + const char *path; + /// combination of 'umf_mem_protection_flags_t' flags + unsigned protection; + /// memory visibility mode + umf_memory_visibility_t visibility; +} umf_file_memory_provider_params_t; + +/// @brief File Memory Provider operation results +typedef enum umf_file_memory_provider_native_error { + UMF_FILE_RESULT_SUCCESS = UMF_FILE_RESULTS_START_FROM, ///< Success + UMF_FILE_RESULT_ERROR_ALLOC_FAILED, ///< Memory allocation failed + UMF_FILE_RESULT_ERROR_FREE_FAILED, ///< Memory deallocation failed + UMF_FILE_RESULT_ERROR_PURGE_FORCE_FAILED, ///< Force purging failed +} umf_file_memory_provider_native_error_t; + +umf_memory_provider_ops_t *umfFileMemoryProviderOps(void); + +/// @brief Create default params for the file memory provider +static inline umf_file_memory_provider_params_t +umfFileMemoryProviderParamsDefault(const char *path) { + umf_file_memory_provider_params_t params = { + path, /* a path to the file */ + UMF_PROTECTION_READ | UMF_PROTECTION_WRITE, /* protection */ + UMF_MEM_MAP_PRIVATE, /* visibility mode */ + }; + + return params; +} + +#ifdef __cplusplus +} +#endif + +#endif /* UMF_FILE_MEMORY_PROVIDER_H */ diff --git a/scripts/docs_config/api.rst b/scripts/docs_config/api.rst index 5e39361e1..625116dd2 100644 --- a/scripts/docs_config/api.rst +++ b/scripts/docs_config/api.rst @@ -104,6 +104,14 @@ A memory provider that provides memory from a device DAX (a character device fil .. doxygenfile:: provider_devdax_memory.h :sections: define enum typedef func var +File Memory Provider +------------------------------------------ + +A memory provider that provides memory by mapping a regular, extendable file. + +.. doxygenfile:: provider_file_memory.h + :sections: define enum typedef func var + Memspace ========================================== diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 00aeb8a47..845a178e3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -102,6 +102,7 @@ set(UMF_SOURCES_WINDOWS libumf_windows.c) set(UMF_SOURCES_COMMON_LINUX_MACOSX provider/provider_devdax_memory.c + provider/provider_file_memory.c provider/provider_os_memory.c provider/provider_os_memory_posix.c memtargets/memtarget_numa.c diff --git a/src/provider/provider_file_memory.c b/src/provider/provider_file_memory.c new file mode 100644 index 000000000..fd8d04371 --- /dev/null +++ b/src/provider/provider_file_memory.c @@ -0,0 +1,644 @@ +/* + * Copyright (C) 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 "critnib.h" +#include "provider_file_memory_internal.h" +#include "provider_os_memory_internal.h" +#include "utils_common.h" +#include "utils_concurrency.h" +#include "utils_log.h" + +#include +#include +#include + +#define TLS_MSG_BUF_LEN 1024 + +typedef struct file_last_native_error_t { + int32_t native_error; + int errno_value; + char msg_buff[TLS_MSG_BUF_LEN]; +} file_last_native_error_t; + +static __TLS file_last_native_error_t TLS_last_native_error; + +// helper values used only in the Native_error_str array +#define _UMF_FILE_RESULT_SUCCESS \ + (UMF_FILE_RESULT_SUCCESS - UMF_FILE_RESULT_SUCCESS) +#define _UMF_FILE_RESULT_ERROR_ALLOC_FAILED \ + (UMF_FILE_RESULT_ERROR_ALLOC_FAILED - UMF_FILE_RESULT_SUCCESS) +#define _UMF_FILE_RESULT_ERROR_FREE_FAILED \ + (UMF_FILE_RESULT_ERROR_FREE_FAILED - UMF_FILE_RESULT_SUCCESS) +#define _UMF_FILE_RESULT_ERROR_PURGE_FORCE_FAILED \ + (UMF_FILE_RESULT_ERROR_PURGE_FORCE_FAILED - UMF_FILE_RESULT_SUCCESS) + +static const char *Native_error_str[] = { + [_UMF_FILE_RESULT_SUCCESS] = "success", + [_UMF_FILE_RESULT_ERROR_ALLOC_FAILED] = "memory allocation failed", + [_UMF_FILE_RESULT_ERROR_FREE_FAILED] = "memory deallocation failed", + [_UMF_FILE_RESULT_ERROR_PURGE_FORCE_FAILED] = "force purging failed", +}; + +static void file_store_last_native_error(int32_t native_error, + int errno_value) { + TLS_last_native_error.native_error = native_error; + TLS_last_native_error.errno_value = errno_value; +} + +static umf_result_t +file_translate_params(umf_file_memory_provider_params_t *in_params, + file_memory_provider_t *provider) { + umf_result_t result; + + result = os_translate_mem_protection_flags(in_params->protection, + &provider->protection); + if (result != UMF_RESULT_SUCCESS) { + LOG_ERR("incorrect memory protection flags: %u", in_params->protection); + return result; + } + + result = os_translate_mem_visibility_flag(in_params->visibility, + &provider->visibility); + if (result != UMF_RESULT_SUCCESS) { + LOG_ERR("incorrect memory visibility flag: %u", in_params->visibility); + return result; + } + + return UMF_RESULT_SUCCESS; +} + +static umf_result_t file_initialize(void *params, void **provider) { + umf_result_t ret; + + if (provider == NULL || params == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + umf_file_memory_provider_params_t *in_params = + (umf_file_memory_provider_params_t *)params; + + size_t page_size = os_get_page_size(); + + if (in_params->path == NULL) { + LOG_ERR("file path is missing"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + file_memory_provider_t *file_provider = + umf_ba_global_alloc(sizeof(*file_provider)); + if (!file_provider) { + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + memset(file_provider, 0, sizeof(*file_provider)); + + file_provider->page_size = page_size; + + ret = file_translate_params(in_params, file_provider); + if (ret != UMF_RESULT_SUCCESS) { + goto err_free_file_provider; + } + + if (util_copy_path(in_params->path, file_provider->path, PATH_MAX)) { + goto err_free_file_provider; + } + + file_provider->fd = os_file_open_or_create(in_params->path); + if (file_provider->fd == -1) { + LOG_ERR("cannot open the file: %s", in_params->path); + ret = UMF_RESULT_ERROR_INVALID_ARGUMENT; + goto err_free_file_provider; + } + + if (os_set_file_size(file_provider->fd, page_size)) { + LOG_ERR("cannot set size of the file: %s", in_params->path); + ret = UMF_RESULT_ERROR_UNKNOWN; + goto err_close_fd; + } + + file_provider->size_fd = page_size; + + LOG_DEBUG("size of the file %s is: %zu", in_params->path, + file_provider->size_fd); + + if (util_mutex_init(&file_provider->lock) == NULL) { + LOG_ERR("lock init failed"); + ret = UMF_RESULT_ERROR_UNKNOWN; + goto err_close_fd; + } + + file_provider->fd_offset_map = critnib_new(); + if (!file_provider->fd_offset_map) { + LOG_ERR("creating the map of file descriptor offsets failed"); + ret = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + goto err_mutex_destroy_not_free; + } + + file_provider->mmaps = critnib_new(); + if (!file_provider->mmaps) { + LOG_ERR("creating the map of memory mappings failed"); + ret = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + goto err_delete_fd_offset_map; + } + + *provider = file_provider; + + return UMF_RESULT_SUCCESS; + +err_delete_fd_offset_map: + critnib_delete(file_provider->fd_offset_map); +err_mutex_destroy_not_free: + util_mutex_destroy_not_free(&file_provider->lock); +err_close_fd: + utils_close_fd(file_provider->fd); +err_free_file_provider: + umf_ba_global_free(file_provider); + return ret; +} + +static void file_finalize(void *provider) { + if (provider == NULL) { + assert(0); + return; + } + + file_memory_provider_t *file_provider = provider; + + uintptr_t key = 0; + uintptr_t rkey = 0; + void *rvalue = NULL; + while (1 == + critnib_find(file_provider->mmaps, key, FIND_G, &rkey, &rvalue)) { + os_munmap((void *)rkey, (size_t)rvalue); + critnib_remove(file_provider->mmaps, rkey); + key = rkey; + } + + util_mutex_destroy_not_free(&file_provider->lock); + utils_close_fd(file_provider->fd); + critnib_delete(file_provider->fd_offset_map); + critnib_delete(file_provider->mmaps); + umf_ba_global_free(file_provider); +} + +static umf_result_t file_mmap_aligned(file_memory_provider_t *file_provider, + size_t size, size_t alignment) { + int prot = file_provider->protection; + int flag = file_provider->visibility; + int fd = file_provider->fd; + size_t size_fd = file_provider->size_fd; + size_t offset_fd = file_provider->offset_fd; + size_t page_size = file_provider->page_size; + + assert(fd > 0); + + // We have to increase size by alignment to be able to "cut out" + // the correctly aligned part of the memory + size_t extended_size = size + alignment; + if (extended_size < size) { + LOG_ERR("invalid size of allocation"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; // arithmetic overflow + } + + size_t rest = extended_size & (page_size - 1); + if (rest) { + extended_size += page_size - rest; + } + if (extended_size < size) { + LOG_ERR("invalid size of allocation"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; // arithmetic overflow + } + + if (offset_fd + extended_size > size_fd) { + if (os_fallocate(fd, offset_fd, extended_size)) { + LOG_ERR("cannot grow the file size from %zu to %zu", size_fd, + offset_fd + extended_size); + return UMF_RESULT_ERROR_UNKNOWN; + } + + LOG_DEBUG("file size grown from %zu to %zu", size_fd, + offset_fd + extended_size); + file_provider->size_fd = size_fd = offset_fd + extended_size; + } + + ASSERT_IS_ALIGNED(extended_size, page_size); + ASSERT_IS_ALIGNED(offset_fd, page_size); + + void *ptr = os_mmap(NULL, extended_size, prot, flag, fd, offset_fd); + if (ptr == NULL) { + LOG_PERR("memory mapping failed"); + return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; + } + + int ret = critnib_insert(file_provider->mmaps, (uintptr_t)ptr, + (void *)(uintptr_t)extended_size, 0 /* update */); + if (ret) { + LOG_ERR("inserting a value to the map of memory mapping failed " + "(addr=%p, size=%zu)", + ptr, extended_size); + } + + file_provider->base_mmap = ptr; + file_provider->size_mmap = extended_size; + file_provider->offset_mmap = 0; + + return UMF_RESULT_SUCCESS; +} + +static umf_result_t file_alloc_aligned(file_memory_provider_t *file_provider, + size_t size, size_t alignment, + void **out_addr, + size_t *alloc_offset_fd) { + assert(alloc_offset_fd); + assert(out_addr); + + umf_result_t umf_result; + + if (util_mutex_lock(&file_provider->lock)) { + LOG_ERR("locking file data failed"); + return UMF_RESULT_ERROR_UNKNOWN; + } + + if (file_provider->size_mmap - file_provider->offset_mmap < size) { + umf_result = file_mmap_aligned(file_provider, size, alignment); + if (umf_result != UMF_RESULT_SUCCESS) { + util_mutex_unlock(&file_provider->lock); + return umf_result; + } + } + + void *base_mmap = file_provider->base_mmap; + assert(base_mmap); + + uintptr_t new_aligned_ptr = + (uintptr_t)base_mmap + file_provider->offset_mmap; + if (alignment) { + uintptr_t rest = new_aligned_ptr & (alignment - 1); + if (rest) { + new_aligned_ptr += alignment - rest; + } + ASSERT_IS_ALIGNED(new_aligned_ptr, alignment); + } + + size_t new_offset_mmap = new_aligned_ptr - (uintptr_t)base_mmap; + if (file_provider->size_mmap - new_offset_mmap < size) { + umf_result = file_mmap_aligned(file_provider, size, alignment); + if (umf_result != UMF_RESULT_SUCCESS) { + util_mutex_unlock(&file_provider->lock); + return umf_result; + } + } + + size_t old_offset_mmap = file_provider->offset_mmap; + file_provider->offset_mmap = new_offset_mmap; + *alloc_offset_fd = + file_provider->offset_fd + new_offset_mmap - old_offset_mmap; + file_provider->offset_fd = *alloc_offset_fd + size; + + *out_addr = (void *)new_aligned_ptr; + + util_mutex_unlock(&file_provider->lock); + + return UMF_RESULT_SUCCESS; +} + +static umf_result_t file_alloc(void *provider, size_t size, size_t alignment, + void **resultPtr) { + umf_result_t umf_result; + int ret; + + if (provider == NULL || resultPtr == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + // alignment must be a power of two and a multiple of sizeof(void *) + if (alignment && + ((alignment & (alignment - 1)) || (alignment % sizeof(void *)))) { + LOG_ERR("wrong alignment: %zu (not a power of 2 or a multiple of " + "sizeof(void *))", + alignment); + return UMF_RESULT_ERROR_INVALID_ALIGNMENT; + } + + file_memory_provider_t *file_provider = (file_memory_provider_t *)provider; + + void *addr = NULL; + size_t alloc_offset_fd; // needed for critnib_insert() + umf_result = file_alloc_aligned(file_provider, size, alignment, &addr, + &alloc_offset_fd); + if (umf_result != UMF_RESULT_SUCCESS) { + file_store_last_native_error(UMF_FILE_RESULT_ERROR_ALLOC_FAILED, 0); + LOG_ERR("memory allocation failed"); + return umf_result; + } + + // store (offset_fd + 1) to be able to store offset_fd == 0 + ret = critnib_insert(file_provider->fd_offset_map, (uintptr_t)addr, + (void *)(uintptr_t)(alloc_offset_fd + 1), + 0 /* update */); + if (ret) { + LOG_ERR("inserting a value to the file descriptor offset map failed " + "(addr=%p, offset=%zu)", + addr, alloc_offset_fd); + } + + *resultPtr = addr; + + return UMF_RESULT_SUCCESS; +} + +// free() is not supported +static umf_result_t file_free(void *provider, void *ptr, size_t size) { + (void)provider; // unused + (void)ptr; // unused + (void)size; // unused + + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + +static void file_get_last_native_error(void *provider, const char **ppMessage, + int32_t *pError) { + (void)provider; // unused + + if (ppMessage == NULL || pError == NULL) { + assert(0); + return; + } + + *pError = TLS_last_native_error.native_error; + if (TLS_last_native_error.errno_value == 0) { + *ppMessage = Native_error_str[*pError - UMF_FILE_RESULT_SUCCESS]; + return; + } + + const char *msg; + size_t len; + size_t pos = 0; + + msg = Native_error_str[*pError - UMF_FILE_RESULT_SUCCESS]; + len = strlen(msg); + memcpy(TLS_last_native_error.msg_buff + pos, msg, len + 1); + pos += len; + + msg = ": "; + len = strlen(msg); + memcpy(TLS_last_native_error.msg_buff + pos, msg, len + 1); + pos += len; + + os_strerror(TLS_last_native_error.errno_value, + TLS_last_native_error.msg_buff + pos, TLS_MSG_BUF_LEN - pos); + + *ppMessage = TLS_last_native_error.msg_buff; +} + +static umf_result_t file_get_recommended_page_size(void *provider, size_t size, + size_t *page_size) { + (void)size; // unused + + if (provider == NULL || page_size == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + *page_size = os_get_page_size(); + + return UMF_RESULT_SUCCESS; +} + +static umf_result_t file_get_min_page_size(void *provider, void *ptr, + size_t *page_size) { + (void)ptr; // unused + + return file_get_recommended_page_size(provider, 0, page_size); +} + +static umf_result_t file_purge_lazy(void *provider, void *ptr, size_t size) { + (void)provider; // unused + (void)ptr; // unused + (void)size; // unused + // purge_lazy is unsupported in case of the file memory provider, + // because the MADV_FREE operation can be applied + // only to private anonymous pages (see madvise(2)). + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + +static umf_result_t file_purge_force(void *provider, void *ptr, size_t size) { + if (provider == NULL || ptr == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + errno = 0; + if (os_purge(ptr, size, UMF_PURGE_FORCE)) { + file_store_last_native_error(UMF_FILE_RESULT_ERROR_PURGE_FORCE_FAILED, + errno); + LOG_PERR("force purging failed"); + return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; + } + return UMF_RESULT_SUCCESS; +} + +static const char *file_get_name(void *provider) { + (void)provider; // unused + return "FILE"; +} + +// This function is supposed to be thread-safe, so it should NOT be called concurrently +// with file_allocation_merge() with the same pointer. +static umf_result_t file_allocation_split(void *provider, void *ptr, + size_t totalSize, size_t firstSize) { + (void)totalSize; + + file_memory_provider_t *file_provider = (file_memory_provider_t *)provider; + if (file_provider->fd <= 0) { + return UMF_RESULT_SUCCESS; + } + + void *value = critnib_get(file_provider->fd_offset_map, (uintptr_t)ptr); + if (value == NULL) { + LOG_ERR("file_allocation_split(): getting a value from the file " + "descriptor offset map failed (addr=%p)", + ptr); + return UMF_RESULT_ERROR_UNKNOWN; + } + + uintptr_t new_key = (uintptr_t)ptr + firstSize; + void *new_value = (void *)((uintptr_t)value + firstSize); + int ret = critnib_insert(file_provider->fd_offset_map, new_key, new_value, + 0 /* update */); + if (ret) { + LOG_ERR("file_allocation_split(): inserting a value to the file " + "descriptor offset map failed (addr=%p, offset=%zu)", + (void *)new_key, (size_t)new_value - 1); + return UMF_RESULT_ERROR_UNKNOWN; + } + + return UMF_RESULT_SUCCESS; +} + +// It should NOT be called concurrently with file_allocation_split() with the same pointer. +static umf_result_t file_allocation_merge(void *provider, void *lowPtr, + void *highPtr, size_t totalSize) { + (void)lowPtr; + (void)totalSize; + + file_memory_provider_t *file_provider = (file_memory_provider_t *)provider; + if (file_provider->fd <= 0) { + return UMF_RESULT_SUCCESS; + } + + void *value = + critnib_remove(file_provider->fd_offset_map, (uintptr_t)highPtr); + if (value == NULL) { + LOG_ERR("file_allocation_merge(): removing a value from the file " + "descriptor offset map failed (addr=%p)", + highPtr); + return UMF_RESULT_ERROR_UNKNOWN; + } + + return UMF_RESULT_SUCCESS; +} + +typedef struct file_ipc_data_t { + char path[PATH_MAX]; + size_t offset_fd; + size_t size; +} file_ipc_data_t; + +static umf_result_t file_get_ipc_handle_size(void *provider, size_t *size) { + if (provider == NULL || size == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + *size = sizeof(file_ipc_data_t); + + return UMF_RESULT_SUCCESS; +} + +static umf_result_t file_get_ipc_handle(void *provider, const void *ptr, + size_t size, void *providerIpcData) { + if (provider == NULL || ptr == NULL || providerIpcData == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + file_memory_provider_t *file_provider = (file_memory_provider_t *)provider; + + void *value = critnib_get(file_provider->fd_offset_map, (uintptr_t)ptr); + if (value == NULL) { + LOG_ERR("file_get_ipc_handle(): getting a value from the IPC cache " + "failed (addr=%p)", + ptr); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + file_ipc_data_t *file_ipc_data = (file_ipc_data_t *)providerIpcData; + file_ipc_data->offset_fd = (size_t)value - 1; + file_ipc_data->size = size; + strncpy(file_ipc_data->path, file_provider->path, PATH_MAX - 1); + file_ipc_data->path[PATH_MAX - 1] = '\0'; + + return UMF_RESULT_SUCCESS; +} + +static umf_result_t file_put_ipc_handle(void *provider, void *providerIpcData) { + if (provider == NULL || providerIpcData == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + file_memory_provider_t *file_provider = (file_memory_provider_t *)provider; + file_ipc_data_t *file_ipc_data = (file_ipc_data_t *)providerIpcData; + + if (strncmp(file_ipc_data->path, file_provider->path, PATH_MAX)) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + return UMF_RESULT_SUCCESS; +} + +static umf_result_t file_open_ipc_handle(void *provider, void *providerIpcData, + void **ptr) { + if (provider == NULL || providerIpcData == NULL || ptr == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + file_memory_provider_t *file_provider = (file_memory_provider_t *)provider; + file_ipc_data_t *file_ipc_data = (file_ipc_data_t *)providerIpcData; + umf_result_t ret = UMF_RESULT_SUCCESS; + int fd; + + if (strncmp(file_ipc_data->path, file_provider->path, PATH_MAX)) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + fd = os_file_open(file_ipc_data->path); + if (fd <= 0) { + LOG_PERR("opening the file to be mapped (%s) failed", + file_ipc_data->path); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + *ptr = os_mmap(NULL, file_ipc_data->size, file_provider->protection, + file_provider->visibility, fd, file_ipc_data->offset_fd); + (void)utils_close_fd(fd); + if (*ptr == NULL) { + file_store_last_native_error(UMF_FILE_RESULT_ERROR_ALLOC_FAILED, errno); + LOG_PERR("memory mapping failed"); + ret = UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; + } + + return ret; +} + +static umf_result_t file_close_ipc_handle(void *provider, void *ptr, + size_t size) { + if (provider == NULL || ptr == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + errno = 0; + int ret = os_munmap(ptr, size); + // ignore error when size == 0 + if (ret && (size > 0)) { + file_store_last_native_error(UMF_FILE_RESULT_ERROR_FREE_FAILED, errno); + LOG_PERR("memory unmapping failed"); + + return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; + } + + return UMF_RESULT_SUCCESS; +} + +static umf_memory_provider_ops_t UMF_FILE_MEMORY_PROVIDER_OPS = { + .version = UMF_VERSION_CURRENT, + .initialize = file_initialize, + .finalize = file_finalize, + .alloc = file_alloc, + .free = file_free, + .get_last_native_error = file_get_last_native_error, + .get_recommended_page_size = file_get_recommended_page_size, + .get_min_page_size = file_get_min_page_size, + .get_name = file_get_name, + .ext.purge_lazy = file_purge_lazy, + .ext.purge_force = file_purge_force, + .ext.allocation_merge = file_allocation_merge, + .ext.allocation_split = file_allocation_split, + .ipc.get_ipc_handle_size = file_get_ipc_handle_size, + .ipc.get_ipc_handle = file_get_ipc_handle, + .ipc.put_ipc_handle = file_put_ipc_handle, + .ipc.open_ipc_handle = file_open_ipc_handle, + .ipc.close_ipc_handle = file_close_ipc_handle}; + +umf_memory_provider_ops_t *umfFileMemoryProviderOps(void) { + return &UMF_FILE_MEMORY_PROVIDER_OPS; +} diff --git a/src/provider/provider_file_memory_internal.h b/src/provider/provider_file_memory_internal.h new file mode 100644 index 000000000..ce77719d5 --- /dev/null +++ b/src/provider/provider_file_memory_internal.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 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_FILE_MEMORY_PROVIDER_INTERNAL_H +#define UMF_FILE_MEMORY_PROVIDER_INTERNAL_H + +#include + +#include "critnib.h" +#include "utils_concurrency.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct file_memory_provider_t { + os_mutex_t lock; // lock for file parameters (size and offsets) + + char path[PATH_MAX]; // a path to the file + int fd; // file descriptor for memory mapping + size_t size_fd; // size of the file used for memory mappings + size_t offset_fd; // offset in the file used for memory mappings + + void *base_mmap; // base address of the current memory mapping + size_t size_mmap; // size of the current memory mapping + size_t offset_mmap; // data offset in the current memory mapping + + unsigned protection; // combination of OS-specific protection flags + unsigned visibility; // memory visibility mode + size_t page_size; // minimum page size + + critnib *mmaps; // a critnib map storing mmap mappings (addr, size) + + // A critnib map storing (ptr, fd_offset + 1) pairs. We add 1 to fd_offset + // in order to be able to store fd_offset equal 0, because + // critnib_get() returns value or NULL, so a value cannot equal 0. + // It is needed mainly in the get_ipc_handle and open_ipc_handle hooks + // to mmap a specific part of a file. + critnib *fd_offset_map; +} file_memory_provider_t; + +#ifdef __cplusplus +} +#endif + +#endif /* UMF_FILE_MEMORY_PROVIDER_INTERNAL_H */ diff --git a/src/provider/provider_os_memory_internal.h b/src/provider/provider_os_memory_internal.h index e3bf4002c..54972686d 100644 --- a/src/provider/provider_os_memory_internal.h +++ b/src/provider/provider_os_memory_internal.h @@ -109,6 +109,12 @@ void os_strerror(int errnum, char *buf, size_t buflen); int os_devdax_open(const char *path); +int os_file_open(const char *path); + +int os_file_open_or_create(const char *path); + +int os_fallocate(int fd, long offset, long len); + #ifdef __cplusplus } #endif diff --git a/src/provider/provider_os_memory_linux.c b/src/provider/provider_os_memory_linux.c index a472dd4b7..9a90e1145 100644 --- a/src/provider/provider_os_memory_linux.c +++ b/src/provider/provider_os_memory_linux.c @@ -150,8 +150,11 @@ int os_set_file_size(int fd, size_t size) { errno = 0; int ret = ftruncate(fd, size); if (ret) { - LOG_PERR("ftruncate(%i, %zu) failed", fd, size); + LOG_PERR("setting size %zu of a file failed", size); + } else { + LOG_DEBUG("set size of a file to %zu bytes", size); } + return ret; } @@ -178,3 +181,7 @@ void *os_devdax_mmap(void *hint_addr, size_t length, int prot, int fd) { return NULL; } + +int os_fallocate(int fd, long offset, long len) { + return posix_fallocate(fd, offset, len); +} diff --git a/src/provider/provider_os_memory_macosx.c b/src/provider/provider_os_memory_macosx.c index 87bae1b0e..33835beac 100644 --- a/src/provider/provider_os_memory_macosx.c +++ b/src/provider/provider_os_memory_macosx.c @@ -67,3 +67,11 @@ void *os_devdax_mmap(void *hint_addr, size_t length, int prot, int fd) { (void)fd; // unused return NULL; // not supported on Windows } + +int os_fallocate(int fd, long offset, long len) { + (void)fd; // unused + (void)offset; // unused + (void)len; // unused + + return -1; +} diff --git a/src/provider/provider_os_memory_posix.c b/src/provider/provider_os_memory_posix.c index 63f38cca3..90348ebfa 100644 --- a/src/provider/provider_os_memory_posix.c +++ b/src/provider/provider_os_memory_posix.c @@ -145,3 +145,36 @@ int os_devdax_open(const char *path) { return fd; } + +// open a file +int os_file_open(const char *path) { + if (!path) { + LOG_ERR("empty path"); + return -1; + } + + int fd = open(path, O_RDWR); + if (fd == -1) { + LOG_PERR("cannot open the file: %s", path); + } + + return fd; +} + +// open a file or create +int os_file_open_or_create(const char *path) { + if (!path) { + LOG_ERR("empty path"); + return -1; + } + + int fd = open(path, O_RDWR | O_CREAT, 0600); + if (fd == -1) { + LOG_PERR("cannot open/create the file: %s", path); + return -1; + } + + LOG_DEBUG("opened/created the file: %s", path); + + return fd; +} diff --git a/src/provider/provider_os_memory_windows.c b/src/provider/provider_os_memory_windows.c index f9232fb66..b295c75f1 100644 --- a/src/provider/provider_os_memory_windows.c +++ b/src/provider/provider_os_memory_windows.c @@ -166,3 +166,25 @@ int os_devdax_open(const char *path) { return -1; } + +// open a file +int os_file_open(const char *path) { + (void)path; // unused + + return -1; +} + +// open a file or create +int os_file_open_or_create(const char *path) { + (void)path; // unused + + return -1; +} + +int os_fallocate(int fd, long offset, long len) { + (void)fd; // unused + (void)offset; // unused + (void)len; // unused + + return -1; +} diff --git a/src/utils/utils_common.h b/src/utils/utils_common.h index 5a6fb87c0..20206b1e4 100644 --- a/src/utils/utils_common.h +++ b/src/utils/utils_common.h @@ -31,6 +31,8 @@ extern "C" { #define ALIGN_UP(value, align) (((value) + (align)-1) & ~((align)-1)) #define ALIGN_DOWN(value, align) ((value) & ~((align)-1)) +#define ASSERT_IS_ALIGNED(value, align) \ + DO_WHILE_EXPRS(assert(((value) & ((align)-1)) == 0)) #define VALGRIND_ANNOTATE_NEW_MEMORY(p, s) DO_WHILE_EMPTY #define VALGRIND_HG_DRD_DISABLE_CHECKING(p, s) DO_WHILE_EMPTY diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index be6d9ad7d..ff07931f1 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -232,6 +232,10 @@ if(LINUX AND (NOT UMF_DISABLE_HWLOC)) # OS-specific functions are implemented NAME provider_devdax_memory SRCS provider_devdax_memory.cpp LIBS ${UMF_UTILS_FOR_TEST}) + add_umf_test( + NAME provider_file_memory + SRCS provider_file_memory.cpp + LIBS ${UMF_UTILS_FOR_TEST}) if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND UMF_BUILD_FUZZTESTS) add_subdirectory(fuzz) endif() diff --git a/test/provider_devdax_memory.cpp b/test/provider_devdax_memory.cpp index 8b0f0360f..1fdd53b08 100644 --- a/test/provider_devdax_memory.cpp +++ b/test/provider_devdax_memory.cpp @@ -19,9 +19,6 @@ using umf_test::test; #define INVALID_PTR ((void *)0x01) -#define ASSERT_IS_ALIGNED(ptr, alignment) \ - ASSERT_EQ(((uintptr_t)ptr % alignment), 0) - typedef enum purge_t { PURGE_NONE = 0, PURGE_LAZY = 1, diff --git a/test/provider_file_memory.cpp b/test/provider_file_memory.cpp new file mode 100644 index 000000000..3903febe7 --- /dev/null +++ b/test/provider_file_memory.cpp @@ -0,0 +1,341 @@ +// Copyright (C) 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 "base.hpp" + +#include "cpp_helpers.hpp" +#include "test_helpers.h" + +#include +#include + +using umf_test::test; + +#define FILE_PATH ((char *)"tmp_file") +#define INVALID_PTR ((void *)0x01) + +typedef enum purge_t { + PURGE_NONE = 0, + PURGE_LAZY = 1, + PURGE_FORCE = 2, +} purge_t; + +static const char *Native_error_str[] = { + "success", // UMF_FILE_RESULT_SUCCESS + "memory allocation failed", // UMF_FILE_RESULT_ERROR_ALLOC_FAILED + "memory deallocation failed", // UMF_FILE_RESULT_ERROR_FREE_FAILED + "force purging failed", // UMF_FILE_RESULT_ERROR_PURGE_FORCE_FAILED +}; + +// test helpers + +static int compare_native_error_str(const char *message, int error) { + const char *error_str = Native_error_str[error - UMF_FILE_RESULT_SUCCESS]; + size_t len = strlen(error_str); + return strncmp(message, error_str, len); +} + +using providerCreateExtParams = std::tuple; + +static void providerCreateExt(providerCreateExtParams params, + umf::provider_unique_handle_t *handle) { + umf_memory_provider_handle_t hProvider = nullptr; + auto [provider_ops, provider_params] = params; + + auto ret = + umfMemoryProviderCreate(provider_ops, provider_params, &hProvider); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(hProvider, nullptr); + + *handle = + umf::provider_unique_handle_t(hProvider, &umfMemoryProviderDestroy); +} + +struct umfProviderTest + : umf_test::test, + ::testing::WithParamInterface { + void SetUp() override { + test::SetUp(); + providerCreateExt(this->GetParam(), &provider); + umf_result_t umf_result = + umfMemoryProviderGetMinPageSize(provider.get(), NULL, &page_size); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + page_plus_64 = page_size + 64; + } + + void TearDown() override { test::TearDown(); } + + umf::provider_unique_handle_t provider; + size_t page_size; + size_t page_plus_64; +}; + +static void test_alloc_free_success(umf_memory_provider_handle_t provider, + size_t size, size_t alignment, + purge_t purge) { + void *ptr = nullptr; + + umf_result_t umf_result = + umfMemoryProviderAlloc(provider, size, alignment, &ptr); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(ptr, nullptr); + + memset(ptr, 0xFF, size); + + if (purge == PURGE_LAZY) { + umf_result = umfMemoryProviderPurgeLazy(provider, ptr, size); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); + } else if (purge == PURGE_FORCE) { + umf_result = umfMemoryProviderPurgeForce(provider, ptr, size); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + } + + umf_result = umfMemoryProviderFree(provider, ptr, size); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); +} + +static void verify_last_native_error(umf_memory_provider_handle_t provider, + int32_t err) { + const char *message; + int32_t error; + umfMemoryProviderGetLastNativeError(provider, &message, &error); + ASSERT_EQ(error, err); + ASSERT_EQ(compare_native_error_str(message, error), 0); +} + +static void test_alloc_failure(umf_memory_provider_handle_t provider, + size_t size, size_t alignment, + umf_result_t result, int32_t err) { + void *ptr = nullptr; + umf_result_t umf_result = + umfMemoryProviderAlloc(provider, size, alignment, &ptr); + ASSERT_EQ(umf_result, result); + ASSERT_EQ(ptr, nullptr); + + if (umf_result == UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC) { + verify_last_native_error(provider, err); + } +} + +// TESTS + +// positive tests using test_alloc_free_success + +umf_file_memory_provider_params_t get_file_params_shared(char *path) { + umf_file_memory_provider_params_t file_params = + umfFileMemoryProviderParamsDefault(path); + file_params.visibility = UMF_MEM_MAP_SHARED; + return file_params; +} + +umf_file_memory_provider_params_t file_params_shared = + get_file_params_shared(FILE_PATH); + +INSTANTIATE_TEST_SUITE_P(fileProviderTest, umfProviderTest, + ::testing::Values(providerCreateExtParams{ + umfFileMemoryProviderOps(), &file_params_shared})); + +TEST_P(umfProviderTest, create_destroy) {} + +TEST_P(umfProviderTest, alloc_page64_align_0) { + test_alloc_free_success(provider.get(), page_plus_64, 0, PURGE_NONE); +} + +TEST_P(umfProviderTest, alloc_page64_align_page_div_2) { + test_alloc_free_success(provider.get(), page_plus_64, page_size / 2, + PURGE_NONE); +} + +TEST_P(umfProviderTest, purge_lazy) { + test_alloc_free_success(provider.get(), page_plus_64, 0, PURGE_LAZY); +} + +TEST_P(umfProviderTest, purge_force) { + test_alloc_free_success(provider.get(), page_plus_64, 0, PURGE_FORCE); +} + +// negative tests using test_alloc_failure + +TEST_P(umfProviderTest, alloc_WRONG_SIZE) { + test_alloc_failure(provider.get(), -1, 0, UMF_RESULT_ERROR_INVALID_ARGUMENT, + 0); +} + +TEST_P(umfProviderTest, alloc_page64_WRONG_ALIGNMENT_3_pages) { + test_alloc_failure(provider.get(), page_plus_64, 3 * page_size, + UMF_RESULT_ERROR_INVALID_ALIGNMENT, 0); +} + +TEST_P(umfProviderTest, alloc_3pages_WRONG_ALIGNMENT_3pages) { + test_alloc_failure(provider.get(), 3 * page_size, 3 * page_size, + UMF_RESULT_ERROR_INVALID_ALIGNMENT, 0); +} + +TEST_P(umfProviderTest, alloc_page64_align_page_minus_1_WRONG_ALIGNMENT_1) { + test_alloc_failure(provider.get(), page_plus_64, page_size - 1, + UMF_RESULT_ERROR_INVALID_ALIGNMENT, 0); +} + +TEST_P(umfProviderTest, alloc_page64_align_one_half_pages_WRONG_ALIGNMENT_2) { + test_alloc_failure(provider.get(), page_plus_64, + page_size + (page_size / 2), + UMF_RESULT_ERROR_INVALID_ALIGNMENT, 0); +} + +// other positive tests + +TEST_P(umfProviderTest, get_min_page_size) { + size_t min_page_size; + umf_result_t umf_result = umfMemoryProviderGetMinPageSize( + provider.get(), nullptr, &min_page_size); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_LE(min_page_size, page_size); +} + +TEST_P(umfProviderTest, get_recommended_page_size) { + size_t min_page_size; + umf_result_t umf_result = umfMemoryProviderGetMinPageSize( + provider.get(), nullptr, &min_page_size); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_LE(min_page_size, page_size); + + size_t recommended_page_size; + umf_result = umfMemoryProviderGetRecommendedPageSize( + provider.get(), 0, &recommended_page_size); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_GE(recommended_page_size, min_page_size); +} + +TEST_P(umfProviderTest, get_name) { + const char *name = umfMemoryProviderGetName(provider.get()); + ASSERT_STREQ(name, "FILE"); +} + +TEST_P(umfProviderTest, free_size_0_ptr_not_null) { + umf_result_t umf_result = + umfMemoryProviderFree(provider.get(), INVALID_PTR, 0); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); +} + +TEST_P(umfProviderTest, free_NULL) { + umf_result_t umf_result = umfMemoryProviderFree(provider.get(), nullptr, 0); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); +} + +// other negative tests + +TEST_F(test, create_empty_path) { + umf_memory_provider_handle_t hProvider = nullptr; + const char *path = ""; + auto wrong_params = umfFileMemoryProviderParamsDefault((char *)path); + auto ret = umfMemoryProviderCreate(umfFileMemoryProviderOps(), + &wrong_params, &hProvider); + EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + EXPECT_EQ(hProvider, nullptr); +} + +TEST_P(umfProviderTest, free_INVALID_POINTER_SIZE_GT_0) { + umf_result_t umf_result = + umfMemoryProviderFree(provider.get(), INVALID_PTR, page_plus_64); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); +} + +TEST_P(umfProviderTest, purge_lazy_INVALID_POINTER) { + umf_result_t umf_result = + umfMemoryProviderPurgeLazy(provider.get(), INVALID_PTR, 1); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); +} + +TEST_P(umfProviderTest, purge_force_INVALID_POINTER) { + umf_result_t umf_result = + umfMemoryProviderPurgeForce(provider.get(), INVALID_PTR, 1); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC); + + verify_last_native_error(provider.get(), + UMF_FILE_RESULT_ERROR_PURGE_FORCE_FAILED); +} + +// IPC tests + +TEST_P(umfProviderTest, IPC_base_success_test) { + umf_result_t umf_result; + void *ptr = nullptr; + size_t size = page_size; + void *ipc_handle = nullptr; + size_t ipc_handle_size; + void *new_ptr = nullptr; + + umf_result = + umfMemoryProviderGetIPCHandleSize(provider.get(), &ipc_handle_size); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(ipc_handle_size, 0); + + umf_result = umfMemoryProviderAlloc(provider.get(), size, page_size, &ptr); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(ptr, nullptr); + memset(ptr, 0xFF, size); + + umf_result = + umfMemoryProviderAlloc(provider.get(), ipc_handle_size, 0, &ipc_handle); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(ipc_handle, nullptr); + memset(ipc_handle, 0x0, ipc_handle_size); + + umf_result = + umfMemoryProviderGetIPCHandle(provider.get(), ptr, size, ipc_handle); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_result = + umfMemoryProviderOpenIPCHandle(provider.get(), ipc_handle, &new_ptr); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(new_ptr, nullptr); + + // it requires mapping with UMF_MEM_MAP_SHARED to work + int ret = memcmp(ptr, new_ptr, size); + ASSERT_EQ(ret, 0); + + umf_result = umfMemoryProviderFree(provider.get(), ptr, size); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); +} + +TEST_P(umfProviderTest, IPC_file_not_exist) { + umf_result_t umf_result; + void *ptr = nullptr; + size_t size = page_size; + void *ipc_handle = nullptr; + size_t ipc_handle_size; + void *new_ptr = nullptr; + + umf_result = + umfMemoryProviderGetIPCHandleSize(provider.get(), &ipc_handle_size); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(ipc_handle_size, 0); + + umf_result = umfMemoryProviderAlloc(provider.get(), size, page_size, &ptr); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(ptr, nullptr); + memset(ptr, 0xFF, size); + + umf_result = + umfMemoryProviderAlloc(provider.get(), ipc_handle_size, 0, &ipc_handle); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(ipc_handle, nullptr); + memset(ipc_handle, 0x0, ipc_handle_size); + + umf_result = + umfMemoryProviderGetIPCHandle(provider.get(), ptr, size, ipc_handle); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + int ret = unlink(FILE_PATH); + ASSERT_EQ(ret, 0); + + umf_result = + umfMemoryProviderOpenIPCHandle(provider.get(), ipc_handle, &new_ptr); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); + ASSERT_EQ(new_ptr, nullptr); + + umf_result = umfMemoryProviderFree(provider.get(), ptr, size); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); +} diff --git a/test/provider_os_memory.cpp b/test/provider_os_memory.cpp index 29fae1441..fca494af8 100644 --- a/test/provider_os_memory.cpp +++ b/test/provider_os_memory.cpp @@ -6,6 +6,7 @@ #include "cpp_helpers.hpp" #include "ipcFixtures.hpp" +#include "test_helpers.h" #include #include @@ -15,9 +16,6 @@ using umf_test::test; #define INVALID_PTR ((void *)0x01) -#define ASSERT_IS_ALIGNED(ptr, alignment) \ - ASSERT_EQ(((uintptr_t)ptr % alignment), 0) - typedef enum purge_t { PURGE_NONE = 0, PURGE_LAZY = 1, From 4603b7e82dfebec99b48a1d9f48728abaeb25237 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 16 Sep 2024 19:12:25 +0200 Subject: [PATCH 096/352] Add IPC test for file memory provider Signed-off-by: Lukasz Dorau --- test/CMakeLists.txt | 17 +++++++++++++++++ test/ipc_file_prov.sh | 32 ++++++++++++++++++++++++++++++++ test/ipc_file_prov_consumer.c | 32 ++++++++++++++++++++++++++++++++ test/ipc_file_prov_producer.c | 32 ++++++++++++++++++++++++++++++++ test/test_valgrind.sh | 4 ++++ 5 files changed, 117 insertions(+) create mode 100755 test/ipc_file_prov.sh create mode 100644 test/ipc_file_prov_consumer.c create mode 100644 test/ipc_file_prov_producer.c diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ff07931f1..24092d1fc 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -370,7 +370,24 @@ if(LINUX) common/ipc_common.c common/ipc_os_prov_common.c) add_umf_ipc_test(TEST ipc_devdax_prov) + + build_umf_test( + NAME + ipc_file_prov_consumer + SRCS + ipc_file_prov_consumer.c + common/ipc_common.c + common/ipc_os_prov_common.c) + build_umf_test( + NAME + ipc_file_prov_producer + SRCS + ipc_file_prov_producer.c + common/ipc_common.c + common/ipc_os_prov_common.c) + add_umf_ipc_test(TEST ipc_file_prov) endif() + if(UMF_BUILD_GPU_TESTS AND UMF_BUILD_LEVEL_ZERO_PROVIDER) build_umf_test( NAME diff --git a/test/ipc_file_prov.sh b/test/ipc_file_prov.sh new file mode 100755 index 000000000..6807f4009 --- /dev/null +++ b/test/ipc_file_prov.sh @@ -0,0 +1,32 @@ +# +# Copyright (C) 2024 Intel Corporation +# +# Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +#!/bin/bash + +set -e + +FILE_NAME="/tmp/umf_file_provider_$$" + +# port should be a number from the range <1024, 65535> +PORT=$(( 1024 + ( $$ % ( 65535 - 1024 )))) + +UMF_LOG_VAL="level:debug;flush:debug;output:stderr;pid:yes" + +# make sure the temp file does not exist +rm -f ${FILE_NAME} + +echo "Starting ipc_file_prov CONSUMER on port $PORT ..." +UMF_LOG=$UMF_LOG_VAL ./umf_test-ipc_file_prov_consumer $PORT $FILE_NAME & + +echo "Waiting 1 sec ..." +sleep 1 + +echo "Starting ipc_file_prov PRODUCER on port $PORT ..." +UMF_LOG=$UMF_LOG_VAL ./umf_test-ipc_file_prov_producer $PORT $FILE_NAME + +# remove the SHM file +rm -f ${FILE_NAME} diff --git a/test/ipc_file_prov_consumer.c b/test/ipc_file_prov_consumer.c new file mode 100644 index 000000000..834fe1054 --- /dev/null +++ b/test/ipc_file_prov_consumer.c @@ -0,0 +1,32 @@ +/* + * Copyright (C) 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 "ipc_common.h" +#include "ipc_os_prov_common.h" + +int main(int argc, char *argv[]) { + if (argc < 3) { + fprintf(stderr, "usage: %s \n", argv[0]); + return -1; + } + + int port = atoi(argv[1]); + char *file_name = argv[2]; + + umf_file_memory_provider_params_t file_params; + + file_params = umfFileMemoryProviderParamsDefault(file_name); + file_params.visibility = UMF_MEM_MAP_SHARED; + + return run_consumer(port, umfFileMemoryProviderOps(), &file_params, memcopy, + NULL); +} diff --git a/test/ipc_file_prov_producer.c b/test/ipc_file_prov_producer.c new file mode 100644 index 000000000..783cff31d --- /dev/null +++ b/test/ipc_file_prov_producer.c @@ -0,0 +1,32 @@ +/* + * Copyright (C) 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 "ipc_common.h" +#include "ipc_os_prov_common.h" + +int main(int argc, char *argv[]) { + if (argc < 3) { + fprintf(stderr, "usage: %s \n", argv[0]); + return -1; + } + + int port = atoi(argv[1]); + char *file_name = argv[2]; + + umf_file_memory_provider_params_t file_params; + + file_params = umfFileMemoryProviderParamsDefault(file_name); + file_params.visibility = UMF_MEM_MAP_SHARED; + + return run_producer(port, umfFileMemoryProviderOps(), &file_params, memcopy, + NULL); +} diff --git a/test/test_valgrind.sh b/test/test_valgrind.sh index 4c8a5633a..bfe4275af 100755 --- a/test/test_valgrind.sh +++ b/test/test_valgrind.sh @@ -92,6 +92,10 @@ for test in $(ls -1 umf_test-*); do echo "- SKIPPED" continue; # skip testing helper binaries used by the ipc_devdax_prov_* tests ;; + umf_test-ipc_file_prov_*) + echo "- SKIPPED" + continue; # skip testing helper binaries used by the ipc_file_prov test + ;; umf_test-memspace_host_all) FILTER='--gtest_filter="-*allocsSpreadAcrossAllNumaNodes"' ;; From 0252728ba4ab8262913a36dac3b4d15fb14dbbf9 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Thu, 12 Sep 2024 00:49:41 +0200 Subject: [PATCH 097/352] Add more IPC tests --- test/ipcAPI.cpp | 7 +++- test/ipcFixtures.hpp | 91 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 89 insertions(+), 9 deletions(-) diff --git a/test/ipcAPI.cpp b/test/ipcAPI.cpp index 524c26d4b..8f8448b62 100644 --- a/test/ipcAPI.cpp +++ b/test/ipcAPI.cpp @@ -25,8 +25,8 @@ struct provider_mock_ipc : public umf_test::provider_base_t { }; umf_test::provider_malloc helper_prov; - allocations_mutex_type alloc_mutex; - allocations_map_type allocations; + static allocations_mutex_type alloc_mutex; + static allocations_map_type allocations; umf_result_t alloc(size_t size, size_t align, void **ptr) noexcept { auto ret = helper_prov.alloc(size, align, ptr); @@ -105,6 +105,9 @@ struct provider_mock_ipc : public umf_test::provider_base_t { } }; +provider_mock_ipc::allocations_mutex_type provider_mock_ipc::alloc_mutex; +provider_mock_ipc::allocations_map_type provider_mock_ipc::allocations; + static umf_memory_provider_ops_t IPC_MOCK_PROVIDER_OPS = umf::providerMakeCOps(); diff --git a/test/ipcFixtures.hpp b/test/ipcFixtures.hpp index ce16e8f79..4c9ebd549 100644 --- a/test/ipcFixtures.hpp +++ b/test/ipcFixtures.hpp @@ -53,7 +53,16 @@ using ipcTestParams = struct umfIpcTest : umf_test::test, ::testing::WithParamInterface { umfIpcTest() {} - void SetUp() override { test::SetUp(); } + void SetUp() override { + test::SetUp(); + auto [pool_ops, pool_params, provider_ops, provider_params, accessor] = + this->GetParam(); + poolOps = pool_ops; + poolParams = pool_params; + providerOps = provider_ops; + providerParams = provider_params; + memAccessor = accessor; + } void TearDown() override { test::TearDown(); } @@ -62,11 +71,9 @@ struct umfIpcTest : umf_test::test, // from memoryPool.hpp umf_memory_provider_handle_t hProvider; umf_memory_pool_handle_t hPool; - auto [pool_ops, pool_params, provider_ops, provider_params, accessor] = - this->GetParam(); auto ret = - umfMemoryProviderCreate(provider_ops, provider_params, &hProvider); + umfMemoryProviderCreate(providerOps, providerParams, &hProvider); EXPECT_EQ(ret, UMF_RESULT_SUCCESS); auto trace = [](void *trace_context, const char *name) { @@ -87,12 +94,10 @@ struct umfIpcTest : umf_test::test, umf_memory_provider_handle_t hTraceProvider = traceProviderCreate(hProvider, true, (void *)&stat, trace); - ret = umfPoolCreate(pool_ops, hTraceProvider, pool_params, + ret = umfPoolCreate(poolOps, hTraceProvider, poolParams, UMF_POOL_CREATE_FLAG_OWN_PROVIDER, &hPool); EXPECT_EQ(ret, UMF_RESULT_SUCCESS); - memAccessor = accessor; - return umf::pool_unique_handle_t(hPool, &umfPoolDestroy); } @@ -111,6 +116,10 @@ struct umfIpcTest : umf_test::test, static constexpr int NTHREADS = 10; stats_type stat; MemoryAccessor *memAccessor = nullptr; + umf_memory_pool_ops_t *poolOps = nullptr; + void *poolParams = nullptr; + umf_memory_provider_ops_t *providerOps = nullptr; + void *providerParams = nullptr; }; TEST_P(umfIpcTest, GetIPCHandleSize) { @@ -122,6 +131,16 @@ TEST_P(umfIpcTest, GetIPCHandleSize) { EXPECT_GT(size, 0); } +TEST_P(umfIpcTest, GetIPCHandleSizeInvalidArgs) { + size_t size = 0; + umf_result_t ret = umfPoolGetIPCHandleSize(nullptr, &size); + EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + umf::pool_unique_handle_t pool = makePool(); + ret = umfPoolGetIPCHandleSize(pool.get(), nullptr); + EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} + TEST_P(umfIpcTest, GetIPCHandleInvalidArgs) { constexpr size_t SIZE = 100; umf_ipc_handle_t ipcHandle = nullptr; @@ -209,6 +228,64 @@ TEST_P(umfIpcTest, BasicFlow) { EXPECT_EQ(stat.closeCount, stat.openCount); } +TEST_P(umfIpcTest, GetPoolByOpenedHandle) { + constexpr size_t SIZE = 100; + constexpr size_t NUM_ALLOCS = 100; + constexpr size_t NUM_POOLS = 4; + void *ptrs[NUM_ALLOCS]; + void *openedPtrs[NUM_POOLS][NUM_ALLOCS]; + std::vector pools_to_open; + umf::pool_unique_handle_t pool = makePool(); + + for (size_t i = 0; i < NUM_POOLS; ++i) { + pools_to_open.push_back(makePool()); + } + + for (size_t i = 0; i < NUM_ALLOCS; ++i) { + void *ptr = umfPoolMalloc(pool.get(), SIZE); + ASSERT_NE(ptr, nullptr); + ptrs[i] = ptr; + } + + for (size_t i = 0; i < NUM_ALLOCS; ++i) { + umf_ipc_handle_t ipcHandle = nullptr; + size_t handleSize = 0; + umf_result_t ret = umfGetIPCHandle(ptrs[i], &ipcHandle, &handleSize); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + for (size_t pool_id = 0; pool_id < NUM_POOLS; pool_id++) { + void *ptr = nullptr; + ret = + umfOpenIPCHandle(pools_to_open[pool_id].get(), ipcHandle, &ptr); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + openedPtrs[pool_id][i] = ptr; + } + + ret = umfPutIPCHandle(ipcHandle); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + } + + for (size_t pool_id = 0; pool_id < NUM_POOLS; pool_id++) { + for (size_t i = 0; i < NUM_ALLOCS; ++i) { + umf_memory_pool_handle_t openedPool = + umfPoolByPtr(openedPtrs[pool_id][i]); + EXPECT_EQ(openedPool, pools_to_open[pool_id].get()); + } + } + + for (size_t pool_id = 0; pool_id < NUM_POOLS; pool_id++) { + for (size_t i = 0; i < NUM_ALLOCS; ++i) { + umf_result_t ret = umfCloseIPCHandle(openedPtrs[pool_id][i]); + EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + } + } + + for (size_t i = 0; i < NUM_ALLOCS; ++i) { + umf_result_t ret = umfFree(ptrs[i]); + EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + } +} + TEST_P(umfIpcTest, ConcurrentGetPutHandles) { std::vector ptrs; constexpr size_t ALLOC_SIZE = 100; From 47aa4491407a2dff626025391c9c83193649ae51 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Mon, 16 Sep 2024 17:50:46 +0200 Subject: [PATCH 098/352] Add umIpcTest.AllocFreeAllocTest test --- test/ipcFixtures.hpp | 49 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/test/ipcFixtures.hpp b/test/ipcFixtures.hpp index 4c9ebd549..cd8905008 100644 --- a/test/ipcFixtures.hpp +++ b/test/ipcFixtures.hpp @@ -286,6 +286,55 @@ TEST_P(umfIpcTest, GetPoolByOpenedHandle) { } } +TEST_P(umfIpcTest, AllocFreeAllocTest) { + constexpr size_t SIZE = 64 * 1024; + umf::pool_unique_handle_t pool = makePool(); + void *ptr = umfPoolMalloc(pool.get(), SIZE); + EXPECT_NE(ptr, nullptr); + + umf_ipc_handle_t ipcHandle = nullptr; + size_t handleSize = 0; + umf_result_t ret = umfGetIPCHandle(ptr, &ipcHandle, &handleSize); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + void *opened_ptr = nullptr; + ret = umfOpenIPCHandle(pool.get(), ipcHandle, &opened_ptr); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + ret = umfCloseIPCHandle(opened_ptr); + EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + + ret = umfPutIPCHandle(ipcHandle); + EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + + ret = umfPoolFree(pool.get(), ptr); + EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + + ptr = umfPoolMalloc(pool.get(), SIZE); + ASSERT_NE(ptr, nullptr); + + ret = umfGetIPCHandle(ptr, &ipcHandle, &handleSize); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + ret = umfOpenIPCHandle(pool.get(), ipcHandle, &opened_ptr); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + ret = umfCloseIPCHandle(opened_ptr); + EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + + ret = umfPutIPCHandle(ipcHandle); + EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + + ret = umfPoolFree(pool.get(), ptr); + EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + + pool.reset(nullptr); + EXPECT_EQ(stat.allocCount, stat.getCount); + EXPECT_EQ(stat.getCount, stat.putCount); + EXPECT_EQ(stat.openCount, stat.getCount); + EXPECT_EQ(stat.openCount, stat.closeCount); +} + TEST_P(umfIpcTest, ConcurrentGetPutHandles) { std::vector ptrs; constexpr size_t ALLOC_SIZE = 100; From 1c43734b2f865634bd1b892d9d9009f2fbc389cc Mon Sep 17 00:00:00 2001 From: Patryk Kaminski Date: Tue, 17 Sep 2024 12:23:34 +0200 Subject: [PATCH 099/352] Handle development tags in versioning --- cmake/helpers.cmake | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/cmake/helpers.cmake b/cmake/helpers.cmake index 1d3e175fa..a09fe283f 100644 --- a/cmake/helpers.cmake +++ b/cmake/helpers.cmake @@ -121,6 +121,22 @@ function(set_version_variables) return() endif() + # v1.5.0-dev - we're on a development tag -> UMF ver: "1.5.0-dev" + string(REGEX MATCHALL "\^v([0-9]+\.[0-9]+\.[0-9]+)-dev\$" MATCHES + ${GIT_VERSION}) + if(MATCHES) + set(UMF_VERSION + "${CMAKE_MATCH_1}-dev" + PARENT_SCOPE) + set(UMF_CMAKE_VERSION + "${CMAKE_MATCH_1}" + PARENT_SCOPE) + set(UMF_VERSION_PRIVATE + 0 + PARENT_SCOPE) + return() + endif() + # v1.5.0-rc1-19-gb8f7a32 -> UMF ver: "1.5.0-rc1.git19.gb8f7a32" string(REGEX MATCHALL "v([0-9.]*)-rc([0-9]*)-([0-9]*)-([0-9a-g]*)" MATCHES ${GIT_VERSION}) @@ -141,6 +157,19 @@ function(set_version_variables) return() endif() + # v1.5.0-dev-19-gb8f7a32 -> UMF ver: "1.5.0-dev.git19.gb8f7a32" + string(REGEX MATCHALL "v([0-9.]*)-dev-([0-9]*)-([0-9a-g]*)" MATCHES + ${GIT_VERSION}) + if(MATCHES) + set(UMF_VERSION + "${CMAKE_MATCH_1}-dev.git${CMAKE_MATCH_2}.${CMAKE_MATCH_3}" + PARENT_SCOPE) + set(UMF_CMAKE_VERSION + "${CMAKE_MATCH_1}" + PARENT_SCOPE) + return() + endif() + # v1.5.0-19-gb8f7a32 -> UMF ver: "1.5.0-git19.gb8f7a32" string(REGEX MATCHALL "v([0-9.]*)-([0-9]*)-([0-9a-g]*)" MATCHES ${GIT_VERSION}) From 6c4642f35f5e7257673f0c9f6fe4449fd1d1a382 Mon Sep 17 00:00:00 2001 From: Rafal Rudnicki Date: Tue, 17 Sep 2024 17:03:56 +0200 Subject: [PATCH 100/352] fix L0 "unused symbol" warning in ubench --- benchmark/ubench.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/benchmark/ubench.c b/benchmark/ubench.c index 900b7b85c..4cbde9491 100644 --- a/benchmark/ubench.c +++ b/benchmark/ubench.c @@ -30,7 +30,8 @@ #include "utils_common.h" -#if (defined UMF_BUILD_GPU_TESTS) +#if (defined UMF_BUILD_LIBUMF_POOL_DISJOINT && \ + defined UMF_BUILD_LEVEL_ZERO_PROVIDER && defined UMF_BUILD_GPU_TESTS) #include "utils_level_zero.h" #endif From 57f0c3676d743ec187ca86220383cb4bbcc43315 Mon Sep 17 00:00:00 2001 From: Rafal Rudnicki Date: Tue, 17 Sep 2024 17:05:24 +0200 Subject: [PATCH 101/352] define l0 prov functions as static --- src/provider/provider_level_zero.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/provider/provider_level_zero.c b/src/provider/provider_level_zero.c index 1b4911980..cc7eeffd8 100644 --- a/src/provider/provider_level_zero.c +++ b/src/provider/provider_level_zero.c @@ -69,7 +69,7 @@ static void store_last_native_error(int32_t native_error) { TLS_last_native_error = native_error; } -umf_result_t ze2umf_result(ze_result_t result) { +static umf_result_t ze2umf_result(ze_result_t result) { switch (result) { case ZE_RESULT_SUCCESS: return UMF_RESULT_SUCCESS; @@ -125,7 +125,8 @@ static void init_ze_global_state(void) { } } -umf_result_t ze_memory_provider_initialize(void *params, void **provider) { +static umf_result_t ze_memory_provider_initialize(void *params, + void **provider) { if (provider == NULL || params == NULL) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; } @@ -181,8 +182,7 @@ umf_result_t ze_memory_provider_initialize(void *params, void **provider) { return UMF_RESULT_SUCCESS; } -void ze_memory_provider_finalize(void *provider) { - assert(provider); +static void ze_memory_provider_finalize(void *provider) { util_init_once(&ze_is_initialized, init_ze_global_state); umf_ba_global_free(provider); @@ -285,11 +285,10 @@ static umf_result_t ze_memory_provider_free(void *provider, void *ptr, return ze2umf_result(ze_result); } -void ze_memory_provider_get_last_native_error(void *provider, - const char **ppMessage, - int32_t *pError) { +static void ze_memory_provider_get_last_native_error(void *provider, + const char **ppMessage, + int32_t *pError) { (void)provider; - (void)ppMessage; assert(pError); @@ -338,7 +337,7 @@ ze_memory_provider_get_recommended_page_size(void *provider, size_t size, return UMF_RESULT_SUCCESS; } -const char *ze_memory_provider_get_name(void *provider) { +static const char *ze_memory_provider_get_name(void *provider) { (void)provider; return "LEVEL_ZERO"; } From abc31b9432acdfc65e277b36c05da87de2f79a58 Mon Sep 17 00:00:00 2001 From: Rafal Rudnicki Date: Tue, 17 Sep 2024 17:05:47 +0200 Subject: [PATCH 102/352] improve l0 prov error handling --- src/provider/provider_level_zero.c | 73 ++++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 18 deletions(-) diff --git a/src/provider/provider_level_zero.c b/src/provider/provider_level_zero.c index cc7eeffd8..19a0dfb0d 100644 --- a/src/provider/provider_level_zero.c +++ b/src/provider/provider_level_zero.c @@ -183,6 +183,10 @@ static umf_result_t ze_memory_provider_initialize(void *params, } static void ze_memory_provider_finalize(void *provider) { + if (provider == NULL) { + ASSERT(0); + return; + } util_init_once(&ze_is_initialized, init_ze_global_state); umf_ba_global_free(provider); @@ -194,8 +198,10 @@ static void ze_memory_provider_finalize(void *provider) { static bool use_relaxed_allocation(ze_memory_provider_t *ze_provider, size_t size) { + assert(ze_provider); assert(ze_provider->device); assert(ze_provider->device_properties.maxMemAllocSize > 0); + return size > ze_provider->device_properties.maxMemAllocSize; } @@ -207,8 +213,9 @@ static ze_relaxed_allocation_limits_exp_desc_t relaxed_device_allocation_desc = static umf_result_t ze_memory_provider_alloc(void *provider, size_t size, size_t alignment, void **resultPtr) { - assert(provider); - assert(resultPtr); + if (provider == NULL || resultPtr == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } ze_memory_provider_t *ze_provider = (ze_memory_provider_t *)provider; @@ -256,7 +263,10 @@ static umf_result_t ze_memory_provider_alloc(void *provider, size_t size, break; } default: - return UMF_RESULT_ERROR_INVALID_ARGUMENT; + // this shouldn't happen as we check the memory_type settings during + // the initialization + LOG_ERR("unsupported USM memory type"); + return UMF_RESULT_ERROR_UNKNOWN; } if (ze_result != ZE_RESULT_SUCCESS) { @@ -279,7 +289,14 @@ static umf_result_t ze_memory_provider_free(void *provider, void *ptr, size_t bytes) { (void)bytes; - assert(provider); + if (provider == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + if (ptr == NULL) { + return UMF_RESULT_SUCCESS; + } + ze_memory_provider_t *ze_provider = (ze_memory_provider_t *)provider; ze_result_t ze_result = g_ze_ops.zeMemFree(ze_provider->context, ptr); return ze2umf_result(ze_result); @@ -290,7 +307,10 @@ static void ze_memory_provider_get_last_native_error(void *provider, int32_t *pError) { (void)provider; - assert(pError); + if (ppMessage == NULL || pError == NULL) { + ASSERT(0); + return; + } *pError = TLS_last_native_error; } @@ -298,9 +318,12 @@ static void ze_memory_provider_get_last_native_error(void *provider, static umf_result_t ze_memory_provider_get_min_page_size(void *provider, void *ptr, size_t *pageSize) { - (void)provider; (void)ptr; + if (provider == NULL || pageSize == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + // TODO *pageSize = 1024 * 64; return UMF_RESULT_SUCCESS; @@ -329,9 +352,12 @@ static umf_result_t ze_memory_provider_purge_force(void *provider, void *ptr, static umf_result_t ze_memory_provider_get_recommended_page_size(void *provider, size_t size, size_t *pageSize) { - (void)provider; (void)size; + if (provider == NULL || pageSize == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + // TODO *pageSize = 1024 * 64; return UMF_RESULT_SUCCESS; @@ -375,8 +401,10 @@ typedef struct ze_ipc_data_t { static umf_result_t ze_memory_provider_get_ipc_handle_size(void *provider, size_t *size) { - (void)provider; - ASSERT(size != NULL); + if (provider == NULL || size == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + *size = sizeof(ze_ipc_data_t); return UMF_RESULT_SUCCESS; } @@ -385,9 +413,12 @@ static umf_result_t ze_memory_provider_get_ipc_handle(void *provider, const void *ptr, size_t size, void *providerIpcData) { - ASSERT(ptr != NULL); - ASSERT(providerIpcData != NULL); (void)size; + + if (provider == NULL || ptr == NULL || providerIpcData == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + ze_result_t ze_result; ze_ipc_data_t *ze_ipc_data = (ze_ipc_data_t *)providerIpcData; struct ze_memory_provider_t *ze_provider = @@ -407,8 +438,10 @@ static umf_result_t ze_memory_provider_get_ipc_handle(void *provider, static umf_result_t ze_memory_provider_put_ipc_handle(void *provider, void *providerIpcData) { - ASSERT(provider != NULL); - ASSERT(providerIpcData != NULL); + if (provider == NULL || providerIpcData == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + ze_result_t ze_result; struct ze_memory_provider_t *ze_provider = (struct ze_memory_provider_t *)provider; @@ -433,9 +466,10 @@ static umf_result_t ze_memory_provider_put_ipc_handle(void *provider, static umf_result_t ze_memory_provider_open_ipc_handle(void *provider, void *providerIpcData, void **ptr) { - ASSERT(provider != NULL); - ASSERT(providerIpcData != NULL); - ASSERT(ptr != NULL); + if (provider == NULL || ptr == NULL || providerIpcData == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + ze_result_t ze_result; ze_ipc_data_t *ze_ipc_data = (ze_ipc_data_t *)providerIpcData; struct ze_memory_provider_t *ze_provider = @@ -470,9 +504,12 @@ static umf_result_t ze_memory_provider_open_ipc_handle(void *provider, static umf_result_t ze_memory_provider_close_ipc_handle(void *provider, void *ptr, size_t size) { - ASSERT(provider != NULL); - ASSERT(ptr != NULL); (void)size; + + if (provider == NULL || ptr == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + ze_result_t ze_result; struct ze_memory_provider_t *ze_provider = (struct ze_memory_provider_t *)provider; From 1abd0cd5eb18d55f1302558bb59f75bafaa9d7a7 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 18 Sep 2024 14:29:36 +0200 Subject: [PATCH 103/352] Update UMF version to 0.10.0 in headers, CI and docs config file --- .github/workflows/basic.yml | 2 +- include/umf/base.h | 2 +- scripts/docs_config/conf.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/basic.yml b/.github/workflows/basic.yml index 232f96869..3580c3621 100644 --- a/.github/workflows/basic.yml +++ b/.github/workflows/basic.yml @@ -8,7 +8,7 @@ permissions: env: # for installation testing - it should match with version set in CMake - UMF_VERSION: 0.9.0 + UMF_VERSION: 0.10.0 BUILD_DIR : "${{github.workspace}}/build" INSTL_DIR : "${{github.workspace}}/../install-dir" diff --git a/include/umf/base.h b/include/umf/base.h index ecc0abf55..854688a86 100644 --- a/include/umf/base.h +++ b/include/umf/base.h @@ -28,7 +28,7 @@ extern "C" { #define UMF_MINOR_VERSION(_ver) (_ver & 0x0000ffff) /// @brief Current version of the UMF headers -#define UMF_VERSION_CURRENT UMF_MAKE_VERSION(0, 9) +#define UMF_VERSION_CURRENT UMF_MAKE_VERSION(0, 10) /// @brief Operation results typedef enum umf_result_t { diff --git a/scripts/docs_config/conf.py b/scripts/docs_config/conf.py index b93d7d977..28c9b5f9f 100644 --- a/scripts/docs_config/conf.py +++ b/scripts/docs_config/conf.py @@ -22,7 +22,7 @@ author = "Intel" # The full version, including alpha/beta/rc tags -release = "0.9.0" +release = "0.10.0" # -- General configuration --------------------------------------------------- From 4a7eb95d81a5acf461f5a30a762248b360ad140f Mon Sep 17 00:00:00 2001 From: Rafal Rudnicki Date: Mon, 29 Jul 2024 16:39:48 +0200 Subject: [PATCH 104/352] add CUDA provider --- .github/workflows/basic.yml | 20 +- .github/workflows/benchmarks.yml | 1 + .github/workflows/codeql.yml | 1 + .github/workflows/fast.yml | 1 + .github/workflows/gpu.yml | 70 +++- .github/workflows/nightly.yml | 1 + .github/workflows/pr_push.yml | 1 + .github/workflows/sanitizers.yml | 2 + .github/workflows/valgrind.yml | 1 + CMakeLists.txt | 18 + README.md | 26 +- benchmark/CMakeLists.txt | 7 +- benchmark/ubench.c | 2 + cmake/FindCUDA.cmake | 35 ++ examples/CMakeLists.txt | 49 ++- examples/cuda_shared_memory/CMakeLists.txt | 74 ++++ .../cuda_shared_memory/cuda_shared_memory.c | 115 ++++++ .../CMakeLists.txt | 6 +- .../level_zero_shared_memory.c} | 0 include/umf/memory_provider_gpu.h | 31 ++ include/umf/providers/provider_cuda.h | 30 ++ include/umf/providers/provider_level_zero.h | 12 +- scripts/docs_config/examples.rst | 7 +- scripts/qemu/run-build.sh | 1 + src/CMakeLists.txt | 36 ++ src/provider/provider_cuda.c | 372 ++++++++++++++++++ test/CMakeLists.txt | 50 ++- test/providers/cuda_helpers.cpp | 291 ++++++++++++++ test/providers/cuda_helpers.h | 36 ++ test/providers/provider_cuda.cpp | 189 +++++++++ 30 files changed, 1453 insertions(+), 32 deletions(-) create mode 100644 cmake/FindCUDA.cmake create mode 100644 examples/cuda_shared_memory/CMakeLists.txt create mode 100644 examples/cuda_shared_memory/cuda_shared_memory.c rename examples/{gpu_shared_memory => level_zero_shared_memory}/CMakeLists.txt (93%) rename examples/{gpu_shared_memory/gpu_shared_memory.c => level_zero_shared_memory/level_zero_shared_memory.c} (100%) create mode 100644 include/umf/memory_provider_gpu.h create mode 100644 include/umf/providers/provider_cuda.h create mode 100644 src/provider/provider_cuda.c create mode 100644 test/providers/cuda_helpers.cpp create mode 100644 test/providers/cuda_helpers.h create mode 100644 test/providers/provider_cuda.cpp diff --git a/.github/workflows/basic.yml b/.github/workflows/basic.yml index 3580c3621..a2e41aa5e 100644 --- a/.github/workflows/basic.yml +++ b/.github/workflows/basic.yml @@ -22,6 +22,7 @@ jobs: compiler: [{c: gcc, cxx: g++}] shared_library: ['OFF'] level_zero_provider: ['ON'] + cuda_provider: ['ON'] install_tbb: ['ON'] disable_hwloc: ['OFF'] link_hwloc_statically: ['OFF'] @@ -31,6 +32,7 @@ jobs: compiler: {c: gcc-7, cxx: g++-7} shared_library: 'OFF' level_zero_provider: 'ON' + cuda_provider: 'ON' install_tbb: 'ON' disable_hwloc: 'OFF' link_hwloc_statically: 'OFF' @@ -39,6 +41,7 @@ jobs: compiler: {c: clang, cxx: clang++} shared_library: 'OFF' level_zero_provider: 'ON' + cuda_provider: 'ON' install_tbb: 'ON' disable_hwloc: 'OFF' link_hwloc_statically: 'OFF' @@ -47,6 +50,7 @@ jobs: compiler: {c: gcc, cxx: g++} shared_library: 'ON' level_zero_provider: 'ON' + cuda_provider: 'ON' install_tbb: 'ON' disable_hwloc: 'OFF' link_hwloc_statically: 'OFF' @@ -55,15 +59,17 @@ jobs: compiler: {c: gcc, cxx: g++} shared_library: 'ON' level_zero_provider: 'ON' + cuda_provider: 'ON' install_tbb: 'ON' disable_hwloc: 'OFF' link_hwloc_statically: 'OFF' - # test level_zero_provider='OFF' + # test level_zero_provider='OFF' and cuda_provider='OFF' - os: 'ubuntu-22.04' build_type: Release compiler: {c: gcc, cxx: g++} shared_library: 'OFF' level_zero_provider: 'OFF' + cuda_provider: 'OFF' install_tbb: 'ON' disable_hwloc: 'OFF' link_hwloc_statically: 'OFF' @@ -73,6 +79,7 @@ jobs: compiler: {c: icx, cxx: icpx} shared_library: 'ON' level_zero_provider: 'ON' + cuda_provider: 'ON' install_tbb: 'ON' disable_hwloc: 'OFF' link_hwloc_statically: 'OFF' @@ -82,6 +89,7 @@ jobs: compiler: {c: gcc, cxx: g++} shared_library: 'ON' level_zero_provider: 'ON' + cuda_provider: 'ON' install_tbb: 'OFF' disable_hwloc: 'OFF' link_hwloc_statically: 'OFF' @@ -90,6 +98,7 @@ jobs: compiler: {c: gcc, cxx: g++} shared_library: 'ON' level_zero_provider: 'ON' + cuda_provider: 'ON' install_tbb: 'ON' disable_hwloc: 'ON' link_hwloc_statically: 'OFF' @@ -98,6 +107,7 @@ jobs: compiler: {c: gcc, cxx: g++} shared_library: 'ON' level_zero_provider: 'ON' + cuda_provider: 'ON' install_tbb: 'ON' disable_hwloc: 'OFF' link_hwloc_statically: 'ON' @@ -149,6 +159,7 @@ jobs: -DCMAKE_C_COMPILER=${{matrix.compiler.c}} -DCMAKE_CXX_COMPILER=${{matrix.compiler.cxx}} -DUMF_BUILD_LEVEL_ZERO_PROVIDER=${{matrix.level_zero_provider}} + -DUMF_BUILD_CUDA_PROVIDER=${{matrix.cuda_provider}} -DUMF_FORMAT_CODE_STYLE=OFF -DUMF_DEVELOPER_MODE=ON -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON @@ -195,23 +206,27 @@ jobs: compiler: [{c: cl, cxx: cl}] shared_library: ['ON', 'OFF'] level_zero_provider: ['ON'] + cuda_provider: ['ON'] include: - os: 'windows-2022' build_type: Release compiler: {c: clang-cl, cxx: clang-cl} shared_library: 'ON' level_zero_provider: 'ON' + cuda_provider: 'ON' toolset: "-T ClangCL" - os: 'windows-2022' build_type: Release compiler: {c: cl, cxx: cl} shared_library: 'ON' level_zero_provider: 'ON' + cuda_provider: 'ON' - os: 'windows-2022' build_type: Release compiler: {c: cl, cxx: cl} shared_library: 'ON' level_zero_provider: 'OFF' + cuda_provider: 'OFF' runs-on: ${{matrix.os}} @@ -247,6 +262,7 @@ jobs: -DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON -DUMF_BUILD_LEVEL_ZERO_PROVIDER=${{matrix.level_zero_provider}} + -DUMF_BUILD_CUDA_PROVIDER=${{matrix.cuda_provider}} -DUMF_TESTS_FAIL_ON_SKIP=ON - name: Build UMF @@ -305,6 +321,7 @@ jobs: -DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=OFF -DUMF_BUILD_LEVEL_ZERO_PROVIDER=ON + -DUMF_BUILD_CUDA_PROVIDER=ON -DUMF_TESTS_FAIL_ON_SKIP=ON -DUMF_LINK_HWLOC_STATICALLY=ON @@ -347,6 +364,7 @@ jobs: -DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=OFF -DUMF_BUILD_LEVEL_ZERO_PROVIDER=ON + -DUMF_BUILD_CUDA_PROVIDER=ON -DUMF_TESTS_FAIL_ON_SKIP=ON -DUMF_LINK_HWLOC_STATICALLY=ON diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml index de48173bf..41710029c 100644 --- a/.github/workflows/benchmarks.yml +++ b/.github/workflows/benchmarks.yml @@ -63,6 +63,7 @@ jobs: -DUMF_FORMAT_CODE_STYLE=OFF -DUMF_DEVELOPER_MODE=OFF -DUMF_BUILD_LEVEL_ZERO_PROVIDER=ON + -DUMF_BUILD_CUDA_PROVIDER=ON -DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index b449eb23e..a44423420 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -84,6 +84,7 @@ jobs: -DUMF_DEVELOPER_MODE=ON -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON -DUMF_BUILD_LEVEL_ZERO_PROVIDER=ON + -DUMF_BUILD_CUDA_PROVIDER=ON -DUMF_TESTS_FAIL_ON_SKIP=ON - name: Build diff --git a/.github/workflows/fast.yml b/.github/workflows/fast.yml index 1e980c3e2..997c4441c 100644 --- a/.github/workflows/fast.yml +++ b/.github/workflows/fast.yml @@ -106,6 +106,7 @@ jobs: -DUMF_BUILD_TESTS=${{matrix.build_tests}} -DUMF_BUILD_EXAMPLES=ON -DUMF_BUILD_LEVEL_ZERO_PROVIDER=ON + -DUMF_BUILD_CUDA_PROVIDER=ON -DUMF_TESTS_FAIL_ON_SKIP=ON -DUMF_BUILD_SHARED_LIBRARY=ON ${{matrix.extra_build_options}} diff --git a/.github/workflows/gpu.yml b/.github/workflows/gpu.yml index 3024b9f7e..279f977b1 100644 --- a/.github/workflows/gpu.yml +++ b/.github/workflows/gpu.yml @@ -1,6 +1,7 @@ # This workflow builds and tests providers using GPU memory. It requires -# "level_zero" labeled self-hosted runners installed on systems with the -# appropriate GPU and drivers. +# appropriately labelled self-hosted runners installed on systems with the +# correct GPU and drivers + name: GPU on: [workflow_call] @@ -63,6 +64,7 @@ jobs: -DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON -DUMF_BUILD_LEVEL_ZERO_PROVIDER=ON + -DUMF_BUILD_CUDA_PROVIDER=OFF -DUMF_TESTS_FAIL_ON_SKIP=ON - name: Configure build for Ubuntu @@ -84,6 +86,7 @@ jobs: -DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON -DUMF_BUILD_LEVEL_ZERO_PROVIDER=ON + -DUMF_BUILD_CUDA_PROVIDER=OFF -DUMF_TESTS_FAIL_ON_SKIP=ON - name: Build UMF @@ -100,3 +103,66 @@ jobs: - name: Run benchmarks working-directory: ${{env.BUILD_DIR}} run: ctest --output-on-failure --test-dir benchmark -C ${{env.BUILD_TYPE}} --exclude-regex umf-bench-multithreaded + + gpu-CUDA: + name: Build + env: + BUILD_TYPE: Release + # run only on upstream; forks will not have the HW + if: github.repository == 'oneapi-src/unified-memory-framework' + strategy: + matrix: + shared_library: ['ON', 'OFF'] + # TODO add windows + os: ['Ubuntu'] + include: + - os: 'Ubuntu' + compiler: {c: gcc, cxx: g++} + number_of_processors: '$(nproc)' + + runs-on: ["DSS-CUDA", "DSS-${{matrix.os}}"] + steps: + - name: Checkout + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + + - name: Get information about platform + if: matrix.os == 'Ubuntu' + run: .github/scripts/get_system_info.sh + + - name: Configure build for Ubuntu + if: matrix.os == 'Ubuntu' + run: > + cmake -B ${{env.BUILD_DIR}} + -DCMAKE_INSTALL_PREFIX="${{env.INSTL_DIR}}" + -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} + -DCMAKE_C_COMPILER=${{matrix.compiler.c}} + -DCMAKE_CXX_COMPILER=${{matrix.compiler.cxx}} + -DUMF_BUILD_SHARED_LIBRARY=${{matrix.shared_library}} + -DUMF_BUILD_BENCHMARKS=ON + -DUMF_BUILD_TESTS=ON + -DUMF_BUILD_GPU_TESTS=ON + -DUMF_BUILD_GPU_EXAMPLES=ON + -DUMF_FORMAT_CODE_STYLE=OFF + -DUMF_DEVELOPER_MODE=ON + -DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON + -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON + -DUMF_BUILD_LEVEL_ZERO_PROVIDER=OFF + -DUMF_BUILD_CUDA_PROVIDER=ON + -DUMF_TESTS_FAIL_ON_SKIP=ON + + - name: Build UMF + run: cmake --build ${{env.BUILD_DIR}} --config ${{env.BUILD_TYPE}} -j ${{matrix.number_of_processors}} + + - name: Run tests + working-directory: ${{env.BUILD_DIR}} + run: ctest -C ${{env.BUILD_TYPE}} --output-on-failure --test-dir test + + - name: Run examples + working-directory: ${{env.BUILD_DIR}} + run: ctest --output-on-failure --test-dir examples -C ${{env.BUILD_TYPE}} + + - name: Run benchmarks + working-directory: ${{env.BUILD_DIR}} + run: ctest --output-on-failure --test-dir benchmark -C ${{env.BUILD_TYPE}} --exclude-regex umf-bench-multithreaded diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index f2bf8f08f..89317cc63 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -79,6 +79,7 @@ jobs: -DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON -DUMF_BUILD_LEVEL_ZERO_PROVIDER=OFF + -DUMF_BUILD_CUDA_PROVIDER=OFF -DUMF_USE_VALGRIND=1 -DUMF_TESTS_FAIL_ON_SKIP=ON diff --git a/.github/workflows/pr_push.yml b/.github/workflows/pr_push.yml index 4c7a27c1d..02b7adf9f 100644 --- a/.github/workflows/pr_push.yml +++ b/.github/workflows/pr_push.yml @@ -37,6 +37,7 @@ jobs: -DUMF_FORMAT_CODE_STYLE=ON -DUMF_BUILD_TESTS=OFF -DUMF_BUILD_LEVEL_ZERO_PROVIDER=OFF + -DUMF_BUILD_CUDA_PROVIDER=OFF -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=OFF - name: Check C/C++ formatting diff --git a/.github/workflows/sanitizers.yml b/.github/workflows/sanitizers.yml index 2a09f60fe..2c63ebd51 100644 --- a/.github/workflows/sanitizers.yml +++ b/.github/workflows/sanitizers.yml @@ -55,6 +55,7 @@ jobs: -DCMAKE_C_COMPILER=${{matrix.compiler.c}} -DCMAKE_CXX_COMPILER=${{matrix.compiler.cxx}} -DUMF_BUILD_LEVEL_ZERO_PROVIDER=ON + -DUMF_BUILD_CUDA_PROVIDER=ON -DUMF_FORMAT_CODE_STYLE=OFF -DUMF_DEVELOPER_MODE=ON -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON @@ -132,6 +133,7 @@ jobs: -DUMF_USE_ASAN=${{matrix.sanitizers.asan}} -DUMF_BUILD_EXAMPLES=ON -DUMF_BUILD_LEVEL_ZERO_PROVIDER=OFF + -DUMF_BUILD_CUDA_PROVIDER=OFF -DUMF_TESTS_FAIL_ON_SKIP=ON - name: Build UMF diff --git a/.github/workflows/valgrind.yml b/.github/workflows/valgrind.yml index 53569385e..40d4e6535 100644 --- a/.github/workflows/valgrind.yml +++ b/.github/workflows/valgrind.yml @@ -35,6 +35,7 @@ jobs: -DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON -DUMF_BUILD_LEVEL_ZERO_PROVIDER=OFF + -DUMF_BUILD_CUDA_PROVIDER=OFF -DUMF_USE_VALGRIND=1 -DUMF_TESTS_FAIL_ON_SKIP=ON diff --git a/CMakeLists.txt b/CMakeLists.txt index e54d1146e..d926b7ec8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,7 @@ find_package(PkgConfig) # Build Options option(UMF_BUILD_SHARED_LIBRARY "Build UMF as shared library" OFF) option(UMF_BUILD_LEVEL_ZERO_PROVIDER "Build Level Zero memory provider" ON) +option(UMF_BUILD_CUDA_PROVIDER "Build CUDA memory provider" ON) option(UMF_BUILD_LIBUMF_POOL_DISJOINT "Build the libumf_pool_disjoint static library" OFF) option(UMF_BUILD_LIBUMF_POOL_JEMALLOC @@ -407,6 +408,18 @@ else() ) endif() +if((UMF_BUILD_GPU_TESTS OR UMF_BUILD_GPU_EXAMPLES) AND UMF_BUILD_CUDA_PROVIDER) + find_package(CUDA REQUIRED cuda) + if(CUDA_LIBRARIES) + set(UMF_CUDA_ENABLED TRUE) + else() + message( + STATUS "Disabling tests and examples that use the CUDA provider " + "because the CUDA libraries they require were not found.") + endif() + # TODO do the same for ze_loader +endif() + # set optional symbols for map/def files # # TODO: ref. #649 @@ -417,6 +430,11 @@ if(UMF_BUILD_LEVEL_ZERO_PROVIDER) add_optional_symbol(umfLevelZeroMemoryProviderOps) endif() +# Conditional configuration for CUDA provider +if(UMF_BUILD_CUDA_PROVIDER) + add_optional_symbol(umfCUDAMemoryProviderOps) +endif() + if(NOT UMF_DISABLE_HWLOC) add_optional_symbol(umfOsMemoryProviderOps) if(LINUX) diff --git a/README.md b/README.md index 0c80bee12..0cfc50cdc 100644 --- a/README.md +++ b/README.md @@ -19,10 +19,11 @@ The Unified Memory Framework (UMF) is a library for constructing allocators and For a quick introduction to UMF usage, please see [examples](https://oneapi-src.github.io/unified-memory-framework/examples.html) documentation, which includes the code of the -[basic example](https://github.com/oneapi-src/unified-memory-framework/blob/main/examples/basic/basic.c) -and the more advanced one that allocates -[USM memory from the GPU device](https://github.com/oneapi-src/unified-memory-framework/blob/main/examples/basic/gpu_shared_memory.c) -using the Level Zero API and UMF Level Zero memory provider. +[basic example](https://github.com/oneapi-src/unified-memory-framework/blob/main/examples/basic/basic.c). +The are also more advanced that allocates USM memory from the +[Level Zero device](https://github.com/oneapi-src/unified-memory-framework/blob/main/examples/level_zero_shared_memory/level_zero_shared_memory.c) +using the Level Zero API and UMF Level Zero memory provider and [CUDA device](https://github.com/oneapi-src/unified-memory-framework/blob/main/examples/cuda_shared_memory/cuda_shared_memory.c) +using the CUDA API and UMF CUDA memory provider. ## Build @@ -101,6 +102,7 @@ List of options provided by CMake: | - | - | - | - | | UMF_BUILD_SHARED_LIBRARY | Build UMF as shared library | ON/OFF | OFF | | UMF_BUILD_LEVEL_ZERO_PROVIDER | Build Level Zero memory provider | ON/OFF | ON | +| UMF_BUILD_CUDA_PROVIDER | Build CUDA memory provider | ON/OFF | ON | | UMF_BUILD_LIBUMF_POOL_DISJOINT | Build the libumf_pool_disjoint static library | ON/OFF | OFF | | UMF_BUILD_LIBUMF_POOL_JEMALLOC | Build the libumf_pool_jemalloc static library | ON/OFF | OFF | | UMF_BUILD_TESTS | Build UMF tests | ON/OFF | ON | @@ -203,6 +205,22 @@ with the `disable_provider_free` parameter set to true. 1) Linux OS 2) A length of a path of a file to be mapped can be `PATH_MAX` (4096) characters at most. +#### CUDA memory provider + +A memory provider that provides memory from CUDA device. + +##### Requirements + +1) Linux or Windows OS +2) The `UMF_BUILD_CUDA_PROVIDER` option turned `ON` (by default) + +Additionally, required for tests: + +3) The `UMF_BUILD_GPU_TESTS` option turned `ON` +4) System with CUDA compatible GPU +5) Required packages: + - nvidia-cuda-dev (Linux) or cuda-sdk (Windows) + ### Memory pool managers #### Proxy pool (part of libumf) diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt index 455b9bc06..cbb6468ab 100644 --- a/benchmark/CMakeLists.txt +++ b/benchmark/CMakeLists.txt @@ -85,6 +85,10 @@ function(add_umf_benchmark) target_compile_definitions(${BENCH_NAME} PRIVATE UMF_BUILD_LEVEL_ZERO_PROVIDER=1) endif() + if(UMF_BUILD_CUDA_PROVIDER) + target_compile_definitions(${BENCH_NAME} + PRIVATE UMF_BUILD_CUDA_PROVIDER=1) + endif() if(UMF_BUILD_GPU_TESTS) target_compile_definitions(${BENCH_NAME} PRIVATE UMF_BUILD_GPU_TESTS=1) endif() @@ -103,8 +107,9 @@ endif() if(LINUX) set(LIBS_OPTIONAL ${LIBS_OPTIONAL} m) endif() -if(UMF_BUILD_GPU_TESTS) +if(UMF_BUILD_GPU_TESTS AND UMF_BUILD_LEVEL_ZERO_PROVIDER) set(LIBS_OPTIONAL ${LIBS_OPTIONAL} ze_loader) + # TODO add CUDA endif() # BENCHMARKS diff --git a/benchmark/ubench.c b/benchmark/ubench.c index 4cbde9491..f70f19fb3 100644 --- a/benchmark/ubench.c +++ b/benchmark/ubench.c @@ -506,6 +506,8 @@ UBENCH_EX(ipc, disjoint_pool_with_level_zero_provider) { } #endif /* (defined UMF_BUILD_LIBUMF_POOL_DISJOINT && defined UMF_BUILD_LEVEL_ZERO_PROVIDER && defined UMF_BUILD_GPU_TESTS) */ +// TODO add IPC benchmark for CUDA + UBENCH_MAIN() #if defined(_MSC_VER) diff --git a/cmake/FindCUDA.cmake b/cmake/FindCUDA.cmake new file mode 100644 index 000000000..92ef5c830 --- /dev/null +++ b/cmake/FindCUDA.cmake @@ -0,0 +1,35 @@ +# Copyright (C) 2024 Intel Corporation +# Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +message(STATUS "Checking for module 'cuda' using find_library()") + +find_library(CUDA_LIBRARY NAMES libcuda cuda) +set(CUDA_LIBRARIES ${CUDA_LIBRARY}) + +get_filename_component(CUDA_LIB_DIR ${CUDA_LIBRARIES} DIRECTORY) +set(CUDA_LIBRARY_DIRS ${CUDA_LIB_DIR}) + +if(WINDOWS) + find_file(CUDA_DLL NAMES "bin/cuda.dll" "cuda.dll") + get_filename_component(CUDA_DLL_DIR ${CUDA_DLL} DIRECTORY) + set(CUDA_DLL_DIRS ${CUDA_DLL_DIR}) +endif() + +if(CUDA_LIBRARY) + message(STATUS " Found cuda using find_library()") + message(STATUS " CUDA_LIBRARIES = ${CUDA_LIBRARIES}") + message(STATUS " CUDA_INCLUDE_DIRS = ${CUDA_INCLUDE_DIRS}") + message(STATUS " CUDA_LIBRARY_DIRS = ${CUDA_LIBRARY_DIRS}") + if(WINDOWS) + message(STATUS " CUDA_DLL_DIRS = ${CUDA_DLL_DIRS}") + endif() +else() + set(MSG_NOT_FOUND "cuda NOT found (set CMAKE_PREFIX_PATH to point the " + "location)") + if(CUDA_FIND_REQUIRED) + message(FATAL_ERROR ${MSG_NOT_FOUND}) + else() + message(WARNING ${MSG_NOT_FOUND}) + endif() +endif() diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 8b61c82a5..763d11670 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -44,16 +44,16 @@ endif() if(UMF_BUILD_GPU_EXAMPLES AND UMF_BUILD_LIBUMF_POOL_DISJOINT AND UMF_BUILD_LEVEL_ZERO_PROVIDER) - set(EXAMPLE_NAME umf_example_gpu_shared_memory) + set(EXAMPLE_NAME umf_example_level_zero_shared_memory) add_umf_executable( NAME ${EXAMPLE_NAME} - SRCS gpu_shared_memory/gpu_shared_memory.c + SRCS level_zero_shared_memory/level_zero_shared_memory.c LIBS disjoint_pool ze_loader umf) target_include_directories( ${EXAMPLE_NAME} - PRIVATE ${UMF_CMAKE_SOURCE_DIR}/src/utils + PRIVATE ${LEVEL_ZERO_INCLUDE_DIRS} ${UMF_CMAKE_SOURCE_DIR}/src/utils ${UMF_CMAKE_SOURCE_DIR}/include ${UMF_CMAKE_SOURCE_DIR}/examples/common) @@ -66,6 +66,44 @@ if(UMF_BUILD_GPU_EXAMPLES set_tests_properties(${EXAMPLE_NAME} PROPERTIES LABELS "example") + if(WINDOWS) + # append PATH to DLLs + set_property(TEST ${EXAMPLE_NAME} PROPERTY ENVIRONMENT_MODIFICATION + "${DLL_PATH_LIST}") + endif() +else() + message(STATUS "GPU Level Zero shared memory example requires " + "UMF_BUILD_GPU_EXAMPLES, UMF_BUILD_LEVEL_ZERO_PROVIDER and " + "UMF_BUILD_LIBUMF_POOL_DISJOINT to be turned ON - skipping") +endif() + +if(UMF_BUILD_GPU_EXAMPLES + AND UMF_BUILD_LIBUMF_POOL_DISJOINT + AND UMF_BUILD_CUDA_PROVIDER + AND UMF_CUDA_ENABLED) + set(EXAMPLE_NAME umf_example_cuda_shared_memory) + + add_umf_executable( + NAME ${EXAMPLE_NAME} + SRCS cuda_shared_memory/cuda_shared_memory.c + LIBS disjoint_pool cuda umf) + + target_include_directories( + ${EXAMPLE_NAME} + PRIVATE ${CUDA_INCLUDE_DIRS} ${UMF_CMAKE_SOURCE_DIR}/src/utils + ${UMF_CMAKE_SOURCE_DIR}/include + ${UMF_CMAKE_SOURCE_DIR}/examples/common) + + target_link_directories(${EXAMPLE_NAME} PRIVATE ${LIBHWLOC_LIBRARY_DIRS} + ${CUDA_LIBRARY_DIRS}) + + add_test( + NAME ${EXAMPLE_NAME} + COMMAND ${EXAMPLE_NAME} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + + set_tests_properties(${EXAMPLE_NAME} PROPERTIES LABELS "example") + if(WINDOWS) # append PATH to DLLs set_property(TEST ${EXAMPLE_NAME} PROPERTY ENVIRONMENT_MODIFICATION @@ -74,9 +112,8 @@ if(UMF_BUILD_GPU_EXAMPLES else() message( STATUS - "GPU shared memory example requires UMF_BUILD_GPU_EXAMPLES, " - "UMF_BUILD_LEVEL_ZERO_PROVIDER and UMF_BUILD_LIBUMF_POOL_DISJOINT " - "to be turned ON - skipping") + "GPU CUDA shared memory example requires UMF_BUILD_GPU_EXAMPLES, UMF_BUILD_CUDA_PROVIDER, UMF_BUILD_LIBUMF_POOL_DISJOINT to be turned ON and installed CUDA libraries - skipping" + ) endif() # TODO: it looks like there is some problem with IPC implementation in Level diff --git a/examples/cuda_shared_memory/CMakeLists.txt b/examples/cuda_shared_memory/CMakeLists.txt new file mode 100644 index 000000000..a30621887 --- /dev/null +++ b/examples/cuda_shared_memory/CMakeLists.txt @@ -0,0 +1,74 @@ +# Copyright (C) 2024 Intel Corporation +# Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 3.14.0 FATAL_ERROR) +project(umf_example_cuda_shared_memory LANGUAGES C) +enable_testing() + +set(UMF_EXAMPLE_DIR "${CMAKE_SOURCE_DIR}/..") +list(APPEND CMAKE_MODULE_PATH "${UMF_EXAMPLE_DIR}/cmake") +message(STATUS "CMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}") + +find_package(PkgConfig) +pkg_check_modules(LIBUMF libumf) +if(NOT LIBUMF_FOUND) + find_package(LIBUMF REQUIRED libumf) +endif() + +pkg_check_modules(LIBHWLOC hwloc>=2.3.0) +if(NOT LIBHWLOC_FOUND) + find_package(LIBHWLOC 2.3.0 REQUIRED hwloc) +endif() + +include(FetchContent) + +set(CUDA_REPO "https://gitlab.com/nvidia/headers/cuda-individual/cudart.git") +set(CUDA_TAG cuda-12.5.1) + +message(STATUS "Fetching CUDA ${CUDA_TAG} from ${CUDA_REPO} ...") + +FetchContent_Declare( + cuda-headers + GIT_REPOSITORY ${CUDA_REPO} + GIT_TAG ${CUDA_TAG} + EXCLUDE_FROM_ALL) + +FetchContent_GetProperties(cuda-headers) +if(NOT cuda-headers_POPULATED) + FetchContent_Populate(cuda-headers) +endif() + +set(CUDA_INCLUDE_DIRS + ${cuda-headers_SOURCE_DIR} + CACHE PATH "Path to CUDA headers") +message(STATUS "CUDA include directory: ${CUDA_INCLUDE_DIRS}") +# build the example +set(EXAMPLE_NAME umf_example_cuda_shared_memory) +add_executable(${EXAMPLE_NAME} cuda_shared_memory.c) +target_include_directories( + ${EXAMPLE_NAME} PRIVATE ${CUDA_INCLUDE_DIRS} ${LIBUMF_INCLUDE_DIRS} + ${UMF_EXAMPLE_DIR}/common) +target_link_directories(${EXAMPLE_NAME} PRIVATE ${LIBUMF_LIBRARY_DIRS} + ${LIBHWLOC_LIBRARY_DIRS}) +target_link_options(${EXAMPLE_NAME} PRIVATE "-Wl,--start-group") +target_link_libraries(${EXAMPLE_NAME} PRIVATE stdc++ libdisjoint_pool.a cuda + ${LIBUMF_LIBRARIES}) + +# an optional part - adds a test of this example +add_test( + NAME ${EXAMPLE_NAME} + COMMAND ${EXAMPLE_NAME} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + +set_tests_properties(${EXAMPLE_NAME} PROPERTIES LABELS "example-standalone") + +if(LINUX) + # set LD_LIBRARY_PATH + set_property( + TEST ${EXAMPLE_NAME} + PROPERTY + ENVIRONMENT_MODIFICATION + "LD_LIBRARY_PATH=path_list_append:${LIBUMF_LIBRARY_DIRS};LD_LIBRARY_PATH=path_list_append:${LIBHWLOC_LIBRARY_DIRS}" + ) +endif() diff --git a/examples/cuda_shared_memory/cuda_shared_memory.c b/examples/cuda_shared_memory/cuda_shared_memory.c new file mode 100644 index 000000000..4b3093522 --- /dev/null +++ b/examples/cuda_shared_memory/cuda_shared_memory.c @@ -0,0 +1,115 @@ +/* + * + * Copyright (C) 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 + +int main(void) { + // A result object for storing UMF API result status + umf_result_t res; + + CUdevice cuDevice; + CUcontext cuContext; + int ret = 0; + + // Initialize the CUDA driver API + cuInit(0); + + // Get the handle to the first CUDA device + cuDeviceGet(&cuDevice, 0); + + // Create a context on the device + cuCtxCreate(&cuContext, 0, cuDevice); + + // Setup parameters for the CUDA memory provider. It will be used for + // allocating memory from CUDA devices. + cuda_memory_provider_params_t cu_memory_provider_params; + cu_memory_provider_params.cuda_context_handle = cuContext; + cu_memory_provider_params.cuda_device_handle = cuDevice; + // Set the memory type to shared to allow the memory to be accessed on both + // CPU and GPU. + cu_memory_provider_params.memory_type = UMF_MEMORY_TYPE_SHARED; + + // Create CUDA memory provider + umf_memory_provider_handle_t cu_memory_provider; + res = umfMemoryProviderCreate(umfCUDAMemoryProviderOps(), + &cu_memory_provider_params, + &cu_memory_provider); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to create a memory provider!\n"); + ret = -1; + goto cuda_destroy; + } + + printf("CUDA memory provider created at %p\n", (void *)cu_memory_provider); + + // Setup parameters for the Disjoint Pool. It will be used for managing the + // memory allocated using memory provider. + umf_disjoint_pool_params_t disjoint_memory_pool_params = + umfDisjointPoolParamsDefault(); + // Set the Slab Min Size to 64KB - the page size for GPU allocations + disjoint_memory_pool_params.SlabMinSize = 64 * 1024L; + // We would keep only single slab per each allocation bucket + disjoint_memory_pool_params.Capacity = 1; + // Set the maximum poolable size to 64KB - objects with size above this + // limit will not be stored/allocated from the pool. + disjoint_memory_pool_params.MaxPoolableSize = 64 * 1024L; + // Enable tracing + disjoint_memory_pool_params.PoolTrace = 1; + + // Create Disjoint Pool memory pool. + umf_memory_pool_handle_t cu_disjoint_memory_pool; + res = umfPoolCreate(umfDisjointPoolOps(), cu_memory_provider, + &disjoint_memory_pool_params, UMF_POOL_CREATE_FLAG_NONE, + &cu_disjoint_memory_pool); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to create a memory pool!\n"); + ret = -1; + goto memory_provider_destroy; + } + + printf("Disjoint Pool created at %p\n", (void *)cu_disjoint_memory_pool); + + // Allocate some memory from the pool + int *ptr = umfPoolMalloc(cu_disjoint_memory_pool, sizeof(int)); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to allocate memory from the memory pool!\n"); + ret = -1; + goto memory_pool_destroy; + } + + // Use allocated memory + *ptr = 1; + + // Free allocated memory + res = umfFree(ptr); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to free memory to the pool!\n"); + ret = -1; + goto memory_pool_destroy; + } + printf("Freed memory at %p\n", (void *)ptr); + + // Cleanup +memory_pool_destroy: + umfPoolDestroy(cu_disjoint_memory_pool); + +memory_provider_destroy: + umfMemoryProviderDestroy(cu_memory_provider); + +cuda_destroy: + ret = cuCtxDestroy(cuContext); + return ret; +} diff --git a/examples/gpu_shared_memory/CMakeLists.txt b/examples/level_zero_shared_memory/CMakeLists.txt similarity index 93% rename from examples/gpu_shared_memory/CMakeLists.txt rename to examples/level_zero_shared_memory/CMakeLists.txt index 659d22397..86d22941f 100644 --- a/examples/gpu_shared_memory/CMakeLists.txt +++ b/examples/level_zero_shared_memory/CMakeLists.txt @@ -3,7 +3,7 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception cmake_minimum_required(VERSION 3.14.0 FATAL_ERROR) -project(umf_example_gpu_shared_memory LANGUAGES C) +project(umf_example_level_zero_shared_memory LANGUAGES C) enable_testing() set(UMF_EXAMPLE_DIR "${CMAKE_SOURCE_DIR}/..") @@ -48,8 +48,8 @@ set(LEVEL_ZERO_INCLUDE_DIRS message(STATUS "Level Zero include directory: ${LEVEL_ZERO_INCLUDE_DIRS}") # build the example -set(EXAMPLE_NAME umf_example_gpu_shared_memory) -add_executable(${EXAMPLE_NAME} gpu_shared_memory.c) +set(EXAMPLE_NAME umf_example_level_zero_shared_memory) +add_executable(${EXAMPLE_NAME} level_zero_shared_memory.c) target_include_directories(${EXAMPLE_NAME} PRIVATE ${LIBUMF_INCLUDE_DIRS} ${UMF_EXAMPLE_DIR}/common) target_link_directories(${EXAMPLE_NAME} PRIVATE ${LIBUMF_LIBRARY_DIRS} diff --git a/examples/gpu_shared_memory/gpu_shared_memory.c b/examples/level_zero_shared_memory/level_zero_shared_memory.c similarity index 100% rename from examples/gpu_shared_memory/gpu_shared_memory.c rename to examples/level_zero_shared_memory/level_zero_shared_memory.c diff --git a/include/umf/memory_provider_gpu.h b/include/umf/memory_provider_gpu.h new file mode 100644 index 000000000..cc3cc3e3e --- /dev/null +++ b/include/umf/memory_provider_gpu.h @@ -0,0 +1,31 @@ +/* + * + * 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_MEMORY_PROVIDER_GPU_H +#define UMF_MEMORY_PROVIDER_GPU_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/// @brief USM memory allocation type +typedef enum umf_usm_memory_type_t { + UMF_MEMORY_TYPE_UNKNOWN = 0, ///< The memory pointed to is of unknown type + UMF_MEMORY_TYPE_HOST, ///< The memory pointed to is a host allocation + UMF_MEMORY_TYPE_DEVICE, ///< The memory pointed to is a device allocation + UMF_MEMORY_TYPE_SHARED, ///< The memory pointed to is a shared ownership allocation +} umf_usm_memory_type_t; + +#ifdef __cplusplus +} +#endif + +#endif /* UMF_MEMORY_PROVIDER_GPU_H */ diff --git a/include/umf/providers/provider_cuda.h b/include/umf/providers/provider_cuda.h new file mode 100644 index 000000000..2f6a07d81 --- /dev/null +++ b/include/umf/providers/provider_cuda.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 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_PROVIDER_CUDA_H +#define UMF_PROVIDER_CUDA_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/// @brief CUDA Memory Provider settings struct +typedef struct cuda_memory_provider_params_t { + void *cuda_context_handle; ///< Handle to the CUDA context + int cuda_device_handle; ///< Handle to the CUDA device + umf_usm_memory_type_t memory_type; ///< Allocation memory type +} cuda_memory_provider_params_t; + +umf_memory_provider_ops_t *umfCUDAMemoryProviderOps(void); + +#ifdef __cplusplus +} +#endif + +#endif /* UMF_PROVIDER_CUDA_H */ diff --git a/include/umf/providers/provider_level_zero.h b/include/umf/providers/provider_level_zero.h index 9685c8530..b3cc02851 100644 --- a/include/umf/providers/provider_level_zero.h +++ b/include/umf/providers/provider_level_zero.h @@ -8,22 +8,14 @@ #ifndef UMF_PROVIDER_LEVEL_ZERO_H #define UMF_PROVIDER_LEVEL_ZERO_H -#include "umf/memory_provider.h" +#include #ifdef __cplusplus extern "C" { #endif -typedef struct _ze_context_handle_t *ze_context_handle_t; typedef struct _ze_device_handle_t *ze_device_handle_t; - -/// @brief USM memory allocation type -typedef enum umf_usm_memory_type_t { - UMF_MEMORY_TYPE_UNKNOWN = 0, ///< The memory pointed to is of unknown type - UMF_MEMORY_TYPE_HOST, ///< The memory pointed to is a host allocation - UMF_MEMORY_TYPE_DEVICE, ///< The memory pointed to is a device allocation - UMF_MEMORY_TYPE_SHARED, ///< The memory pointed to is a shared ownership allocation -} umf_usm_memory_type_t; +typedef struct _ze_context_handle_t *ze_context_handle_t; /// @brief Level Zero Memory Provider settings struct typedef struct level_zero_memory_provider_params_t { diff --git a/scripts/docs_config/examples.rst b/scripts/docs_config/examples.rst index 1a76eea2a..0f88fcc40 100644 --- a/scripts/docs_config/examples.rst +++ b/scripts/docs_config/examples.rst @@ -111,8 +111,8 @@ Freeing memory is as easy as can be:: GPU shared memory ============================================================================== -You can find the full example code in the `examples/gpu_shared_memory/gpu_shared_memory.c`_ file -in the UMF repository. +You can find the full example code in the `examples/level_zero_shared_memory/level_zero_shared_memory.c`_ file +or `examples/cuda_shared_memory/cuda_shared_memory.c`_ file in the UMF repository. TODO @@ -209,7 +209,8 @@ function is called on the consumer side. The memory mappings on the consumer sid the :any:`umfCloseIPCHandle` function is called. .. _examples/basic/basic.c: https://github.com/oneapi-src/unified-memory-framework/blob/main/examples/basic/basic.c -.. _examples/gpu_shared_memory/gpu_shared_memory.c: https://github.com/oneapi-src/unified-memory-framework/blob/main/examples/gpu_shared_memory/gpu_shared_memory.c +.. _examples/level_zero_shared_memory/level_zero_shared_memory.c: https://github.com/oneapi-src/unified-memory-framework/blob/main/examples/level_zero_shared_memory/level_zero_shared_memory.c +.. _examples/cuda_shared_memory/cuda_shared_memory.c: https://github.com/oneapi-src/unified-memory-framework/blob/main/examples/cuda_shared_memory/cuda_shared_memory.c .. _examples/ipc_level_zero/ipc_level_zero.c: https://github.com/oneapi-src/unified-memory-framework/blob/main/examples/ipc_level_zero/ipc_level_zero.c .. _examples/custom_provider/file_provider.c: https://github.com/oneapi-src/unified-memory-framework/blob/main/examples/custom_provider/file_provider.c .. _examples/memspace: https://github.com/oneapi-src/unified-memory-framework/blob/main/examples/memspace/ diff --git a/scripts/qemu/run-build.sh b/scripts/qemu/run-build.sh index 5ed1e43da..666bd2200 100755 --- a/scripts/qemu/run-build.sh +++ b/scripts/qemu/run-build.sh @@ -15,6 +15,7 @@ cd build cmake .. \ -DCMAKE_BUILD_TYPE=Debug \ -DUMF_BUILD_LEVEL_ZERO_PROVIDER=ON \ + -DUMF_BUILD_CUDA_PROVIDER=ON \ -DUMF_FORMAT_CODE_STYLE=OFF \ -DUMF_DEVELOPER_MODE=ON \ -DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 845a178e3..cabe71b2d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -48,6 +48,32 @@ elseif(UMF_BUILD_LEVEL_ZERO_PROVIDER) message(STATUS "Level Zero include directory: ${LEVEL_ZERO_INCLUDE_DIRS}") endif() +if(UMF_BUILD_CUDA_PROVIDER) + include(FetchContent) + + set(CUDA_REPO + "https://gitlab.com/nvidia/headers/cuda-individual/cudart.git") + set(CUDA_TAG cuda-12.5.1) + + message(STATUS "Fetching CUDA ${CUDA_TAG} from ${CUDA_REPO} ...") + + FetchContent_Declare( + cuda-headers + GIT_REPOSITORY ${CUDA_REPO} + GIT_TAG ${CUDA_TAG} + EXCLUDE_FROM_ALL) + + FetchContent_GetProperties(cuda-headers) + if(NOT cuda-headers_POPULATED) + FetchContent_Populate(cuda-headers) + endif() + + set(CUDA_INCLUDE_DIRS + ${cuda-headers_SOURCE_DIR} + CACHE PATH "Path to CUDA headers") + message(STATUS "CUDA include directory: ${CUDA_INCLUDE_DIRS}") +endif() + add_subdirectory(utils) set(UMF_LIBS $) @@ -220,6 +246,12 @@ if(UMF_BUILD_LEVEL_ZERO_PROVIDER) "UMF_BUILD_LEVEL_ZERO_PROVIDER=1") endif() +if(UMF_BUILD_CUDA_PROVIDER) + target_sources(umf PRIVATE provider/provider_cuda.c) + set(UMF_COMPILE_DEFINITIONS ${UMF_COMPILE_DEFINITIONS} + "UMF_BUILD_CUDA_PROVIDER=1") +endif() + add_library(${PROJECT_NAME}::umf ALIAS umf) if(LIBHWLOC_INCLUDE_DIRS) @@ -230,6 +262,10 @@ if(LEVEL_ZERO_INCLUDE_DIRS) target_include_directories(umf PRIVATE ${LEVEL_ZERO_INCLUDE_DIRS}) endif() +if(CUDA_INCLUDE_DIRS) + target_include_directories(umf PRIVATE ${CUDA_INCLUDE_DIRS}) +endif() + target_include_directories( umf PUBLIC $ diff --git a/src/provider/provider_cuda.c b/src/provider/provider_cuda.c new file mode 100644 index 000000000..d72c47022 --- /dev/null +++ b/src/provider/provider_cuda.c @@ -0,0 +1,372 @@ +/* + * Copyright (C) 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 "cuda.h" + +#include "base_alloc_global.h" +#include "utils_assert.h" +#include "utils_common.h" +#include "utils_concurrency.h" +#include "utils_load_library.h" +#include "utils_log.h" +#include "utils_sanitizers.h" + +typedef struct cu_memory_provider_t { + CUcontext context; + CUdevice device; + umf_usm_memory_type_t memory_type; + size_t min_alignment; +} cu_memory_provider_t; + +typedef struct cu_ops_t { + CUresult (*cuMemGetAllocationGranularity)( + size_t *granularity, const CUmemAllocationProp *prop, + CUmemAllocationGranularity_flags option); + CUresult (*cuMemAlloc)(CUdeviceptr *dptr, size_t bytesize); + CUresult (*cuMemAllocHost)(void **pp, size_t bytesize); + CUresult (*cuMemAllocManaged)(CUdeviceptr *dptr, size_t bytesize, + unsigned int flags); + CUresult (*cuMemFree)(CUdeviceptr dptr); + CUresult (*cuMemFreeHost)(void *p); + + CUresult (*cuGetErrorName)(CUresult error, const char **pStr); + CUresult (*cuGetErrorString)(CUresult error, const char **pStr); +} cu_ops_t; + +static cu_ops_t g_cu_ops; +static UTIL_ONCE_FLAG cu_is_initialized = UTIL_ONCE_FLAG_INIT; +static bool Init_cu_global_state_failed; + +// forward decl needed for alloc +static umf_result_t cu_memory_provider_free(void *provider, void *ptr, + size_t bytes); + +#define TLS_MSG_BUF_LEN 1024 + +typedef struct cu_last_native_error_t { + CUresult native_error; + char msg_buff[TLS_MSG_BUF_LEN]; +} cu_last_native_error_t; + +static __TLS cu_last_native_error_t TLS_last_native_error; + +static void cu_store_last_native_error(CUresult native_error) { + TLS_last_native_error.native_error = native_error; +} + +static umf_result_t cu2umf_result(CUresult result) { + switch (result) { + case CUDA_SUCCESS: + return UMF_RESULT_SUCCESS; + case CUDA_ERROR_OUT_OF_MEMORY: + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + case CUDA_ERROR_INVALID_VALUE: + case CUDA_ERROR_INVALID_HANDLE: + case CUDA_ERROR_INVALID_RESOURCE_TYPE: + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + default: + cu_store_last_native_error(result); + return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; + } +} + +static void init_cu_global_state(void) { +#ifdef _WIN32 + const char *lib_name = "cudart.dll"; +#else + const char *lib_name = "libcuda.so"; +#endif + // check if CUDA shared library is already loaded + // we pass 0 as a handle to search the global symbol table + + // NOTE: some symbols defined in the lib have _vX postfixes - it is + // important to load the proper version of functions + *(void **)&g_cu_ops.cuMemGetAllocationGranularity = + util_get_symbol_addr(0, "cuMemGetAllocationGranularity", lib_name); + *(void **)&g_cu_ops.cuMemAlloc = + util_get_symbol_addr(0, "cuMemAlloc_v2", lib_name); + *(void **)&g_cu_ops.cuMemAllocHost = + util_get_symbol_addr(0, "cuMemAllocHost_v2", lib_name); + *(void **)&g_cu_ops.cuMemAllocManaged = + util_get_symbol_addr(0, "cuMemAllocManaged", lib_name); + *(void **)&g_cu_ops.cuMemFree = + util_get_symbol_addr(0, "cuMemFree_v2", lib_name); + *(void **)&g_cu_ops.cuMemFreeHost = + util_get_symbol_addr(0, "cuMemFreeHost", lib_name); + *(void **)&g_cu_ops.cuGetErrorName = + util_get_symbol_addr(0, "cuGetErrorName", lib_name); + *(void **)&g_cu_ops.cuGetErrorString = + util_get_symbol_addr(0, "cuGetErrorString", lib_name); + + if (!g_cu_ops.cuMemGetAllocationGranularity || !g_cu_ops.cuMemAlloc || + !g_cu_ops.cuMemAllocHost || !g_cu_ops.cuMemAllocManaged || + !g_cu_ops.cuMemFree || !g_cu_ops.cuMemFreeHost || + !g_cu_ops.cuGetErrorName || !g_cu_ops.cuGetErrorString) { + LOG_ERR("Required CUDA symbols not found."); + Init_cu_global_state_failed = true; + } +} + +static umf_result_t cu_memory_provider_initialize(void *params, + void **provider) { + if (provider == NULL || params == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + cuda_memory_provider_params_t *cu_params = + (cuda_memory_provider_params_t *)params; + + if (cu_params->memory_type == UMF_MEMORY_TYPE_UNKNOWN || + cu_params->memory_type > UMF_MEMORY_TYPE_SHARED) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + if (cu_params->cuda_context_handle == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + util_init_once(&cu_is_initialized, init_cu_global_state); + if (Init_cu_global_state_failed) { + LOG_ERR("Loading CUDA symbols failed"); + return UMF_RESULT_ERROR_UNKNOWN; + } + + cu_memory_provider_t *cu_provider = + umf_ba_global_alloc(sizeof(cu_memory_provider_t)); + if (!cu_provider) { + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + // CUDA alloc functions doesn't allow to provide user alignment - get the + // minimum one from the driver + size_t min_alignment = 0; + CUmemAllocationProp allocProps = {0}; + allocProps.location.type = CU_MEM_LOCATION_TYPE_DEVICE; + allocProps.type = CU_MEM_ALLOCATION_TYPE_PINNED; + allocProps.location.id = cu_provider->device; + CUresult cu_result = g_cu_ops.cuMemGetAllocationGranularity( + &min_alignment, &allocProps, CU_MEM_ALLOC_GRANULARITY_MINIMUM); + if (cu_result != CUDA_SUCCESS) { + umf_ba_global_free(cu_provider); + return cu2umf_result(cu_result); + } + + cu_provider->context = cu_params->cuda_context_handle; + cu_provider->device = cu_params->cuda_device_handle; + cu_provider->memory_type = cu_params->memory_type; + cu_provider->min_alignment = min_alignment; + + *provider = cu_provider; + + return UMF_RESULT_SUCCESS; +} + +static void cu_memory_provider_finalize(void *provider) { + if (provider == NULL) { + ASSERT(0); + return; + } + + umf_ba_global_free(provider); +} + +static umf_result_t cu_memory_provider_alloc(void *provider, size_t size, + size_t alignment, + void **resultPtr) { + if (provider == NULL || resultPtr == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + cu_memory_provider_t *cu_provider = (cu_memory_provider_t *)provider; + + if (alignment > cu_provider->min_alignment) { + // alignment of CUDA allocations is controlled by the CUDA driver - + // currently UMF doesn't support alignment larger than default + return UMF_RESULT_ERROR_NOT_SUPPORTED; + } + + CUresult cu_result = CUDA_SUCCESS; + switch (cu_provider->memory_type) { + case UMF_MEMORY_TYPE_HOST: { + cu_result = g_cu_ops.cuMemAllocHost(resultPtr, size); + break; + } + case UMF_MEMORY_TYPE_DEVICE: { + cu_result = g_cu_ops.cuMemAlloc((CUdeviceptr *)resultPtr, size); + break; + } + case UMF_MEMORY_TYPE_SHARED: { + cu_result = g_cu_ops.cuMemAllocManaged((CUdeviceptr *)resultPtr, size, + CU_MEM_ATTACH_GLOBAL); + break; + } + default: + // this shouldn't happen as we check the memory_type settings during + // the initialization + LOG_ERR("unsupported USM memory type"); + return UMF_RESULT_ERROR_UNKNOWN; + } + + // check the alignment + if (alignment > 0 && ((uintptr_t)(*resultPtr) % alignment) != 0) { + cu_memory_provider_free(provider, *resultPtr, size); + LOG_ERR("unsupported alignment size"); + return UMF_RESULT_ERROR_INVALID_ALIGNMENT; + } + + return cu2umf_result(cu_result); +} + +static umf_result_t cu_memory_provider_free(void *provider, void *ptr, + size_t bytes) { + (void)bytes; + + if (provider == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + if (ptr == NULL) { + return UMF_RESULT_SUCCESS; + } + + cu_memory_provider_t *cu_provider = (cu_memory_provider_t *)provider; + + CUresult cu_result = CUDA_SUCCESS; + switch (cu_provider->memory_type) { + case UMF_MEMORY_TYPE_HOST: { + cu_result = g_cu_ops.cuMemFreeHost(ptr); + break; + } + case UMF_MEMORY_TYPE_SHARED: + case UMF_MEMORY_TYPE_DEVICE: { + cu_result = g_cu_ops.cuMemFree((CUdeviceptr)ptr); + break; + } + default: + // this shouldn't happen as we check the memory_type settings during + // the initialization + LOG_ERR("unsupported USM memory type"); + return UMF_RESULT_ERROR_UNKNOWN; + } + + return cu2umf_result(cu_result); +} + +static void cu_memory_provider_get_last_native_error(void *provider, + const char **ppMessage, + int32_t *pError) { + (void)provider; + + if (ppMessage == NULL || pError == NULL) { + ASSERT(0); + return; + } + + const char *error_name = 0; + const char *error_string = 0; + g_cu_ops.cuGetErrorName(TLS_last_native_error.native_error, &error_name); + g_cu_ops.cuGetErrorString(TLS_last_native_error.native_error, + &error_string); + + size_t buf_size = 0; + strncpy(TLS_last_native_error.msg_buff, error_name, TLS_MSG_BUF_LEN - 1); + buf_size = strlen(TLS_last_native_error.msg_buff); + + strncat(TLS_last_native_error.msg_buff, " - ", + TLS_MSG_BUF_LEN - buf_size - 1); + buf_size = strlen(TLS_last_native_error.msg_buff); + + strncat(TLS_last_native_error.msg_buff, error_string, + TLS_MSG_BUF_LEN - buf_size - 1); + + *pError = TLS_last_native_error.native_error; + *ppMessage = TLS_last_native_error.msg_buff; +} + +static umf_result_t cu_memory_provider_get_min_page_size(void *provider, + void *ptr, + size_t *pageSize) { + (void)ptr; + + if (provider == NULL || pageSize == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + cu_memory_provider_t *cu_provider = (cu_memory_provider_t *)provider; + + CUmemAllocationProp allocProps = {0}; + allocProps.location.type = CU_MEM_LOCATION_TYPE_DEVICE; + allocProps.type = CU_MEM_ALLOCATION_TYPE_PINNED; + allocProps.location.id = cu_provider->device; + + CUresult cu_result = g_cu_ops.cuMemGetAllocationGranularity( + pageSize, &allocProps, CU_MEM_ALLOC_GRANULARITY_MINIMUM); + + return cu2umf_result(cu_result); +} + +static umf_result_t +cu_memory_provider_get_recommended_page_size(void *provider, size_t size, + size_t *pageSize) { + (void)size; + + if (provider == NULL || pageSize == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + cu_memory_provider_t *cu_provider = (cu_memory_provider_t *)provider; + + CUmemAllocationProp allocProps = {0}; + allocProps.location.type = CU_MEM_LOCATION_TYPE_DEVICE; + allocProps.type = CU_MEM_ALLOCATION_TYPE_PINNED; + allocProps.location.id = cu_provider->device; + + CUresult cu_result = g_cu_ops.cuMemGetAllocationGranularity( + pageSize, &allocProps, CU_MEM_ALLOC_GRANULARITY_RECOMMENDED); + + return cu2umf_result(cu_result); +} + +static const char *cu_memory_provider_get_name(void *provider) { + (void)provider; + return "CUDA"; +} + +static struct umf_memory_provider_ops_t UMF_CUDA_MEMORY_PROVIDER_OPS = { + .version = UMF_VERSION_CURRENT, + .initialize = cu_memory_provider_initialize, + .finalize = cu_memory_provider_finalize, + .alloc = cu_memory_provider_alloc, + .free = cu_memory_provider_free, + .get_last_native_error = cu_memory_provider_get_last_native_error, + .get_recommended_page_size = cu_memory_provider_get_recommended_page_size, + .get_min_page_size = cu_memory_provider_get_min_page_size, + .get_name = cu_memory_provider_get_name, + // TODO + /* + .ext.purge_lazy = cu_memory_provider_purge_lazy, + .ext.purge_force = cu_memory_provider_purge_force, + .ext.allocation_merge = cu_memory_provider_allocation_merge, + .ext.allocation_split = cu_memory_provider_allocation_split, + .ipc.get_ipc_handle_size = cu_memory_provider_get_ipc_handle_size, + .ipc.get_ipc_handle = cu_memory_provider_get_ipc_handle, + .ipc.put_ipc_handle = cu_memory_provider_put_ipc_handle, + .ipc.open_ipc_handle = cu_memory_provider_open_ipc_handle, + .ipc.close_ipc_handle = cu_memory_provider_close_ipc_handle, + */ +}; + +umf_memory_provider_ops_t *umfCUDAMemoryProviderOps(void) { + return &UMF_CUDA_MEMORY_PROVIDER_OPS; +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f486b6e15..f2e1a4561 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -266,6 +266,36 @@ if(UMF_BUILD_GPU_TESTS AND UMF_BUILD_LEVEL_ZERO_PROVIDER) PRIVATE ${LEVEL_ZERO_INCLUDE_DIRS}) endif() +if(UMF_BUILD_GPU_TESTS AND UMF_BUILD_CUDA_PROVIDER) + if(UMF_CUDA_ENABLED) + # we have two test binaries here that use the same sources, but differ + # in the way they are linked to the CUDA (statically or at runtime using + # dlopen) + add_umf_test( + NAME provider_cuda + SRCS providers/provider_cuda.cpp providers/cuda_helpers.cpp + LIBS ${UMF_UTILS_FOR_TEST} cuda) + target_include_directories(umf_test-provider_cuda + PRIVATE ${CUDA_INCLUDE_DIRS}) + target_link_directories(umf_test-provider_cuda PRIVATE + ${CUDA_LIBRARY_DIRS}) + + add_umf_test( + NAME provider_cuda_dlopen + SRCS providers/provider_cuda.cpp providers/cuda_helpers.cpp + LIBS ${UMF_UTILS_FOR_TEST}) + target_compile_definitions(umf_test-provider_cuda_dlopen + PUBLIC USE_DLOPEN=1) + target_include_directories(umf_test-provider_cuda_dlopen + PRIVATE ${CUDA_INCLUDE_DIRS}) + else() + message( + STATUS + "CUDA provdier tests requires CUDA libraries to be installed and added to the default library search path - skipping" + ) + endif() +endif() + if(UMF_BUILD_SHARED_LIBRARY) # if build as shared library, ba symbols won't be visible in tests set(BA_SOURCES_FOR_TEST ${BA_SOURCES}) @@ -392,6 +422,8 @@ if(LINUX) add_umf_ipc_test(TEST ipc_file_prov) endif() + # TODO add IPC tests for CUDA + if(UMF_BUILD_GPU_TESTS AND UMF_BUILD_LEVEL_ZERO_PROVIDER) build_umf_test( NAME @@ -462,15 +494,29 @@ if(LINUX if(UMF_BUILD_GPU_EXAMPLES AND UMF_BUILD_LIBUMF_POOL_DISJOINT AND UMF_BUILD_LEVEL_ZERO_PROVIDER) - set(EXAMPLES ${EXAMPLES} gpu_shared_memory) + set(EXAMPLES ${EXAMPLES} level_zero_shared_memory) else() message( STATUS - "GPU shared memory example requires UMF_BUILD_GPU_EXAMPLES, " + "GPU level zero shared memory example requires UMF_BUILD_GPU_EXAMPLES, " "UMF_BUILD_LEVEL_ZERO_PROVIDER and UMF_BUILD_LIBUMF_POOL_DISJOINT " "to be turned ON - skipping") endif() + if(UMF_BUILD_GPU_EXAMPLES + AND UMF_BUILD_LIBUMF_POOL_DISJOINT + AND UMF_BUILD_CUDA_PROVIDER + AND UMF_CUDA_ENABLED) + set(EXAMPLES ${EXAMPLES} cuda_shared_memory) + else() + message( + STATUS + "GPU CUDA shared memory example requires UMF_BUILD_GPU_EXAMPLES, " + "UMF_BUILD_CUDA_PROVIDER, UMF_BUILD_LIBUMF_POOL_DISJOINT " + "to be turned ON and installed CUDA libraries - skipping") + endif() + + # TODO add IPC examples for CUDA if(UMF_BUILD_GPU_EXAMPLES AND UMF_BUILD_LIBUMF_POOL_DISJOINT AND UMF_BUILD_LEVEL_ZERO_PROVIDER) diff --git a/test/providers/cuda_helpers.cpp b/test/providers/cuda_helpers.cpp new file mode 100644 index 000000000..08584a45f --- /dev/null +++ b/test/providers/cuda_helpers.cpp @@ -0,0 +1,291 @@ +/* + * Copyright (C) 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 "cuda_helpers.h" +#include "utils_concurrency.h" +#include "utils_load_library.h" + +struct libcu_ops { + CUresult (*cuInit)(unsigned int flags); + CUresult (*cuCtxCreate)(CUcontext *pctx, unsigned int flags, CUdevice dev); + CUresult (*cuCtxDestroy)(CUcontext ctx); + CUresult (*cuDeviceGet)(CUdevice *device, int ordinal); + CUresult (*cuMemAlloc)(CUdeviceptr *dptr, size_t size); + CUresult (*cuMemFree)(CUdeviceptr dptr); + CUresult (*cuMemAllocHost)(void **pp, size_t size); + CUresult (*cuMemAllocManaged)(CUdeviceptr *dptr, size_t bytesize, + unsigned int flags); + CUresult (*cuMemFreeHost)(void *p); + CUresult (*cuMemsetD32)(CUdeviceptr dstDevice, unsigned int pattern, + size_t size); + CUresult (*cuMemcpyDtoH)(void *dstHost, CUdeviceptr srcDevice, size_t size); + CUresult (*cuPointerGetAttributes)(unsigned int numAttributes, + CUpointer_attribute *attributes, + void **data, CUdeviceptr ptr); +} libcu_ops; + +#if USE_DLOPEN +struct DlHandleCloser { + void operator()(void *dlHandle) { + if (dlHandle) { + util_close_library(dlHandle); + } + } +}; + +std::unique_ptr cuDlHandle = nullptr; +int InitCUDAOps() { +#ifdef _WIN32 + const char *lib_name = "cudart.dll"; +#else + const char *lib_name = "libcuda.so"; +#endif + // CUDA symbols + // NOTE that we use UMF_UTIL_OPEN_LIBRARY_GLOBAL which add all loaded + // symbols to the global symbol table. + cuDlHandle = std::unique_ptr( + util_open_library(lib_name, UMF_UTIL_OPEN_LIBRARY_GLOBAL)); + + // NOTE: some symbols defined in the lib have _vX postfixes - this is + // important to load the proper version of functions + *(void **)&libcu_ops.cuInit = + util_get_symbol_addr(cuDlHandle.get(), "cuInit", lib_name); + if (libcu_ops.cuInit == nullptr) { + fprintf(stderr, "cuInit symbol not found in %s\n", lib_name); + return -1; + } + *(void **)&libcu_ops.cuCtxCreate = + util_get_symbol_addr(cuDlHandle.get(), "cuCtxCreate_v2", lib_name); + if (libcu_ops.cuCtxCreate == nullptr) { + fprintf(stderr, "cuCtxCreate_v2 symbol not found in %s\n", lib_name); + return -1; + } + *(void **)&libcu_ops.cuCtxDestroy = + util_get_symbol_addr(cuDlHandle.get(), "cuCtxDestroy_v2", lib_name); + if (libcu_ops.cuCtxDestroy == nullptr) { + fprintf(stderr, "cuCtxDestroy symbol not found in %s\n", lib_name); + return -1; + } + *(void **)&libcu_ops.cuDeviceGet = + util_get_symbol_addr(cuDlHandle.get(), "cuDeviceGet", lib_name); + if (libcu_ops.cuDeviceGet == nullptr) { + fprintf(stderr, "cuDeviceGet symbol not found in %s\n", lib_name); + return -1; + } + *(void **)&libcu_ops.cuMemAlloc = + util_get_symbol_addr(cuDlHandle.get(), "cuMemAlloc_v2", lib_name); + if (libcu_ops.cuMemAlloc == nullptr) { + fprintf(stderr, "cuMemAlloc_v2 symbol not found in %s\n", lib_name); + return -1; + } + *(void **)&libcu_ops.cuMemFree = + util_get_symbol_addr(cuDlHandle.get(), "cuMemFree_v2", lib_name); + if (libcu_ops.cuMemFree == nullptr) { + fprintf(stderr, "cuMemFree_v2 symbol not found in %s\n", lib_name); + return -1; + } + *(void **)&libcu_ops.cuMemAllocHost = + util_get_symbol_addr(cuDlHandle.get(), "cuMemAllocHost_v2", lib_name); + if (libcu_ops.cuMemAllocHost == nullptr) { + fprintf(stderr, "cuMemAllocHost_v2 symbol not found in %s\n", lib_name); + return -1; + } + *(void **)&libcu_ops.cuMemAllocManaged = + util_get_symbol_addr(cuDlHandle.get(), "cuMemAllocManaged", lib_name); + if (libcu_ops.cuMemAllocManaged == nullptr) { + fprintf(stderr, "cuMemAllocManaged symbol not found in %s\n", lib_name); + return -1; + } + *(void **)&libcu_ops.cuMemFreeHost = + util_get_symbol_addr(cuDlHandle.get(), "cuMemFreeHost", lib_name); + if (libcu_ops.cuMemFreeHost == nullptr) { + fprintf(stderr, "cuMemFreeHost symbol not found in %s\n", lib_name); + return -1; + } + *(void **)&libcu_ops.cuMemsetD32 = + util_get_symbol_addr(cuDlHandle.get(), "cuMemsetD32_v2", lib_name); + if (libcu_ops.cuMemsetD32 == nullptr) { + fprintf(stderr, "cuMemsetD32_v2 symbol not found in %s\n", lib_name); + return -1; + } + *(void **)&libcu_ops.cuMemcpyDtoH = + util_get_symbol_addr(cuDlHandle.get(), "cuMemcpyDtoH_v2", lib_name); + if (libcu_ops.cuMemcpyDtoH == nullptr) { + fprintf(stderr, "cuMemcpyDtoH_v2 symbol not found in %s\n", lib_name); + return -1; + } + *(void **)&libcu_ops.cuPointerGetAttributes = util_get_symbol_addr( + cuDlHandle.get(), "cuPointerGetAttributes", lib_name); + if (libcu_ops.cuPointerGetAttributes == nullptr) { + fprintf(stderr, "cuPointerGetAttributes symbol not found in %s\n", + lib_name); + return -1; + } + + return 0; +} + +#else // USE_DLOPEN +int InitCUDAOps() { + // CUDA is linked statically but we prepare ops structure to + // make test code consistent + libcu_ops.cuInit = cuInit; + libcu_ops.cuCtxCreate = cuCtxCreate; + libcu_ops.cuCtxDestroy = cuCtxDestroy; + libcu_ops.cuDeviceGet = cuDeviceGet; + libcu_ops.cuMemAlloc = cuMemAlloc; + libcu_ops.cuMemAllocHost = cuMemAllocHost; + libcu_ops.cuMemAllocManaged = cuMemAllocManaged; + libcu_ops.cuMemFree = cuMemFree; + libcu_ops.cuMemFreeHost = cuMemFreeHost; + libcu_ops.cuMemsetD32 = cuMemsetD32; + libcu_ops.cuMemcpyDtoH = cuMemcpyDtoH; + libcu_ops.cuPointerGetAttributes = cuPointerGetAttributes; + + return 0; +} +#endif // USE_DLOPEN + +static int init_cuda_lib(void) { + CUresult result = libcu_ops.cuInit(0); + if (result != CUDA_SUCCESS) { + return -1; + } + return 0; +} + +int cuda_fill(CUcontext context, CUdevice device, void *ptr, size_t size, + const void *pattern, size_t pattern_size) { + + (void)context; + (void)device; + (void)pattern_size; + + // TODO support patterns > sizeof(unsigned int) + if (pattern_size > sizeof(unsigned int)) { + fprintf(stderr, "patterns > sizeof(unsigned int) are unsupported!\n"); + return -1; + } + + int ret = 0; + CUresult res = + libcu_ops.cuMemsetD32((CUdeviceptr)ptr, *(unsigned int *)pattern, + size / sizeof(unsigned int)); + if (res != CUDA_SUCCESS) { + fprintf(stderr, "cuMemsetD32() failed!\n"); + return -1; + } + + return ret; +} + +int cuda_copy(CUcontext context, CUdevice device, void *dst_ptr, void *src_ptr, + size_t size) { + (void)context; + (void)device; + + int ret = 0; + CUresult res = libcu_ops.cuMemcpyDtoH(dst_ptr, (CUdeviceptr)src_ptr, size); + if (res != CUDA_SUCCESS) { + fprintf(stderr, "cuMemcpyDtoH() failed!\n"); + return -1; + } + + return ret; +} + +umf_usm_memory_type_t get_mem_type(CUcontext context, void *ptr) { + + (void)context; + + unsigned int managed; + unsigned int type; + void *attrib_vals[2] = {&managed, &type}; + CUpointer_attribute attribs[2] = {CU_POINTER_ATTRIBUTE_IS_MANAGED, + CU_POINTER_ATTRIBUTE_MEMORY_TYPE}; + + CUresult res = libcu_ops.cuPointerGetAttributes(2, attribs, attrib_vals, + (CUdeviceptr)ptr); + if (res != CUDA_SUCCESS) { + fprintf(stderr, "cuPointerGetAttributes() failed!\n"); + return UMF_MEMORY_TYPE_UNKNOWN; + } + + if (type == CU_MEMORYTYPE_DEVICE && managed == 0) { + return UMF_MEMORY_TYPE_DEVICE; + } else if (type == CU_MEMORYTYPE_DEVICE && managed == 1) { + return UMF_MEMORY_TYPE_SHARED; + } else if (type == CU_MEMORYTYPE_HOST) { + return UMF_MEMORY_TYPE_HOST; + } + + return UMF_MEMORY_TYPE_UNKNOWN; +} + +UTIL_ONCE_FLAG cuda_init_flag; +int InitResult; +void init_cuda_once() { + InitResult = InitCUDAOps(); + if (InitResult != 0) { + return; + } + InitResult = init_cuda_lib(); +} + +int init_cuda() { + util_init_once(&cuda_init_flag, init_cuda_once); + + return InitResult; +} + +cuda_memory_provider_params_t +create_cuda_prov_params(umf_usm_memory_type_t memory_type) { + cuda_memory_provider_params_t params = {NULL, 0, UMF_MEMORY_TYPE_UNKNOWN}; + int ret = -1; + + ret = init_cuda(); + if (ret != 0) { + // Return empty params. Test will be skipped. + return params; + } + + // Get the first CUDA device + CUdevice cuDevice = -1; + CUresult res = libcu_ops.cuDeviceGet(&cuDevice, 0); + if (res != CUDA_SUCCESS || cuDevice < 0) { + // Return empty params. Test will be skipped. + return params; + } + + // Create a CUDA context + CUcontext cuContext = nullptr; + res = libcu_ops.cuCtxCreate(&cuContext, 0, cuDevice); + if (res != CUDA_SUCCESS || cuContext == nullptr) { + // Return empty params. Test will be skipped. + return params; + } + + params.cuda_context_handle = cuContext; + params.cuda_device_handle = cuDevice; + params.memory_type = memory_type; + + return params; +} + +int destroy_context(CUcontext context) { + CUresult res = libcu_ops.cuCtxDestroy(context); + if (res != CUDA_SUCCESS) { + fprintf(stderr, "cuCtxDestroy() failed!\n"); + return -1; + } + + return 0; +} diff --git a/test/providers/cuda_helpers.h b/test/providers/cuda_helpers.h new file mode 100644 index 000000000..3227fc9c5 --- /dev/null +++ b/test/providers/cuda_helpers.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 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 TEST_COMMON_CUDA_HELPERS_HPP +#define TEST_COMMON_CUDA_HELPERS_HPP + +#include + +#include "cuda.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int destroy_context(CUcontext context); + +int cuda_fill(CUcontext context, CUdevice device, void *ptr, size_t size, + const void *pattern, size_t pattern_size); + +int cuda_copy(CUcontext context, CUdevice device, void *dst_ptr, void *src_ptr, + size_t size); + +umf_usm_memory_type_t get_mem_type(CUcontext context, void *ptr); + +cuda_memory_provider_params_t +create_cuda_prov_params(umf_usm_memory_type_t memory_type); + +#ifdef __cplusplus +} +#endif + +#endif // TEST_COMMON_CUDA_HELPERS_HPP diff --git a/test/providers/provider_cuda.cpp b/test/providers/provider_cuda.cpp new file mode 100644 index 000000000..f563d45c8 --- /dev/null +++ b/test/providers/provider_cuda.cpp @@ -0,0 +1,189 @@ +// Copyright (C) 2024 Intel Corporation +// Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#ifdef _WIN32 +//workaround for std::numeric_limits on windows +#define NOMINMAX +#endif + +#include + +#include + +#include "cuda_helpers.h" +#include "ipcFixtures.hpp" +#include "pool.hpp" +#include "utils_load_library.h" + +using umf_test::test; +using namespace umf_test; + +class CUDAMemoryAccessor : public MemoryAccessor { + public: + void init(CUcontext hContext, CUdevice hDevice) { + hDevice_ = hDevice; + hContext_ = hContext; + } + + void fill(void *ptr, size_t size, const void *pattern, + size_t pattern_size) { + ASSERT_NE(hContext_, nullptr); + ASSERT_GE(hDevice_, -1); + ASSERT_NE(ptr, nullptr); + + int ret = + cuda_fill(hContext_, hDevice_, ptr, size, pattern, pattern_size); + ASSERT_EQ(ret, 0); + } + + void copy(void *dst_ptr, void *src_ptr, size_t size) { + ASSERT_NE(hContext_, nullptr); + ASSERT_GE(hDevice_, -1); + ASSERT_NE(dst_ptr, nullptr); + ASSERT_NE(src_ptr, nullptr); + + int ret = cuda_copy(hContext_, hDevice_, dst_ptr, src_ptr, size); + ASSERT_EQ(ret, 0); + } + + private: + CUdevice hDevice_; + CUcontext hContext_; +}; + +using CUDAProviderTestParams = + std::tuple; + +struct umfCUDAProviderTest + : umf_test::test, + ::testing::WithParamInterface { + + void SetUp() override { + test::SetUp(); + + auto [memory_type, accessor] = this->GetParam(); + params = create_cuda_prov_params(memory_type); + memAccessor = accessor; + if (memory_type == UMF_MEMORY_TYPE_DEVICE) { + ((CUDAMemoryAccessor *)memAccessor) + ->init((CUcontext)params.cuda_context_handle, + params.cuda_device_handle); + } + } + + void TearDown() override { + if (params.cuda_context_handle) { + int ret = destroy_context((CUcontext)params.cuda_context_handle); + ASSERT_EQ(ret, 0); + } + test::TearDown(); + } + + cuda_memory_provider_params_t params; + MemoryAccessor *memAccessor = nullptr; +}; + +TEST_P(umfCUDAProviderTest, basic) { + const size_t size = 1024 * 8; + const uint32_t pattern = 0xAB; + + // create CUDA provider + umf_memory_provider_handle_t provider = nullptr; + umf_result_t umf_result = + umfMemoryProviderCreate(umfCUDAMemoryProviderOps(), ¶ms, &provider); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(provider, nullptr); + + size_t pageSize = 0; + umf_result = umfMemoryProviderGetMinPageSize(provider, 0, &pageSize); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_GE(pageSize, 0); + + umf_result = + umfMemoryProviderGetRecommendedPageSize(provider, 0, &pageSize); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_GE(pageSize, 0); + + void *ptr = nullptr; + umf_result = umfMemoryProviderAlloc(provider, size, 128, &ptr); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(ptr, nullptr); + + // use the allocated memory - fill it with a 0xAB pattern + memAccessor->fill(ptr, size, &pattern, sizeof(pattern)); + + umf_usm_memory_type_t memoryTypeActual = + get_mem_type((CUcontext)params.cuda_context_handle, ptr); + ASSERT_EQ(memoryTypeActual, params.memory_type); + + // check if the pattern was successfully applied + uint32_t *hostMemory = (uint32_t *)calloc(1, size); + memAccessor->copy(hostMemory, ptr, size); + for (size_t i = 0; i < size / sizeof(int); i++) { + ASSERT_EQ(hostMemory[i], pattern); + } + free(hostMemory); + + umf_result = umfMemoryProviderFree(provider, ptr, size); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umfMemoryProviderDestroy(provider); +} + +TEST_P(umfCUDAProviderTest, allocInvalidSize) { + // create CUDA provider + umf_memory_provider_handle_t provider = nullptr; + umf_result_t umf_result = + umfMemoryProviderCreate(umfCUDAMemoryProviderOps(), ¶ms, &provider); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(provider, nullptr); + + // try to alloc (int)-1 + void *ptr = nullptr; + umf_result = umfMemoryProviderAlloc(provider, -1, 0, &ptr); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY); + + // in case of size == 0 we should got INVALID_ARGUMENT error + // NOTE: this is invalid only for the DEVICE or SHARED allocations + if (params.memory_type != UMF_MEMORY_TYPE_HOST) { + umf_result = umfMemoryProviderAlloc(provider, 0, 0, &ptr); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); + } + + // destroy context and try to alloc some memory + destroy_context((CUcontext)params.cuda_context_handle); + params.cuda_context_handle = 0; + umf_result = umfMemoryProviderAlloc(provider, 128, 0, &ptr); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC); + + const char *message; + int32_t error; + umfMemoryProviderGetLastNativeError(provider, &message, &error); + ASSERT_EQ(error, CUDA_ERROR_INVALID_CONTEXT); + const char *expected_message = + "CUDA_ERROR_INVALID_CONTEXT - invalid device context"; + ASSERT_EQ(strncmp(message, expected_message, strlen(expected_message)), 0); +} + +// TODO add tests that mixes CUDA Memory Provider and Disjoint Pool + +CUDAMemoryAccessor cuAccessor; +HostMemoryAccessor hostAccessor; + +INSTANTIATE_TEST_SUITE_P( + umfCUDAProviderTestSuite, umfCUDAProviderTest, + ::testing::Values( + CUDAProviderTestParams{UMF_MEMORY_TYPE_DEVICE, &cuAccessor}, + CUDAProviderTestParams{UMF_MEMORY_TYPE_SHARED, &hostAccessor}, + CUDAProviderTestParams{UMF_MEMORY_TYPE_HOST, &hostAccessor})); + +// TODO: add IPC API +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(umfIpcTest); +/* +INSTANTIATE_TEST_SUITE_P(umfCUDAProviderTestSuite, umfIpcTest, + ::testing::Values(ipcTestParams{ + umfProxyPoolOps(), nullptr, + umfCUDAMemoryProviderOps(), + &cuParams_device_memory, &l0Accessor})); +*/ From dedfde13d4e90777b011b32ef4fb36bafbfa6f6a Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Thu, 19 Sep 2024 10:46:49 +0200 Subject: [PATCH 105/352] Fix error handling in file_open_ipc_handle() Fix error handling in file_open_ipc_handle(). It fixes the Coverity issue no. 469239. Signed-off-by: Lukasz Dorau --- src/provider/provider_file_memory.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/provider/provider_file_memory.c b/src/provider/provider_file_memory.c index fd8d04371..e366a1553 100644 --- a/src/provider/provider_file_memory.c +++ b/src/provider/provider_file_memory.c @@ -582,7 +582,7 @@ static umf_result_t file_open_ipc_handle(void *provider, void *providerIpcData, } fd = os_file_open(file_ipc_data->path); - if (fd <= 0) { + if (fd == -1) { LOG_PERR("opening the file to be mapped (%s) failed", file_ipc_data->path); return UMF_RESULT_ERROR_INVALID_ARGUMENT; From 883a548cf7114785082ad6934ee081f7b19f81c0 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Thu, 19 Sep 2024 10:58:57 +0200 Subject: [PATCH 106/352] Remove unneeded headers Remove unneeded headers: - provider_devdax_memory_internal.h - provider_file_memory_internal.h Signed-off-by: Lukasz Dorau --- src/provider/provider_devdax_memory.c | 10 +++- .../provider_devdax_memory_internal.h | 32 ------------ src/provider/provider_file_memory.c | 27 +++++++++- src/provider/provider_file_memory_internal.h | 50 ------------------- 4 files changed, 35 insertions(+), 84 deletions(-) delete mode 100644 src/provider/provider_devdax_memory_internal.h delete mode 100644 src/provider/provider_file_memory_internal.h diff --git a/src/provider/provider_devdax_memory.c b/src/provider/provider_devdax_memory.c index 8d1c4bc9e..0507463c0 100644 --- a/src/provider/provider_devdax_memory.c +++ b/src/provider/provider_devdax_memory.c @@ -14,7 +14,6 @@ #include #include "base_alloc_global.h" -#include "provider_devdax_memory_internal.h" #include "provider_os_memory_internal.h" #include "utils_common.h" #include "utils_concurrency.h" @@ -28,6 +27,15 @@ #define TLS_MSG_BUF_LEN 1024 +typedef struct devdax_memory_provider_t { + char path[PATH_MAX]; // a path to the device DAX + size_t size; // size of the file used for memory mapping + void *base; // base address of memory mapping + size_t offset; // offset in the file used for memory mapping + os_mutex_t lock; // lock of ptr and offset + unsigned protection; // combination of OS-specific protection flags +} devdax_memory_provider_t; + typedef struct devdax_last_native_error_t { int32_t native_error; int errno_value; diff --git a/src/provider/provider_devdax_memory_internal.h b/src/provider/provider_devdax_memory_internal.h deleted file mode 100644 index 981089e08..000000000 --- a/src/provider/provider_devdax_memory_internal.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 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_DEVDAX_MEMORY_PROVIDER_INTERNAL_H -#define UMF_DEVDAX_MEMORY_PROVIDER_INTERNAL_H - -#include - -#include "utils_concurrency.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct devdax_memory_provider_t { - char path[PATH_MAX]; // a path to the device DAX - size_t size; // size of the file used for memory mapping - void *base; // base address of memory mapping - size_t offset; // offset in the file used for memory mapping - os_mutex_t lock; // lock of ptr and offset - unsigned protection; // combination of OS-specific protection flags -} devdax_memory_provider_t; - -#ifdef __cplusplus -} -#endif - -#endif /* UMF_DEVDAX_MEMORY_PROVIDER_INTERNAL_H */ diff --git a/src/provider/provider_file_memory.c b/src/provider/provider_file_memory.c index fd8d04371..b67d52d32 100644 --- a/src/provider/provider_file_memory.c +++ b/src/provider/provider_file_memory.c @@ -15,7 +15,6 @@ #include "base_alloc_global.h" #include "critnib.h" -#include "provider_file_memory_internal.h" #include "provider_os_memory_internal.h" #include "utils_common.h" #include "utils_concurrency.h" @@ -27,6 +26,32 @@ #define TLS_MSG_BUF_LEN 1024 +typedef struct file_memory_provider_t { + os_mutex_t lock; // lock for file parameters (size and offsets) + + char path[PATH_MAX]; // a path to the file + int fd; // file descriptor for memory mapping + size_t size_fd; // size of the file used for memory mappings + size_t offset_fd; // offset in the file used for memory mappings + + void *base_mmap; // base address of the current memory mapping + size_t size_mmap; // size of the current memory mapping + size_t offset_mmap; // data offset in the current memory mapping + + unsigned protection; // combination of OS-specific protection flags + unsigned visibility; // memory visibility mode + size_t page_size; // minimum page size + + critnib *mmaps; // a critnib map storing mmap mappings (addr, size) + + // A critnib map storing (ptr, fd_offset + 1) pairs. We add 1 to fd_offset + // in order to be able to store fd_offset equal 0, because + // critnib_get() returns value or NULL, so a value cannot equal 0. + // It is needed mainly in the get_ipc_handle and open_ipc_handle hooks + // to mmap a specific part of a file. + critnib *fd_offset_map; +} file_memory_provider_t; + typedef struct file_last_native_error_t { int32_t native_error; int errno_value; diff --git a/src/provider/provider_file_memory_internal.h b/src/provider/provider_file_memory_internal.h deleted file mode 100644 index ce77719d5..000000000 --- a/src/provider/provider_file_memory_internal.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 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_FILE_MEMORY_PROVIDER_INTERNAL_H -#define UMF_FILE_MEMORY_PROVIDER_INTERNAL_H - -#include - -#include "critnib.h" -#include "utils_concurrency.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct file_memory_provider_t { - os_mutex_t lock; // lock for file parameters (size and offsets) - - char path[PATH_MAX]; // a path to the file - int fd; // file descriptor for memory mapping - size_t size_fd; // size of the file used for memory mappings - size_t offset_fd; // offset in the file used for memory mappings - - void *base_mmap; // base address of the current memory mapping - size_t size_mmap; // size of the current memory mapping - size_t offset_mmap; // data offset in the current memory mapping - - unsigned protection; // combination of OS-specific protection flags - unsigned visibility; // memory visibility mode - size_t page_size; // minimum page size - - critnib *mmaps; // a critnib map storing mmap mappings (addr, size) - - // A critnib map storing (ptr, fd_offset + 1) pairs. We add 1 to fd_offset - // in order to be able to store fd_offset equal 0, because - // critnib_get() returns value or NULL, so a value cannot equal 0. - // It is needed mainly in the get_ipc_handle and open_ipc_handle hooks - // to mmap a specific part of a file. - critnib *fd_offset_map; -} file_memory_provider_t; - -#ifdef __cplusplus -} -#endif - -#endif /* UMF_FILE_MEMORY_PROVIDER_INTERNAL_H */ From b1e1edb4e05e27c4311bcfe5441b958d1e69c3a4 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Fri, 20 Sep 2024 08:53:46 +0200 Subject: [PATCH 107/352] Move all common functions to utils_common Move all common functions to utils_common and rename them to utils_* Signed-off-by: Lukasz Dorau --- include/umf/memory_provider.h | 17 ++ include/umf/providers/provider_os_memory.h | 17 -- src/CMakeLists.txt | 18 +- src/provider/provider_devdax_memory.c | 31 ++- src/provider/provider_file_memory.c | 37 ++-- src/provider/provider_os_memory.c | 82 +++----- src/provider/provider_os_memory_internal.h | 51 ----- src/provider/provider_os_memory_posix.c | 180 ----------------- src/provider/provider_os_memory_windows.c | 190 ------------------ src/utils/CMakeLists.txt | 11 + src/utils/utils_common.c | 25 +++ src/utils/utils_common.h | 51 +++++ .../utils_linux_common.c} | 128 ++++++------ .../utils_macosx_common.c} | 57 +++++- src/utils/utils_posix_common.c | 162 +++++++++++++++ src/utils/utils_windows_common.c | 165 +++++++++++++++ test/CMakeLists.txt | 23 ++- test/utils/utils_log.cpp | 2 + 18 files changed, 636 insertions(+), 611 deletions(-) delete mode 100644 src/provider/provider_os_memory_posix.c delete mode 100644 src/provider/provider_os_memory_windows.c rename src/{provider/provider_os_memory_linux.c => utils/utils_linux_common.c} (82%) rename src/{provider/provider_os_memory_macosx.c => utils/utils_macosx_common.c} (56%) diff --git a/include/umf/memory_provider.h b/include/umf/memory_provider.h index cec8edbcf..fb217a0e8 100644 --- a/include/umf/memory_provider.h +++ b/include/umf/memory_provider.h @@ -17,6 +17,23 @@ extern "C" { #endif +/// @brief Memory visibility mode +typedef enum umf_memory_visibility_t { + UMF_MEM_MAP_PRIVATE = 1, ///< private memory mapping + UMF_MEM_MAP_SHARED, ///< shared memory mapping (supported on Linux only) +} umf_memory_visibility_t; + +/// @brief Protection of the memory allocations +typedef enum umf_mem_protection_flags_t { + UMF_PROTECTION_NONE = (1 << 0), ///< Memory allocations can not be accessed + UMF_PROTECTION_READ = (1 << 1), ///< Memory allocations can be read. + UMF_PROTECTION_WRITE = (1 << 2), ///< Memory allocations can be written. + UMF_PROTECTION_EXEC = (1 << 3), ///< Memory allocations can be executed. + /// @cond + UMF_PROTECTION_MAX // must be the last one + /// @endcond +} umf_mem_protection_flags_t; + /// @brief A struct containing memory provider specific set of functions typedef struct umf_memory_provider_t *umf_memory_provider_handle_t; diff --git a/include/umf/providers/provider_os_memory.h b/include/umf/providers/provider_os_memory.h index 1d4494547..e175aaa6a 100644 --- a/include/umf/providers/provider_os_memory.h +++ b/include/umf/providers/provider_os_memory.h @@ -18,23 +18,6 @@ extern "C" { #define UMF_OS_RESULTS_START_FROM 1000 /// @endcond -/// @brief Protection of the memory allocations -typedef enum umf_mem_protection_flags_t { - UMF_PROTECTION_NONE = (1 << 0), ///< Memory allocations can not be accessed - UMF_PROTECTION_READ = (1 << 1), ///< Memory allocations can be read. - UMF_PROTECTION_WRITE = (1 << 2), ///< Memory allocations can be written. - UMF_PROTECTION_EXEC = (1 << 3), ///< Memory allocations can be executed. - /// @cond - UMF_PROTECTION_MAX // must be the last one - /// @endcond -} umf_mem_protection_flags_t; - -/// @brief Memory visibility mode -typedef enum umf_memory_visibility_t { - UMF_MEM_MAP_PRIVATE = 1, ///< private memory mapping - UMF_MEM_MAP_SHARED, ///< shared memory mapping (supported on Linux only) -} umf_memory_visibility_t; - /// @brief Memory binding mode /// Specifies how memory is bound to NUMA nodes on systems that support NUMA. /// Not every mode is supported on every system. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cabe71b2d..9eb883cfa 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -130,7 +130,6 @@ set(UMF_SOURCES_COMMON_LINUX_MACOSX provider/provider_devdax_memory.c provider/provider_file_memory.c provider/provider_os_memory.c - provider/provider_os_memory_posix.c memtargets/memtarget_numa.c memspaces/memspace_numa.c memspaces/memspace_host_all.c @@ -139,17 +138,14 @@ set(UMF_SOURCES_COMMON_LINUX_MACOSX memspaces/memspace_lowest_latency.c) if(NOT UMF_DISABLE_HWLOC) - set(UMF_SOURCES_LINUX - ${UMF_SOURCES_LINUX} ${UMF_SOURCES_COMMON_LINUX_MACOSX} - provider/provider_os_memory_linux.c) + set(UMF_SOURCES_LINUX ${UMF_SOURCES_LINUX} + ${UMF_SOURCES_COMMON_LINUX_MACOSX}) - set(UMF_SOURCES_MACOSX - ${UMF_SOURCES_MACOSX} ${UMF_SOURCES_COMMON_LINUX_MACOSX} - provider/provider_os_memory_macosx.c) + set(UMF_SOURCES_MACOSX ${UMF_SOURCES_MACOSX} + ${UMF_SOURCES_COMMON_LINUX_MACOSX}) - set(UMF_SOURCES_WINDOWS - ${UMF_SOURCES_WINDOWS} provider/provider_os_memory.c - provider/provider_os_memory_windows.c) + set(UMF_SOURCES_WINDOWS ${UMF_SOURCES_WINDOWS} + provider/provider_os_memory.c) set(UMF_LIBS ${UMF_LIBS} ${LIBHWLOC_LIBRARIES}) @@ -180,7 +176,7 @@ set(UMF_PRIVATE_LIBRARY_DIRS ${UMF_PRIVATE_LIBRARY_DIRS} if(LINUX) set(UMF_SOURCES ${UMF_SOURCES} ${UMF_SOURCES_LINUX}) - set(UMF_LIBS ${UMF_LIBS} dl rt) # librt for shm_open() + set(UMF_LIBS ${UMF_LIBS} dl) elseif(WINDOWS) set(UMF_SOURCES ${UMF_SOURCES} ${UMF_SOURCES_WINDOWS}) diff --git a/src/provider/provider_devdax_memory.c b/src/provider/provider_devdax_memory.c index 0507463c0..321c68d9c 100644 --- a/src/provider/provider_devdax_memory.c +++ b/src/provider/provider_devdax_memory.c @@ -14,7 +14,6 @@ #include #include "base_alloc_global.h" -#include "provider_os_memory_internal.h" #include "utils_common.h" #include "utils_concurrency.h" #include "utils_log.h" @@ -76,8 +75,8 @@ devdax_translate_params(umf_devdax_memory_provider_params_t *in_params, devdax_memory_provider_t *provider) { umf_result_t result; - result = os_translate_mem_protection_flags(in_params->protection, - &provider->protection); + result = utils_translate_mem_protection_flags(in_params->protection, + &provider->protection); if (result != UMF_RESULT_SUCCESS) { LOG_ERR("incorrect memory protection flags: %u", in_params->protection); return result; @@ -124,15 +123,15 @@ static umf_result_t devdax_initialize(void *params, void **provider) { goto err_free_devdax_provider; } - int fd = os_devdax_open(in_params->path); + int fd = utils_devdax_open(in_params->path); if (fd == -1) { LOG_ERR("cannot open the device DAX: %s", in_params->path); ret = UMF_RESULT_ERROR_INVALID_ARGUMENT; goto err_free_devdax_provider; } - devdax_provider->base = os_devdax_mmap(NULL, devdax_provider->size, - devdax_provider->protection, fd); + devdax_provider->base = utils_devdax_mmap(NULL, devdax_provider->size, + devdax_provider->protection, fd); utils_close_fd(fd); if (devdax_provider->base == NULL) { LOG_PDEBUG("devdax memory mapping failed (path=%s, size=%zu)", @@ -155,7 +154,7 @@ static umf_result_t devdax_initialize(void *params, void **provider) { return UMF_RESULT_SUCCESS; err_unmap_devdax: - os_munmap(devdax_provider->base, devdax_provider->size); + utils_munmap(devdax_provider->base, devdax_provider->size); err_free_devdax_provider: umf_ba_global_free(devdax_provider); return ret; @@ -169,7 +168,7 @@ static void devdax_finalize(void *provider) { devdax_memory_provider_t *devdax_provider = provider; util_mutex_destroy_not_free(&devdax_provider->lock); - os_munmap(devdax_provider->base, devdax_provider->size); + utils_munmap(devdax_provider->base, devdax_provider->size); umf_ba_global_free(devdax_provider); } @@ -281,8 +280,8 @@ static void devdax_get_last_native_error(void *provider, const char **ppMessage, memcpy(TLS_last_native_error.msg_buff + pos, msg, len + 1); pos += len; - os_strerror(TLS_last_native_error.errno_value, - TLS_last_native_error.msg_buff + pos, TLS_MSG_BUF_LEN - pos); + utils_strerror(TLS_last_native_error.errno_value, + TLS_last_native_error.msg_buff + pos, TLS_MSG_BUF_LEN - pos); *ppMessage = TLS_last_native_error.msg_buff; } @@ -296,7 +295,7 @@ static umf_result_t devdax_get_recommended_page_size(void *provider, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - *page_size = os_get_page_size(); + *page_size = util_get_page_size(); return UMF_RESULT_SUCCESS; } @@ -324,7 +323,7 @@ static umf_result_t devdax_purge_force(void *provider, void *ptr, size_t size) { } errno = 0; - if (os_purge(ptr, size, UMF_PURGE_FORCE)) { + if (utils_purge(ptr, size, UMF_PURGE_FORCE)) { devdax_store_last_native_error( UMF_DEVDAX_RESULT_ERROR_PURGE_FORCE_FAILED, errno); LOG_PERR("force purging failed"); @@ -453,14 +452,14 @@ static umf_result_t devdax_open_ipc_handle(void *provider, } umf_result_t ret = UMF_RESULT_SUCCESS; - int fd = os_devdax_open(devdax_provider->path); + int fd = utils_devdax_open(devdax_provider->path); if (fd == -1) { LOG_PERR("opening a devdax (%s) failed", devdax_provider->path); return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - char *base = os_devdax_mmap(NULL, devdax_provider->size, - devdax_provider->protection, fd); + char *base = utils_devdax_mmap(NULL, devdax_provider->size, + devdax_provider->protection, fd); if (base == NULL) { devdax_store_last_native_error(UMF_DEVDAX_RESULT_ERROR_ALLOC_FAILED, errno); @@ -493,7 +492,7 @@ static umf_result_t devdax_close_ipc_handle(void *provider, void *ptr, (devdax_memory_provider_t *)provider; errno = 0; - int ret = os_munmap(devdax_provider->base, devdax_provider->size); + int ret = utils_munmap(devdax_provider->base, devdax_provider->size); // ignore error when size == 0 if (ret && (size > 0)) { devdax_store_last_native_error(UMF_DEVDAX_RESULT_ERROR_FREE_FAILED, diff --git a/src/provider/provider_file_memory.c b/src/provider/provider_file_memory.c index b42be4526..0936daaf0 100644 --- a/src/provider/provider_file_memory.c +++ b/src/provider/provider_file_memory.c @@ -15,7 +15,6 @@ #include "base_alloc_global.h" #include "critnib.h" -#include "provider_os_memory_internal.h" #include "utils_common.h" #include "utils_concurrency.h" #include "utils_log.h" @@ -88,15 +87,15 @@ file_translate_params(umf_file_memory_provider_params_t *in_params, file_memory_provider_t *provider) { umf_result_t result; - result = os_translate_mem_protection_flags(in_params->protection, - &provider->protection); + result = utils_translate_mem_protection_flags(in_params->protection, + &provider->protection); if (result != UMF_RESULT_SUCCESS) { LOG_ERR("incorrect memory protection flags: %u", in_params->protection); return result; } - result = os_translate_mem_visibility_flag(in_params->visibility, - &provider->visibility); + result = utils_translate_mem_visibility_flag(in_params->visibility, + &provider->visibility); if (result != UMF_RESULT_SUCCESS) { LOG_ERR("incorrect memory visibility flag: %u", in_params->visibility); return result; @@ -115,7 +114,7 @@ static umf_result_t file_initialize(void *params, void **provider) { umf_file_memory_provider_params_t *in_params = (umf_file_memory_provider_params_t *)params; - size_t page_size = os_get_page_size(); + size_t page_size = util_get_page_size(); if (in_params->path == NULL) { LOG_ERR("file path is missing"); @@ -141,14 +140,14 @@ static umf_result_t file_initialize(void *params, void **provider) { goto err_free_file_provider; } - file_provider->fd = os_file_open_or_create(in_params->path); + file_provider->fd = utils_file_open_or_create(in_params->path); if (file_provider->fd == -1) { LOG_ERR("cannot open the file: %s", in_params->path); ret = UMF_RESULT_ERROR_INVALID_ARGUMENT; goto err_free_file_provider; } - if (os_set_file_size(file_provider->fd, page_size)) { + if (utils_set_file_size(file_provider->fd, page_size)) { LOG_ERR("cannot set size of the file: %s", in_params->path); ret = UMF_RESULT_ERROR_UNKNOWN; goto err_close_fd; @@ -207,7 +206,7 @@ static void file_finalize(void *provider) { void *rvalue = NULL; while (1 == critnib_find(file_provider->mmaps, key, FIND_G, &rkey, &rvalue)) { - os_munmap((void *)rkey, (size_t)rvalue); + utils_munmap((void *)rkey, (size_t)rvalue); critnib_remove(file_provider->mmaps, rkey); key = rkey; } @@ -248,7 +247,7 @@ static umf_result_t file_mmap_aligned(file_memory_provider_t *file_provider, } if (offset_fd + extended_size > size_fd) { - if (os_fallocate(fd, offset_fd, extended_size)) { + if (utils_fallocate(fd, offset_fd, extended_size)) { LOG_ERR("cannot grow the file size from %zu to %zu", size_fd, offset_fd + extended_size); return UMF_RESULT_ERROR_UNKNOWN; @@ -262,7 +261,7 @@ static umf_result_t file_mmap_aligned(file_memory_provider_t *file_provider, ASSERT_IS_ALIGNED(extended_size, page_size); ASSERT_IS_ALIGNED(offset_fd, page_size); - void *ptr = os_mmap(NULL, extended_size, prot, flag, fd, offset_fd); + void *ptr = utils_mmap(NULL, extended_size, prot, flag, fd, offset_fd); if (ptr == NULL) { LOG_PERR("memory mapping failed"); return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; @@ -423,8 +422,8 @@ static void file_get_last_native_error(void *provider, const char **ppMessage, memcpy(TLS_last_native_error.msg_buff + pos, msg, len + 1); pos += len; - os_strerror(TLS_last_native_error.errno_value, - TLS_last_native_error.msg_buff + pos, TLS_MSG_BUF_LEN - pos); + utils_strerror(TLS_last_native_error.errno_value, + TLS_last_native_error.msg_buff + pos, TLS_MSG_BUF_LEN - pos); *ppMessage = TLS_last_native_error.msg_buff; } @@ -437,7 +436,7 @@ static umf_result_t file_get_recommended_page_size(void *provider, size_t size, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - *page_size = os_get_page_size(); + *page_size = util_get_page_size(); return UMF_RESULT_SUCCESS; } @@ -465,7 +464,7 @@ static umf_result_t file_purge_force(void *provider, void *ptr, size_t size) { } errno = 0; - if (os_purge(ptr, size, UMF_PURGE_FORCE)) { + if (utils_purge(ptr, size, UMF_PURGE_FORCE)) { file_store_last_native_error(UMF_FILE_RESULT_ERROR_PURGE_FORCE_FAILED, errno); LOG_PERR("force purging failed"); @@ -606,15 +605,15 @@ static umf_result_t file_open_ipc_handle(void *provider, void *providerIpcData, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - fd = os_file_open(file_ipc_data->path); + fd = utils_file_open(file_ipc_data->path); if (fd == -1) { LOG_PERR("opening the file to be mapped (%s) failed", file_ipc_data->path); return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - *ptr = os_mmap(NULL, file_ipc_data->size, file_provider->protection, - file_provider->visibility, fd, file_ipc_data->offset_fd); + *ptr = utils_mmap(NULL, file_ipc_data->size, file_provider->protection, + file_provider->visibility, fd, file_ipc_data->offset_fd); (void)utils_close_fd(fd); if (*ptr == NULL) { file_store_last_native_error(UMF_FILE_RESULT_ERROR_ALLOC_FAILED, errno); @@ -632,7 +631,7 @@ static umf_result_t file_close_ipc_handle(void *provider, void *ptr, } errno = 0; - int ret = os_munmap(ptr, size); + int ret = utils_munmap(ptr, size); // ignore error when size == 0 if (ret && (size > 0)) { file_store_last_native_error(UMF_FILE_RESULT_ERROR_FREE_FAILED, errno); diff --git a/src/provider/provider_os_memory.c b/src/provider/provider_os_memory.c index 00251e53b..fe2505dce 100644 --- a/src/provider/provider_os_memory.c +++ b/src/provider/provider_os_memory.c @@ -134,31 +134,6 @@ static umf_result_t initialize_nodeset(os_memory_provider_t *os_provider, return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; } -umf_result_t os_translate_flags(unsigned in_flags, unsigned max, - umf_result_t (*translate_flag)(unsigned, - unsigned *), - unsigned *out_flags) { - unsigned out_f = 0; - for (unsigned n = 1; n < max; n <<= 1) { - if (in_flags & n) { - unsigned flag; - umf_result_t result = translate_flag(n, &flag); - if (result != UMF_RESULT_SUCCESS) { - return result; - } - out_f |= flag; - in_flags &= ~n; // clear this bit - } - } - - if (in_flags != 0) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - - *out_flags = out_f; - return UMF_RESULT_SUCCESS; -} - static umf_result_t validate_numa_mode(umf_numa_mode_t mode, int nodemaskEmpty) { switch (mode) { @@ -289,7 +264,7 @@ create_fd_for_mmap(umf_os_memory_provider_params_t *in_params, /* create a new shared memory file */ provider->fd = - os_shm_create(in_params->shm_name, provider->max_size_fd); + utils_shm_create(in_params->shm_name, provider->max_size_fd); if (provider->fd == -1) { LOG_ERR("creating a shared memory file /dev/shm/%s of size %zu for " "memory mapping failed", @@ -304,14 +279,14 @@ create_fd_for_mmap(umf_os_memory_provider_params_t *in_params, return UMF_RESULT_SUCCESS; } - provider->fd = os_create_anonymous_fd(); + provider->fd = utils_create_anonymous_fd(); if (provider->fd <= 0) { LOG_ERR( "creating an anonymous file descriptor for memory mapping failed"); return UMF_RESULT_ERROR_UNKNOWN; } - int ret = os_set_file_size(provider->fd, provider->max_size_fd); + int ret = utils_set_file_size(provider->fd, provider->max_size_fd); if (ret) { LOG_ERR("setting size %zu of an anonymous file failed", provider->max_size_fd); @@ -413,15 +388,15 @@ static umf_result_t translate_params(umf_os_memory_provider_params_t *in_params, os_memory_provider_t *provider) { umf_result_t result; - result = os_translate_mem_protection_flags(in_params->protection, - &provider->protection); + result = utils_translate_mem_protection_flags(in_params->protection, + &provider->protection); if (result != UMF_RESULT_SUCCESS) { LOG_ERR("incorrect memory protection flags: %u", in_params->protection); return result; } - result = os_translate_mem_visibility_flag(in_params->visibility, - &provider->visibility); + result = utils_translate_mem_visibility_flag(in_params->visibility, + &provider->visibility); if (result != UMF_RESULT_SUCCESS) { LOG_ERR("incorrect memory visibility flag: %u", in_params->visibility); return result; @@ -634,11 +609,11 @@ static inline void assert_is_page_aligned(uintptr_t ptr, size_t page_size) { (void)page_size; // unused in Release build } -static int os_mmap_aligned(void *hint_addr, size_t length, size_t alignment, - size_t page_size, int prot, int flag, int fd, - size_t max_fd_size, os_mutex_t *lock_fd, - void **out_addr, size_t *fd_size, - size_t *fd_offset) { +static int utils_mmap_aligned(void *hint_addr, size_t length, size_t alignment, + size_t page_size, int prot, int flag, int fd, + size_t max_fd_size, os_mutex_t *lock_fd, + void **out_addr, size_t *fd_size, + size_t *fd_offset) { assert(out_addr); size_t extended_length = length; @@ -670,7 +645,8 @@ static int os_mmap_aligned(void *hint_addr, size_t length, size_t alignment, util_mutex_unlock(lock_fd); } - void *ptr = os_mmap(hint_addr, extended_length, prot, flag, fd, *fd_offset); + void *ptr = + utils_mmap(hint_addr, extended_length, prot, flag, fd, *fd_offset); if (ptr == NULL) { LOG_PDEBUG("memory mapping failed"); return -1; @@ -689,7 +665,7 @@ static int os_mmap_aligned(void *hint_addr, size_t length, size_t alignment, size_t head_len = aligned_addr - addr; if (head_len > 0) { - os_munmap(ptr, head_len); + utils_munmap(ptr, head_len); } // tail address has to page-aligned @@ -703,7 +679,7 @@ static int os_mmap_aligned(void *hint_addr, size_t length, size_t alignment, size_t tail_len = (addr + extended_length) - tail; if (tail_len > 0) { - os_munmap((void *)tail, tail_len); + utils_munmap((void *)tail, tail_len); } *out_addr = (void *)aligned_addr; @@ -917,7 +893,7 @@ static umf_result_t os_alloc(void *provider, size_t size, size_t alignment, void *addr = NULL; errno = 0; - ret = os_mmap_aligned( + ret = utils_mmap_aligned( NULL, size, alignment, page_size, os_provider->protection, os_provider->visibility, os_provider->fd, os_provider->max_size_fd, &os_provider->lock_fd, &addr, &os_provider->size_fd, &fd_offset); @@ -984,7 +960,7 @@ static umf_result_t os_alloc(void *provider, size_t size, size_t alignment, return UMF_RESULT_SUCCESS; err_unmap: - (void)os_munmap(addr, size); + (void)utils_munmap(addr, size); return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; } @@ -1004,7 +980,7 @@ static umf_result_t os_free(void *provider, void *ptr, size_t size) { } errno = 0; - int ret = os_munmap(ptr, size); + int ret = utils_munmap(ptr, size); if (ret) { os_store_last_native_error(UMF_OS_RESULT_ERROR_FREE_FAILED, errno); LOG_PERR("memory deallocation failed"); @@ -1044,8 +1020,8 @@ static void os_get_last_native_error(void *provider, const char **ppMessage, memcpy(TLS_last_native_error.msg_buff + pos, msg, len + 1); pos += len; - os_strerror(TLS_last_native_error.errno_value, - TLS_last_native_error.msg_buff + pos, TLS_MSG_BUF_LEN - pos); + utils_strerror(TLS_last_native_error.errno_value, + TLS_last_native_error.msg_buff + pos, TLS_MSG_BUF_LEN - pos); *ppMessage = TLS_last_native_error.msg_buff; } @@ -1058,7 +1034,7 @@ static umf_result_t os_get_recommended_page_size(void *provider, size_t size, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - *page_size = os_get_page_size(); + *page_size = util_get_page_size(); return UMF_RESULT_SUCCESS; } @@ -1076,7 +1052,7 @@ static umf_result_t os_purge_lazy(void *provider, void *ptr, size_t size) { } errno = 0; - if (os_purge(ptr, size, UMF_PURGE_LAZY)) { + if (utils_purge(ptr, size, UMF_PURGE_LAZY)) { os_store_last_native_error(UMF_OS_RESULT_ERROR_PURGE_LAZY_FAILED, errno); LOG_PERR("lazy purging failed"); @@ -1092,7 +1068,7 @@ static umf_result_t os_purge_force(void *provider, void *ptr, size_t size) { } errno = 0; - if (os_purge(ptr, size, UMF_PURGE_FORCE)) { + if (utils_purge(ptr, size, UMF_PURGE_FORCE)) { os_store_last_native_error(UMF_OS_RESULT_ERROR_PURGE_FORCE_FAILED, errno); LOG_PERR("force purging failed"); @@ -1258,13 +1234,13 @@ static umf_result_t os_open_ipc_handle(void *provider, void *providerIpcData, int fd; if (os_provider->shm_name[0]) { - fd = os_shm_open(os_provider->shm_name); + fd = utils_shm_open(os_provider->shm_name); if (fd <= 0) { LOG_PERR("opening a shared memory file (%s) failed", os_provider->shm_name); return UMF_RESULT_ERROR_UNKNOWN; } - (void)os_shm_unlink(os_provider->shm_name); + (void)utils_shm_unlink(os_provider->shm_name); } else { umf_result_t umf_result = utils_duplicate_fd(os_ipc_data->pid, os_ipc_data->fd, &fd); @@ -1274,8 +1250,8 @@ static umf_result_t os_open_ipc_handle(void *provider, void *providerIpcData, } } - *ptr = os_mmap(NULL, os_ipc_data->size, os_provider->protection, - os_provider->visibility, fd, os_ipc_data->fd_offset); + *ptr = utils_mmap(NULL, os_ipc_data->size, os_provider->protection, + os_provider->visibility, fd, os_ipc_data->fd_offset); if (*ptr == NULL) { os_store_last_native_error(UMF_OS_RESULT_ERROR_ALLOC_FAILED, errno); LOG_PERR("memory mapping failed"); @@ -1294,7 +1270,7 @@ static umf_result_t os_close_ipc_handle(void *provider, void *ptr, } errno = 0; - int ret = os_munmap(ptr, size); + int ret = utils_munmap(ptr, size); // ignore error when size == 0 if (ret && (size > 0)) { os_store_last_native_error(UMF_OS_RESULT_ERROR_FREE_FAILED, errno); diff --git a/src/provider/provider_os_memory_internal.h b/src/provider/provider_os_memory_internal.h index 54972686d..e01a3de75 100644 --- a/src/provider/provider_os_memory_internal.h +++ b/src/provider/provider_os_memory_internal.h @@ -26,11 +26,6 @@ extern "C" { #endif -typedef enum umf_purge_advise_t { - UMF_PURGE_LAZY, - UMF_PURGE_FORCE, -} umf_purge_advise_t; - typedef struct os_memory_provider_t { unsigned protection; // combination of OS-specific protection flags unsigned visibility; // memory visibility mode @@ -69,52 +64,6 @@ typedef struct os_memory_provider_t { hwloc_topology_t topo; } os_memory_provider_t; -umf_result_t os_translate_flags(unsigned in_flags, unsigned max, - umf_result_t (*translate_flag)(unsigned, - unsigned *), - unsigned *out_flags); - -umf_result_t os_translate_mem_protection_flags(unsigned in_protection, - unsigned *out_protection); - -umf_result_t os_translate_mem_visibility_flag(umf_memory_visibility_t in_flag, - unsigned *out_flag); - -int os_create_anonymous_fd(void); - -int os_shm_create(const char *shm_name, size_t size); - -int os_shm_open(const char *shm_name); - -int os_shm_unlink(const char *shm_name); - -size_t get_max_file_size(void); - -int os_get_file_size(int fd, size_t *size); - -int os_set_file_size(int fd, size_t size); - -void *os_mmap(void *hint_addr, size_t length, int prot, int flag, int fd, - size_t fd_offset); - -void *os_devdax_mmap(void *hint_addr, size_t length, int prot, int fd); - -int os_munmap(void *addr, size_t length); - -int os_purge(void *addr, size_t length, int advice); - -size_t os_get_page_size(void); - -void os_strerror(int errnum, char *buf, size_t buflen); - -int os_devdax_open(const char *path); - -int os_file_open(const char *path); - -int os_file_open_or_create(const char *path); - -int os_fallocate(int fd, long offset, long len); - #ifdef __cplusplus } #endif diff --git a/src/provider/provider_os_memory_posix.c b/src/provider/provider_os_memory_posix.c deleted file mode 100644 index 90348ebfa..000000000 --- a/src/provider/provider_os_memory_posix.c +++ /dev/null @@ -1,180 +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 -#include - -#include - -#include "provider_os_memory_internal.h" -#include "utils_log.h" -#include "utils_sanitizers.h" - -// maximum value of the off_t type -#define OFF_T_MAX \ - (sizeof(off_t) == sizeof(long long) \ - ? LLONG_MAX \ - : (sizeof(off_t) == sizeof(long) ? LONG_MAX : INT_MAX)) - -umf_result_t os_translate_mem_protection_one_flag(unsigned in_protection, - unsigned *out_protection) { - switch (in_protection) { - case UMF_PROTECTION_NONE: - *out_protection = PROT_NONE; - return UMF_RESULT_SUCCESS; - case UMF_PROTECTION_READ: - *out_protection = PROT_READ; - return UMF_RESULT_SUCCESS; - case UMF_PROTECTION_WRITE: - *out_protection = PROT_WRITE; - return UMF_RESULT_SUCCESS; - case UMF_PROTECTION_EXEC: - *out_protection = PROT_EXEC; - return UMF_RESULT_SUCCESS; - } - return UMF_RESULT_ERROR_INVALID_ARGUMENT; -} - -size_t get_max_file_size(void) { return OFF_T_MAX; } - -umf_result_t os_translate_mem_protection_flags(unsigned in_protection, - unsigned *out_protection) { - // translate protection - combination of 'umf_mem_protection_flags_t' flags - return os_translate_flags(in_protection, UMF_PROTECTION_MAX, - os_translate_mem_protection_one_flag, - out_protection); -} - -static int os_translate_purge_advise(umf_purge_advise_t advise) { - switch (advise) { - case UMF_PURGE_LAZY: - return MADV_FREE; - case UMF_PURGE_FORCE: - return MADV_DONTNEED; - } - return -1; -} - -void *os_mmap(void *hint_addr, size_t length, int prot, int flag, int fd, - size_t fd_offset) { - fd = (fd == 0) ? -1 : fd; - if (fd == -1) { - // MAP_ANONYMOUS - the mapping is not backed by any file - flag |= MAP_ANONYMOUS; - } - - void *ptr = mmap(hint_addr, length, prot, flag, fd, fd_offset); - if (ptr == MAP_FAILED) { - return NULL; - } - // this should be unnecessary but pairs of mmap/munmap do not reset - // asan's user-poisoning flags, leading to invalid error reports - // Bug 81619: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81619 - utils_annotate_memory_defined(ptr, length); - return ptr; -} - -int os_munmap(void *addr, size_t length) { - // this should be unnecessary but pairs of mmap/munmap do not reset - // asan's user-poisoning flags, leading to invalid error reports - // Bug 81619: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81619 - utils_annotate_memory_defined(addr, length); - return munmap(addr, length); -} - -size_t os_get_page_size(void) { return sysconf(_SC_PAGE_SIZE); } - -int os_purge(void *addr, size_t length, int advice) { - return madvise(addr, length, os_translate_purge_advise(advice)); -} - -void os_strerror(int errnum, char *buf, size_t buflen) { -// 'strerror_r' implementation is XSI-compliant (returns 0 on success) -#if (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE - if (strerror_r(errnum, buf, buflen)) { -#else // 'strerror_r' implementation is GNU-specific (returns pointer on success) - if (!strerror_r(errnum, buf, buflen)) { -#endif - LOG_PERR("Retrieving error code description failed"); - } -} - -// open a devdax -int os_devdax_open(const char *path) { - if (path == NULL) { - LOG_ERR("empty path"); - return -1; - } - - if (strstr(path, "/dev/dax") != path) { - LOG_ERR("path of the file \"%s\" does not start with \"/dev/dax\"", - path); - return -1; - } - - int fd = open(path, O_RDWR); - if (fd == -1) { - LOG_PERR("cannot open the file: %s", path); - return -1; - } - - struct stat statbuf; - int ret = stat(path, &statbuf); - if (ret) { - LOG_PERR("stat(%s) failed", path); - close(fd); - return -1; - } - - if (!S_ISCHR(statbuf.st_mode)) { - LOG_ERR("file %s is not a character device", path); - close(fd); - return -1; - } - - return fd; -} - -// open a file -int os_file_open(const char *path) { - if (!path) { - LOG_ERR("empty path"); - return -1; - } - - int fd = open(path, O_RDWR); - if (fd == -1) { - LOG_PERR("cannot open the file: %s", path); - } - - return fd; -} - -// open a file or create -int os_file_open_or_create(const char *path) { - if (!path) { - LOG_ERR("empty path"); - return -1; - } - - int fd = open(path, O_RDWR | O_CREAT, 0600); - if (fd == -1) { - LOG_PERR("cannot open/create the file: %s", path); - return -1; - } - - LOG_DEBUG("opened/created the file: %s", path); - - return fd; -} diff --git a/src/provider/provider_os_memory_windows.c b/src/provider/provider_os_memory_windows.c deleted file mode 100644 index b295c75f1..000000000 --- a/src/provider/provider_os_memory_windows.c +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (C) 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 "utils_concurrency.h" -#include "utils_log.h" - -static UTIL_ONCE_FLAG Page_size_is_initialized = UTIL_ONCE_FLAG_INIT; -static size_t Page_size; - -umf_result_t os_translate_mem_protection_flags(unsigned in_protection, - unsigned *out_protection) { - switch (in_protection) { - case UMF_PROTECTION_NONE: - *out_protection = PAGE_NOACCESS; - return UMF_RESULT_SUCCESS; - case UMF_PROTECTION_EXEC: - *out_protection = PAGE_EXECUTE; - return UMF_RESULT_SUCCESS; - case (UMF_PROTECTION_EXEC | UMF_PROTECTION_READ): - *out_protection = PAGE_EXECUTE_READ; - return UMF_RESULT_SUCCESS; - case (UMF_PROTECTION_EXEC | UMF_PROTECTION_READ | UMF_PROTECTION_WRITE): - *out_protection = PAGE_EXECUTE_READWRITE; - return UMF_RESULT_SUCCESS; - case (UMF_PROTECTION_EXEC | UMF_PROTECTION_WRITE): - *out_protection = PAGE_EXECUTE_WRITECOPY; - return UMF_RESULT_SUCCESS; - case UMF_PROTECTION_READ: - *out_protection = PAGE_READONLY; - return UMF_RESULT_SUCCESS; - case (UMF_PROTECTION_READ | UMF_PROTECTION_WRITE): - *out_protection = PAGE_READWRITE; - return UMF_RESULT_SUCCESS; - case UMF_PROTECTION_WRITE: - *out_protection = PAGE_WRITECOPY; - return UMF_RESULT_SUCCESS; - } - LOG_ERR("os_translate_mem_protection_flags(): unsupported protection flag: " - "%u", - in_protection); - return UMF_RESULT_ERROR_INVALID_ARGUMENT; -} - -umf_result_t os_translate_mem_visibility_flag(umf_memory_visibility_t in_flag, - unsigned *out_flag) { - switch (in_flag) { - case UMF_MEM_MAP_PRIVATE: - *out_flag = 0; // ignored on Windows - return UMF_RESULT_SUCCESS; - case UMF_MEM_MAP_SHARED: - return UMF_RESULT_ERROR_NOT_SUPPORTED; // not supported on Windows yet - } - return UMF_RESULT_ERROR_INVALID_ARGUMENT; -} - -// create a shared memory file -int os_shm_create(const char *shm_name, size_t size) { - (void)shm_name; // unused - (void)size; // unused - return 0; // ignored on Windows -} - -// open a shared memory file -int os_shm_open(const char *shm_name) { - (void)shm_name; // unused - return 0; // ignored on Windows -} - -// unlink a shared memory file -int os_shm_unlink(const char *shm_name) { - (void)shm_name; // unused - return 0; // ignored on Windows -} - -int os_create_anonymous_fd(void) { - return 0; // ignored on Windows -} - -size_t get_max_file_size(void) { return SIZE_MAX; } - -int os_get_file_size(int fd, size_t *size) { - (void)fd; // unused - (void)size; // unused - return -1; // not supported on Windows -} - -int os_set_file_size(int fd, size_t size) { - (void)fd; // unused - (void)size; // unused - return 0; // ignored on Windows -} - -void *os_mmap(void *hint_addr, size_t length, int prot, int flag, int fd, - size_t fd_offset) { - (void)flag; // ignored on Windows - (void)fd; // ignored on Windows - (void)fd_offset; // ignored on Windows - return VirtualAlloc(hint_addr, length, MEM_RESERVE | MEM_COMMIT, prot); -} - -void *os_devdax_mmap(void *hint_addr, size_t length, int prot, int fd) { - (void)hint_addr; // unused - (void)length; // unused - (void)prot; // unused - (void)fd; // unused - return NULL; // not supported on Windows -} - -int os_munmap(void *addr, size_t length) { - // If VirtualFree() succeeds, the return value is nonzero. - // If VirtualFree() fails, the return value is 0 (zero). - (void)length; // unused - return (VirtualFree(addr, 0, MEM_RELEASE) == 0); -} - -int os_purge(void *addr, size_t length, int advice) { - // If VirtualFree() succeeds, the return value is nonzero. - // If VirtualFree() fails, the return value is 0 (zero). - (void)advice; // unused - - // temporarily disable the C6250 warning as we intentionally use the - // MEM_DECOMMIT flag only -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable : 6250) -#endif // _MSC_VER - - return (VirtualFree(addr, length, MEM_DECOMMIT) == 0); - -#if defined(_MSC_VER) -#pragma warning(pop) -#endif // _MSC_VER -} - -static void _os_get_page_size(void) { - SYSTEM_INFO SystemInfo; - GetSystemInfo(&SystemInfo); - Page_size = SystemInfo.dwPageSize; -} - -size_t os_get_page_size(void) { - util_init_once(&Page_size_is_initialized, _os_get_page_size); - return Page_size; -} - -void os_strerror(int errnum, char *buf, size_t buflen) { - strerror_s(buf, buflen, errnum); -} - -// open a devdax -int os_devdax_open(const char *path) { - (void)path; // unused - - return -1; -} - -// open a file -int os_file_open(const char *path) { - (void)path; // unused - - return -1; -} - -// open a file or create -int os_file_open_or_create(const char *path) { - (void)path; // unused - - return -1; -} - -int os_fallocate(int fd, long offset, long len) { - (void)fd; // unused - (void)offset; // unused - (void)len; // unused - - return -1; -} diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt index c7a285ce2..a0bff39fd 100644 --- a/src/utils/CMakeLists.txt +++ b/src/utils/CMakeLists.txt @@ -10,6 +10,10 @@ set(UMF_UTILS_SOURCES_COMMON utils_common.c utils_log.c utils_load_library.c) set(UMF_UTILS_SOURCES_POSIX utils_posix_common.c utils_posix_concurrency.c utils_posix_math.c) +set(UMF_UTILS_SOURCES_LINUX utils_linux_common.c) + +set(UMF_UTILS_SOURCES_MACOSX utils_macosx_common.c) + set(UMF_UTILS_SOURCES_WINDOWS utils_windows_common.c utils_windows_concurrency.c utils_windows_math.c) @@ -33,6 +37,13 @@ if(LINUX OR MACOSX) set(UMF_UTILS_SOURCES ${UMF_UTILS_SOURCES_COMMON} ${UMF_UTILS_SOURCES_POSIX}) set(UMF_UTILS_LIBS dl) + + if(LINUX) + set(UMF_UTILS_SOURCES ${UMF_UTILS_SOURCES} ${UMF_UTILS_SOURCES_LINUX}) + set(UMF_UTILS_LIBS ${UMF_UTILS_LIBS} rt) # librt for shm_open() + elseif(MACOSX) + set(UMF_UTILS_SOURCES ${UMF_UTILS_SOURCES} ${UMF_UTILS_SOURCES_MACOSX}) + endif() elseif(WINDOWS) set(UMF_UTILS_SOURCES ${UMF_UTILS_SOURCES_COMMON} ${UMF_UTILS_SOURCES_WINDOWS}) diff --git a/src/utils/utils_common.c b/src/utils/utils_common.c index e94126b33..5ae1be3a1 100644 --- a/src/utils/utils_common.c +++ b/src/utils/utils_common.c @@ -91,3 +91,28 @@ int util_copy_path(const char *in_path, char out_path[], size_t path_max) { return 0; } + +umf_result_t utils_translate_flags(unsigned in_flags, unsigned max, + umf_result_t (*translate_flag)(unsigned, + unsigned *), + unsigned *out_flags) { + unsigned out_f = 0; + for (unsigned n = 1; n < max; n <<= 1) { + if (in_flags & n) { + unsigned flag; + umf_result_t result = translate_flag(n, &flag); + if (result != UMF_RESULT_SUCCESS) { + return result; + } + out_f |= flag; + in_flags &= ~n; // clear this bit + } + } + + if (in_flags != 0) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + *out_flags = out_f; + return UMF_RESULT_SUCCESS; +} diff --git a/src/utils/utils_common.h b/src/utils/utils_common.h index 20206b1e4..a9796415f 100644 --- a/src/utils/utils_common.h +++ b/src/utils/utils_common.h @@ -15,11 +15,17 @@ #include #include +#include #ifdef __cplusplus extern "C" { #endif +typedef enum umf_purge_advise_t { + UMF_PURGE_LAZY, + UMF_PURGE_FORCE, +} umf_purge_advise_t; + #define DO_WHILE_EMPTY \ do { \ } while (0) @@ -89,6 +95,51 @@ umf_result_t utils_duplicate_fd(int pid, int fd_in, int *fd_out); int util_copy_path(const char *in_path, char out_path[], size_t path_max); +umf_result_t utils_translate_flags(unsigned in_flags, unsigned max, + umf_result_t (*translate_flag)(unsigned, + unsigned *), + unsigned *out_flags); + +umf_result_t utils_translate_mem_protection_flags(unsigned in_protection, + unsigned *out_protection); + +umf_result_t +utils_translate_mem_visibility_flag(umf_memory_visibility_t in_flag, + unsigned *out_flag); + +int utils_create_anonymous_fd(void); + +int utils_shm_create(const char *shm_name, size_t size); + +int utils_shm_open(const char *shm_name); + +int utils_shm_unlink(const char *shm_name); + +size_t get_max_file_size(void); + +int utils_get_file_size(int fd, size_t *size); + +int utils_set_file_size(int fd, size_t size); + +void *utils_mmap(void *hint_addr, size_t length, int prot, int flag, int fd, + size_t fd_offset); + +void *utils_devdax_mmap(void *hint_addr, size_t length, int prot, int fd); + +int utils_munmap(void *addr, size_t length); + +int utils_purge(void *addr, size_t length, int advice); + +void utils_strerror(int errnum, char *buf, size_t buflen); + +int utils_devdax_open(const char *path); + +int utils_file_open(const char *path); + +int utils_file_open_or_create(const char *path); + +int utils_fallocate(int fd, long offset, long len); + #ifdef __cplusplus } #endif diff --git a/src/provider/provider_os_memory_linux.c b/src/utils/utils_linux_common.c similarity index 82% rename from src/provider/provider_os_memory_linux.c rename to src/utils/utils_linux_common.c index 9a90e1145..1ee5cccc8 100644 --- a/src/provider/provider_os_memory_linux.c +++ b/src/utils/utils_linux_common.c @@ -1,9 +1,11 @@ /* + * * 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 @@ -13,13 +15,15 @@ #include #include -#include +#include +#include -#include "provider_os_memory_internal.h" +#include "utils_common.h" #include "utils_log.h" -umf_result_t os_translate_mem_visibility_flag(umf_memory_visibility_t in_flag, - unsigned *out_flag) { +umf_result_t +utils_translate_mem_visibility_flag(umf_memory_visibility_t in_flag, + unsigned *out_flag) { switch (in_flag) { case UMF_MEM_MAP_PRIVATE: *out_flag = MAP_PRIVATE; @@ -31,8 +35,60 @@ umf_result_t os_translate_mem_visibility_flag(umf_memory_visibility_t in_flag, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } +/* + * MMap a /dev/dax device. + * First try to mmap with (MAP_SHARED_VALIDATE | MAP_SYNC) flags + * which allows flushing from the user-space. If MAP_SYNC fails + * try to mmap with MAP_SHARED flag (without MAP_SYNC). + */ +void *utils_devdax_mmap(void *hint_addr, size_t length, int prot, int fd) { + void *ptr = utils_mmap(hint_addr, length, prot, + MAP_SHARED_VALIDATE | MAP_SYNC, fd, 0); + if (ptr) { + LOG_DEBUG( + "devdax mapped with the (MAP_SHARED_VALIDATE | MAP_SYNC) flags"); + return ptr; + } + + ptr = utils_mmap(hint_addr, length, prot, MAP_SHARED, fd, 0); + if (ptr) { + LOG_DEBUG("devdax mapped with the MAP_SHARED flag"); + return ptr; + } + + return NULL; +} + +int utils_get_file_size(int fd, size_t *size) { + struct stat statbuf; + int ret = fstat(fd, &statbuf); + if (ret) { + LOG_PERR("fstat(%i) failed", fd); + return ret; + } + + *size = statbuf.st_size; + return 0; +} + +int utils_set_file_size(int fd, size_t size) { + errno = 0; + int ret = ftruncate(fd, size); + if (ret) { + LOG_PERR("setting size %zu of a file failed", size); + } else { + LOG_DEBUG("set size of a file to %zu bytes", size); + } + + return ret; +} + +int utils_fallocate(int fd, long offset, long len) { + return posix_fallocate(fd, offset, len); +} + // create a shared memory file -int os_shm_create(const char *shm_name, size_t size) { +int utils_shm_create(const char *shm_name, size_t size) { if (shm_name == NULL) { LOG_ERR("empty name of a shared memory file"); return -1; @@ -46,7 +102,7 @@ int os_shm_create(const char *shm_name, size_t size) { return fd; } - int ret = os_set_file_size(fd, size); + int ret = utils_set_file_size(fd, size); if (ret) { LOG_ERR("setting size (%zu) of a file /dev/shm/%s failed", size, shm_name); @@ -59,7 +115,7 @@ int os_shm_create(const char *shm_name, size_t size) { } // open a shared memory file -int os_shm_open(const char *shm_name) { +int utils_shm_open(const char *shm_name) { if (shm_name == NULL) { LOG_ERR("empty name of a shared memory file"); return -1; @@ -74,7 +130,7 @@ int os_shm_open(const char *shm_name) { } // unlink a shared memory file -int os_shm_unlink(const char *shm_name) { return shm_unlink(shm_name); } +int utils_shm_unlink(const char *shm_name) { return shm_unlink(shm_name); } static int syscall_memfd_secret(void) { int fd = -1; @@ -109,7 +165,7 @@ static int syscall_memfd_create(void) { } // create an anonymous file descriptor -int os_create_anonymous_fd(void) { +int utils_create_anonymous_fd(void) { int fd = -1; if (!util_env_var_has_str("UMF_MEM_FD_FUNC", "memfd_create")) { @@ -133,55 +189,3 @@ int os_create_anonymous_fd(void) { return fd; } - -int os_get_file_size(int fd, size_t *size) { - struct stat statbuf; - int ret = fstat(fd, &statbuf); - if (ret) { - LOG_PERR("fstat(%i) failed", fd); - return ret; - } - - *size = statbuf.st_size; - return 0; -} - -int os_set_file_size(int fd, size_t size) { - errno = 0; - int ret = ftruncate(fd, size); - if (ret) { - LOG_PERR("setting size %zu of a file failed", size); - } else { - LOG_DEBUG("set size of a file to %zu bytes", size); - } - - return ret; -} - -/* - * MMap a /dev/dax device. - * First try to mmap with (MAP_SHARED_VALIDATE | MAP_SYNC) flags - * which allows flushing from the user-space. If MAP_SYNC fails - * try to mmap with MAP_SHARED flag (without MAP_SYNC). - */ -void *os_devdax_mmap(void *hint_addr, size_t length, int prot, int fd) { - void *ptr = - os_mmap(hint_addr, length, prot, MAP_SHARED_VALIDATE | MAP_SYNC, fd, 0); - if (ptr) { - LOG_DEBUG( - "devdax mapped with the (MAP_SHARED_VALIDATE | MAP_SYNC) flags"); - return ptr; - } - - ptr = os_mmap(hint_addr, length, prot, MAP_SHARED, fd, 0); - if (ptr) { - LOG_DEBUG("devdax mapped with the MAP_SHARED flag"); - return ptr; - } - - return NULL; -} - -int os_fallocate(int fd, long offset, long len) { - return posix_fallocate(fd, offset, len); -} diff --git a/src/provider/provider_os_memory_macosx.c b/src/utils/utils_macosx_common.c similarity index 56% rename from src/provider/provider_os_memory_macosx.c rename to src/utils/utils_macosx_common.c index 33835beac..1ab5c4c85 100644 --- a/src/provider/provider_os_memory_macosx.c +++ b/src/utils/utils_macosx_common.c @@ -1,17 +1,60 @@ /* + * * 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 "provider_os_memory_internal.h" #include "utils_log.h" +umf_result_t +utils_translate_mem_visibility_flag(umf_memory_visibility_t in_flag, + unsigned *out_flag) { + switch (in_flag) { + case UMF_MEM_MAP_PRIVATE: + *out_flag = MAP_PRIVATE; + return UMF_RESULT_SUCCESS; + case UMF_MEM_MAP_SHARED: + return UMF_RESULT_ERROR_NOT_SUPPORTED; // not supported on MacOSX + } + return UMF_RESULT_ERROR_INVALID_ARGUMENT; +} + +void *utils_devdax_mmap(void *hint_addr, size_t length, int prot, int fd) { + (void)hint_addr; // unused + (void)length; // unused + (void)prot; // unused + (void)fd; // unused + return NULL; // not supported +} + +int utils_get_file_size(int fd, size_t *size) { + (void)fd; // unused + (void)size; // unused + return -1; // not supported on MacOSX +} + +int utils_set_file_size(int fd, size_t size) { + (void)fd; // unused + (void)size; // unused + return 0; // ignored on MacOSX +} + +int utils_fallocate(int fd, long offset, long len) { + (void)fd; // unused + (void)offset; // unused + (void)len; // unused + + return -1; +} + umf_result_t os_translate_mem_visibility_flag(umf_memory_visibility_t in_flag, unsigned *out_flag) { switch (in_flag) { @@ -25,26 +68,26 @@ umf_result_t os_translate_mem_visibility_flag(umf_memory_visibility_t in_flag, } // create a shared memory file -int os_shm_create(const char *shm_name, size_t size) { +int utils_shm_create(const char *shm_name, size_t size) { (void)shm_name; // unused (void)size; // unused return 0; // ignored on MacOSX } // open a shared memory file -int os_shm_open(const char *shm_name) { +int utils_shm_open(const char *shm_name) { (void)shm_name; // unused return 0; // ignored on MacOSX } // unlink a shared memory file -int os_shm_unlink(const char *shm_name) { +int utils_shm_unlink(const char *shm_name) { (void)shm_name; // unused return 0; // ignored on MacOSX } // create an anonymous file descriptor -int os_create_anonymous_fd(void) { +int utils_create_anonymous_fd(void) { return 0; // ignored on MacOSX } diff --git a/src/utils/utils_posix_common.c b/src/utils/utils_posix_common.c index 51049e613..42a5d06f1 100644 --- a/src/utils/utils_posix_common.c +++ b/src/utils/utils_posix_common.c @@ -8,14 +8,20 @@ */ #include +#include +#include #include #include +#include +#include #include +#include #include #include "utils_common.h" #include "utils_concurrency.h" #include "utils_log.h" +#include "utils_sanitizers.h" #ifndef __NR_pidfd_open #define __NR_pidfd_open 434 /* Syscall id */ @@ -24,6 +30,12 @@ #define __NR_pidfd_getfd 438 /* Syscall id */ #endif +// maximum value of the off_t type +#define OFF_T_MAX \ + (sizeof(off_t) == sizeof(long long) \ + ? LLONG_MAX \ + : (sizeof(off_t) == sizeof(long) ? LONG_MAX : INT_MAX)) + static UTIL_ONCE_FLAG Page_size_is_initialized = UTIL_ONCE_FLAG_INIT; static size_t Page_size; @@ -104,3 +116,153 @@ umf_result_t utils_duplicate_fd(int pid, int fd_in, int *fd_out) { return UMF_RESULT_SUCCESS; #endif } + +umf_result_t utils_translate_mem_protection_one_flag(unsigned in_protection, + unsigned *out_protection) { + switch (in_protection) { + case UMF_PROTECTION_NONE: + *out_protection = PROT_NONE; + return UMF_RESULT_SUCCESS; + case UMF_PROTECTION_READ: + *out_protection = PROT_READ; + return UMF_RESULT_SUCCESS; + case UMF_PROTECTION_WRITE: + *out_protection = PROT_WRITE; + return UMF_RESULT_SUCCESS; + case UMF_PROTECTION_EXEC: + *out_protection = PROT_EXEC; + return UMF_RESULT_SUCCESS; + } + return UMF_RESULT_ERROR_INVALID_ARGUMENT; +} + +size_t get_max_file_size(void) { return OFF_T_MAX; } + +umf_result_t utils_translate_mem_protection_flags(unsigned in_protection, + unsigned *out_protection) { + // translate protection - combination of 'umf_mem_protection_flags_t' flags + return utils_translate_flags(in_protection, UMF_PROTECTION_MAX, + utils_translate_mem_protection_one_flag, + out_protection); +} + +static int utils_translate_purge_advise(umf_purge_advise_t advise) { + switch (advise) { + case UMF_PURGE_LAZY: + return MADV_FREE; + case UMF_PURGE_FORCE: + return MADV_DONTNEED; + } + return -1; +} + +void *utils_mmap(void *hint_addr, size_t length, int prot, int flag, int fd, + size_t fd_offset) { + fd = (fd == 0) ? -1 : fd; + if (fd == -1) { + // MAP_ANONYMOUS - the mapping is not backed by any file + flag |= MAP_ANONYMOUS; + } + + void *ptr = mmap(hint_addr, length, prot, flag, fd, fd_offset); + if (ptr == MAP_FAILED) { + return NULL; + } + // this should be unnecessary but pairs of mmap/munmap do not reset + // asan's user-poisoning flags, leading to invalid error reports + // Bug 81619: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81619 + utils_annotate_memory_defined(ptr, length); + return ptr; +} + +int utils_munmap(void *addr, size_t length) { + // this should be unnecessary but pairs of mmap/munmap do not reset + // asan's user-poisoning flags, leading to invalid error reports + // Bug 81619: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81619 + utils_annotate_memory_defined(addr, length); + return munmap(addr, length); +} + +int utils_purge(void *addr, size_t length, int advice) { + return madvise(addr, length, utils_translate_purge_advise(advice)); +} + +void utils_strerror(int errnum, char *buf, size_t buflen) { +// 'strerror_r' implementation is XSI-compliant (returns 0 on success) +#if (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE + if (strerror_r(errnum, buf, buflen)) { +#else // 'strerror_r' implementation is GNU-specific (returns pointer on success) + if (!strerror_r(errnum, buf, buflen)) { +#endif + LOG_PERR("Retrieving error code description failed"); + } +} + +// open a devdax +int utils_devdax_open(const char *path) { + if (path == NULL) { + LOG_ERR("empty path"); + return -1; + } + + if (strstr(path, "/dev/dax") != path) { + LOG_ERR("path of the file \"%s\" does not start with \"/dev/dax\"", + path); + return -1; + } + + int fd = open(path, O_RDWR); + if (fd == -1) { + LOG_PERR("cannot open the file: %s", path); + return -1; + } + + struct stat statbuf; + int ret = stat(path, &statbuf); + if (ret) { + LOG_PERR("stat(%s) failed", path); + close(fd); + return -1; + } + + if (!S_ISCHR(statbuf.st_mode)) { + LOG_ERR("file %s is not a character device", path); + close(fd); + return -1; + } + + return fd; +} + +// open a file +int utils_file_open(const char *path) { + if (!path) { + LOG_ERR("empty path"); + return -1; + } + + int fd = open(path, O_RDWR); + if (fd == -1) { + LOG_PERR("cannot open the file: %s", path); + } + + return fd; +} + +// open a file or create +int utils_file_open_or_create(const char *path) { + if (!path) { + LOG_ERR("empty path"); + return -1; + } + + int fd = open(path, O_RDWR | O_CREAT, 0600); + if (fd == -1) { + LOG_PERR("cannot open/create the file: %s", path); + return -1; + } + + LOG_DEBUG("opened/created the file: %s", path); + + return fd; +} diff --git a/src/utils/utils_windows_common.c b/src/utils/utils_windows_common.c index 9358891ad..f33b29e1b 100644 --- a/src/utils/utils_windows_common.c +++ b/src/utils/utils_windows_common.c @@ -9,11 +9,16 @@ #include +#include #include #include +#include +#include +#include #include "utils_common.h" #include "utils_concurrency.h" +#include "utils_log.h" #define BUFFER_SIZE 1024 @@ -46,3 +51,163 @@ umf_result_t utils_duplicate_fd(int pid, int fd_in, int *fd_out) { (void)fd_out; // unused return UMF_RESULT_ERROR_NOT_SUPPORTED; } + +umf_result_t utils_translate_mem_protection_flags(unsigned in_protection, + unsigned *out_protection) { + switch (in_protection) { + case UMF_PROTECTION_NONE: + *out_protection = PAGE_NOACCESS; + return UMF_RESULT_SUCCESS; + case UMF_PROTECTION_EXEC: + *out_protection = PAGE_EXECUTE; + return UMF_RESULT_SUCCESS; + case (UMF_PROTECTION_EXEC | UMF_PROTECTION_READ): + *out_protection = PAGE_EXECUTE_READ; + return UMF_RESULT_SUCCESS; + case (UMF_PROTECTION_EXEC | UMF_PROTECTION_READ | UMF_PROTECTION_WRITE): + *out_protection = PAGE_EXECUTE_READWRITE; + return UMF_RESULT_SUCCESS; + case (UMF_PROTECTION_EXEC | UMF_PROTECTION_WRITE): + *out_protection = PAGE_EXECUTE_WRITECOPY; + return UMF_RESULT_SUCCESS; + case UMF_PROTECTION_READ: + *out_protection = PAGE_READONLY; + return UMF_RESULT_SUCCESS; + case (UMF_PROTECTION_READ | UMF_PROTECTION_WRITE): + *out_protection = PAGE_READWRITE; + return UMF_RESULT_SUCCESS; + case UMF_PROTECTION_WRITE: + *out_protection = PAGE_WRITECOPY; + return UMF_RESULT_SUCCESS; + } + LOG_ERR( + "utils_translate_mem_protection_flags(): unsupported protection flag: " + "%u", + in_protection); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; +} + +umf_result_t +utils_translate_mem_visibility_flag(umf_memory_visibility_t in_flag, + unsigned *out_flag) { + switch (in_flag) { + case UMF_MEM_MAP_PRIVATE: + *out_flag = 0; // ignored on Windows + return UMF_RESULT_SUCCESS; + case UMF_MEM_MAP_SHARED: + return UMF_RESULT_ERROR_NOT_SUPPORTED; // not supported on Windows yet + } + return UMF_RESULT_ERROR_INVALID_ARGUMENT; +} + +// create a shared memory file +int utils_shm_create(const char *shm_name, size_t size) { + (void)shm_name; // unused + (void)size; // unused + return 0; // ignored on Windows +} + +// open a shared memory file +int utils_shm_open(const char *shm_name) { + (void)shm_name; // unused + return 0; // ignored on Windows +} + +// unlink a shared memory file +int utils_shm_unlink(const char *shm_name) { + (void)shm_name; // unused + return 0; // ignored on Windows +} + +int utils_create_anonymous_fd(void) { + return 0; // ignored on Windows +} + +size_t get_max_file_size(void) { return SIZE_MAX; } + +int utils_get_file_size(int fd, size_t *size) { + (void)fd; // unused + (void)size; // unused + return -1; // not supported on Windows +} + +int utils_set_file_size(int fd, size_t size) { + (void)fd; // unused + (void)size; // unused + return 0; // ignored on Windows +} + +void *utils_mmap(void *hint_addr, size_t length, int prot, int flag, int fd, + size_t fd_offset) { + (void)flag; // ignored on Windows + (void)fd; // ignored on Windows + (void)fd_offset; // ignored on Windows + return VirtualAlloc(hint_addr, length, MEM_RESERVE | MEM_COMMIT, prot); +} + +void *utils_devdax_mmap(void *hint_addr, size_t length, int prot, int fd) { + (void)hint_addr; // unused + (void)length; // unused + (void)prot; // unused + (void)fd; // unused + return NULL; // not supported on Windows +} + +int utils_munmap(void *addr, size_t length) { + // If VirtualFree() succeeds, the return value is nonzero. + // If VirtualFree() fails, the return value is 0 (zero). + (void)length; // unused + return (VirtualFree(addr, 0, MEM_RELEASE) == 0); +} + +int utils_purge(void *addr, size_t length, int advice) { + // If VirtualFree() succeeds, the return value is nonzero. + // If VirtualFree() fails, the return value is 0 (zero). + (void)advice; // unused + + // temporarily disable the C6250 warning as we intentionally use the + // MEM_DECOMMIT flag only +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 6250) +#endif // _MSC_VER + + return (VirtualFree(addr, length, MEM_DECOMMIT) == 0); + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif // _MSC_VER +} + +void utils_strerror(int errnum, char *buf, size_t buflen) { + strerror_s(buf, buflen, errnum); +} + +// open a devdax +int utils_devdax_open(const char *path) { + (void)path; // unused + + return -1; +} + +// open a file +int utils_file_open(const char *path) { + (void)path; // unused + + return -1; +} + +// open a file or create +int utils_file_open_or_create(const char *path) { + (void)path; // unused + + return -1; +} + +int utils_fallocate(int fd, long offset, long len) { + (void)fd; // unused + (void)offset; // unused + (void)len; // unused + + return -1; +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f2e1a4561..22599dad4 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -114,10 +114,6 @@ endfunction() add_subdirectory(common) -add_umf_test(NAME base SRCS base.cpp) -add_umf_test(NAME memoryPool SRCS memoryPoolAPI.cpp malloc_compliance_tests.cpp) -add_umf_test(NAME memoryProvider SRCS memoryProviderAPI.cpp) - if(UMF_BUILD_SHARED_LIBRARY) # if build as shared library, utils symbols won't be visible in tests set(UMF_UTILS_FOR_TEST umf_utils) @@ -125,6 +121,14 @@ if(UMF_BUILD_SHARED_LIBRARY) set(UMF_UTILS_SOURCES ../src/utils/utils_common.c ../src/utils/utils_posix_common.c ../src/utils/utils_posix_concurrency.c) + if(LINUX) + set(UMF_UTILS_SOURCES ${UMF_UTILS_SOURCES} + ../src/utils/utils_linux_common.c) + set(UMF_LOGGER_LIBS rt) # librt for shm_open() + elseif(MACOSX) + set(UMF_UTILS_SOURCES ${UMF_UTILS_SOURCES} + ../src/utils/utils_macosx_common.c) + endif() elseif(WINDOWS) set(UMF_UTILS_SOURCES ../src/utils/utils_common.c ../src/utils/utils_windows_common.c @@ -132,7 +136,16 @@ if(UMF_BUILD_SHARED_LIBRARY) endif() endif() -add_umf_test(NAME logger SRCS utils/utils_log.cpp ${UMF_UTILS_SOURCES}) +add_umf_test(NAME base SRCS base.cpp) +add_umf_test( + NAME memoryPool + SRCS memoryPoolAPI.cpp malloc_compliance_tests.cpp + LIBS ${UMF_UTILS_FOR_TEST}) +add_umf_test(NAME memoryProvider SRCS memoryProviderAPI.cpp) +add_umf_test( + NAME logger + SRCS utils/utils_log.cpp ${UMF_UTILS_SOURCES} + LIBS ${UMF_LOGGER_LIBS}) add_umf_test( NAME utils_common diff --git a/test/utils/utils_log.cpp b/test/utils/utils_log.cpp index 3e899e685..f865b416b 100644 --- a/test/utils/utils_log.cpp +++ b/test/utils/utils_log.cpp @@ -107,7 +107,9 @@ const char *env_variable = ""; #define strerror_s(A, B, C) mock_strerror_windows(A, B, C) //getenv returns 'char *' not 'const char *' so we need explicit cast to drop const #define getenv(X) strstr(X, "UMF_LOG") ? (char *)env_variable : getenv(X) +#ifndef UMF_VERSION #define UMF_VERSION "test version" +#endif #include "utils/utils_log.c" #undef util_env_var #undef fopen From ae251900e59dfb717561408e6f8a94a25e535963 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Fri, 20 Sep 2024 10:12:33 +0200 Subject: [PATCH 108/352] Rename all util_* functions to utils_* Signed-off-by: Lukasz Dorau --- benchmark/ubench.c | 2 +- src/base_alloc/base_alloc.c | 24 ++++---- src/base_alloc/base_alloc_global.c | 2 +- src/base_alloc/base_alloc_linear.c | 34 +++++------ src/base_alloc/base_alloc_linux.c | 2 +- src/base_alloc/base_alloc_windows.c | 2 +- src/critnib/critnib.c | 40 ++++++------- src/libumf.c | 6 +- src/memspaces/memspace_highest_bandwidth.c | 4 +- src/memspaces/memspace_highest_capacity.c | 4 +- src/memspaces/memspace_host_all.c | 2 +- src/memspaces/memspace_lowest_latency.c | 4 +- src/pool/pool_scalable.c | 24 ++++---- src/provider/provider_cuda.c | 18 +++--- src/provider/provider_devdax_memory.c | 20 +++---- src/provider/provider_file_memory.c | 22 +++---- src/provider/provider_level_zero.c | 24 ++++---- src/provider/provider_os_memory.c | 16 ++--- src/provider/provider_os_memory_internal.h | 8 +-- src/provider/provider_tracking.c | 22 +++---- src/provider/provider_tracking.h | 2 +- src/proxy_lib/proxy_lib.c | 14 ++--- src/topology.c | 2 +- src/utils/utils_common.c | 14 ++--- src/utils/utils_common.h | 16 ++--- src/utils/utils_concurrency.h | 40 ++++++------- src/utils/utils_linux_common.c | 2 +- src/utils/utils_load_library.c | 16 ++--- src/utils/utils_load_library.h | 8 +-- src/utils/utils_log.c | 64 ++++++++++---------- src/utils/utils_log.h | 36 +++++------ src/utils/utils_posix_common.c | 6 +- src/utils/utils_posix_concurrency.c | 14 ++--- src/utils/utils_windows_common.c | 6 +- src/utils/utils_windows_concurrency.c | 22 +++---- test/providers/cuda_helpers.cpp | 30 +++++----- test/providers/level_zero_helpers.cpp | 46 +++++++------- test/test_base_alloc_linear.cpp | 2 +- test/utils/utils.cpp | 70 +++++++++++----------- test/utils/utils_log.cpp | 34 +++++------ 40 files changed, 362 insertions(+), 362 deletions(-) diff --git a/benchmark/ubench.c b/benchmark/ubench.c index f70f19fb3..04695a0f4 100644 --- a/benchmark/ubench.c +++ b/benchmark/ubench.c @@ -53,7 +53,7 @@ #include "ubench.h" // BENCHMARK CONFIG #define N_ITERATIONS 1000 -#define ALLOC_SIZE (util_get_page_size()) +#define ALLOC_SIZE (utils_get_page_size()) // OS MEMORY PROVIDER CONFIG #define OS_MEMORY_PROVIDER_TRACE (0) diff --git a/src/base_alloc/base_alloc.c b/src/base_alloc/base_alloc.c index 144f5423b..353e5058d 100644 --- a/src/base_alloc/base_alloc.c +++ b/src/base_alloc/base_alloc.c @@ -36,7 +36,7 @@ struct umf_ba_chunk_t { struct umf_ba_main_pool_meta_t { size_t pool_size; // size of each pool (argument of each ba_os_alloc() call) size_t chunk_size; // size of all memory chunks in this pool - os_mutex_t free_lock; // lock of free_list + utils_mutex_t free_lock; // lock of free_list umf_ba_chunk_t *free_list; // list of free chunks size_t n_allocs; // number of allocated chunks #ifndef NDEBUG @@ -135,7 +135,7 @@ static void *ba_os_alloc_annotated(size_t pool_size) { umf_ba_pool_t *umf_ba_create(size_t size) { size_t chunk_size = ALIGN_UP(size, MEMORY_ALIGNMENT); - size_t mutex_size = ALIGN_UP(util_mutex_get_size(), MEMORY_ALIGNMENT); + size_t mutex_size = ALIGN_UP(utils_mutex_get_size(), MEMORY_ALIGNMENT); size_t metadata_size = sizeof(struct umf_ba_main_pool_meta_t); size_t pool_size = sizeof(void *) + metadata_size + mutex_size + @@ -168,10 +168,10 @@ umf_ba_pool_t *umf_ba_create(size_t size) { char *data_ptr = (char *)&pool->data; size_t size_left = pool_size - offsetof(umf_ba_pool_t, data); - util_align_ptr_size((void **)&data_ptr, &size_left, MEMORY_ALIGNMENT); + utils_align_ptr_size((void **)&data_ptr, &size_left, MEMORY_ALIGNMENT); // init free_lock - os_mutex_t *mutex = util_mutex_init(&pool->metadata.free_lock); + utils_mutex_t *mutex = utils_mutex_init(&pool->metadata.free_lock); if (!mutex) { ba_os_free(pool, pool_size); return NULL; @@ -184,13 +184,13 @@ umf_ba_pool_t *umf_ba_create(size_t size) { } void *umf_ba_alloc(umf_ba_pool_t *pool) { - util_mutex_lock(&pool->metadata.free_lock); + utils_mutex_lock(&pool->metadata.free_lock); if (pool->metadata.free_list == NULL) { umf_ba_next_pool_t *new_pool = (umf_ba_next_pool_t *)ba_os_alloc_annotated( pool->metadata.pool_size); if (!new_pool) { - util_mutex_unlock(&pool->metadata.free_lock); + utils_mutex_unlock(&pool->metadata.free_lock); return NULL; } @@ -209,7 +209,7 @@ void *umf_ba_alloc(umf_ba_pool_t *pool) { size_t size_left = pool->metadata.pool_size - offsetof(umf_ba_next_pool_t, data); - util_align_ptr_size((void **)&data_ptr, &size_left, MEMORY_ALIGNMENT); + utils_align_ptr_size((void **)&data_ptr, &size_left, MEMORY_ALIGNMENT); ba_divide_memory_into_chunks(pool, data_ptr, size_left); } @@ -234,7 +234,7 @@ void *umf_ba_alloc(umf_ba_pool_t *pool) { VALGRIND_DO_MALLOCLIKE_BLOCK(chunk, pool->metadata.chunk_size, 0, 0); utils_annotate_memory_undefined(chunk, pool->metadata.chunk_size); - util_mutex_unlock(&pool->metadata.free_lock); + utils_mutex_unlock(&pool->metadata.free_lock); return chunk; } @@ -269,7 +269,7 @@ void umf_ba_free(umf_ba_pool_t *pool, void *ptr) { umf_ba_chunk_t *chunk = (umf_ba_chunk_t *)ptr; - util_mutex_lock(&pool->metadata.free_lock); + utils_mutex_lock(&pool->metadata.free_lock); assert(pool_contains_pointer(pool, ptr)); chunk->next = pool->metadata.free_list; pool->metadata.free_list = chunk; @@ -281,14 +281,14 @@ void umf_ba_free(umf_ba_pool_t *pool, void *ptr) { VALGRIND_DO_FREELIKE_BLOCK(chunk, 0); utils_annotate_memory_inaccessible(chunk, pool->metadata.chunk_size); - util_mutex_unlock(&pool->metadata.free_lock); + utils_mutex_unlock(&pool->metadata.free_lock); } void umf_ba_destroy(umf_ba_pool_t *pool) { // Do not destroy if we are running in the proxy library, // because it may need those resources till // the very end of exiting the application. - if (pool->metadata.n_allocs && util_is_running_in_proxy_lib()) { + if (pool->metadata.n_allocs && utils_is_running_in_proxy_lib()) { return; } @@ -308,6 +308,6 @@ void umf_ba_destroy(umf_ba_pool_t *pool) { ba_os_free(current_pool, size); } - util_mutex_destroy_not_free(&pool->metadata.free_lock); + utils_mutex_destroy_not_free(&pool->metadata.free_lock); ba_os_free(pool, size); } diff --git a/src/base_alloc/base_alloc_global.c b/src/base_alloc/base_alloc_global.c index 12a93fd8b..ec6bc9fcb 100644 --- a/src/base_alloc/base_alloc_global.c +++ b/src/base_alloc/base_alloc_global.c @@ -149,7 +149,7 @@ static void *get_original_alloc(void *user_ptr, size_t *total_size, } void *umf_ba_global_aligned_alloc(size_t size, size_t alignment) { - util_init_once(&ba_is_initialized, umf_ba_create_global); + utils_init_once(&ba_is_initialized, umf_ba_create_global); if (size == 0) { return NULL; diff --git a/src/base_alloc/base_alloc_linear.c b/src/base_alloc/base_alloc_linear.c index be7b0943c..de4ac0b1e 100644 --- a/src/base_alloc/base_alloc_linear.c +++ b/src/base_alloc/base_alloc_linear.c @@ -31,7 +31,7 @@ typedef struct umf_ba_next_linear_pool_t umf_ba_next_linear_pool_t; // metadata is set and used only in the main (the first) pool typedef struct umf_ba_main_linear_pool_meta_t { size_t pool_size; // size of this pool (argument of ba_os_alloc() call) - os_mutex_t lock; + utils_mutex_t lock; char *data_ptr; size_t size_left; size_t pool_n_allocs; // number of allocations in this pool @@ -98,7 +98,7 @@ umf_ba_linear_pool_t *umf_ba_linear_create(size_t pool_size) { void *data_ptr = &pool->data; size_t size_left = pool_size - offsetof(umf_ba_linear_pool_t, data); - util_align_ptr_size(&data_ptr, &size_left, MEMORY_ALIGNMENT); + utils_align_ptr_size(&data_ptr, &size_left, MEMORY_ALIGNMENT); pool->metadata.pool_size = pool_size; pool->metadata.data_ptr = data_ptr; @@ -109,7 +109,7 @@ umf_ba_linear_pool_t *umf_ba_linear_create(size_t pool_size) { _DEBUG_EXECUTE(pool->metadata.global_n_allocs = 0); // init lock - os_mutex_t *lock = util_mutex_init(&pool->metadata.lock); + utils_mutex_t *lock = utils_mutex_init(&pool->metadata.lock); if (!lock) { ba_os_free(pool, pool_size); return NULL; @@ -123,7 +123,7 @@ void *umf_ba_linear_alloc(umf_ba_linear_pool_t *pool, size_t size) { return NULL; } size_t aligned_size = ALIGN_UP(size, MEMORY_ALIGNMENT); - util_mutex_lock(&pool->metadata.lock); + utils_mutex_lock(&pool->metadata.lock); if (pool->metadata.size_left < aligned_size) { size_t pool_size = MINIMUM_LINEAR_POOL_SIZE; size_t usable_size = @@ -139,7 +139,7 @@ void *umf_ba_linear_alloc(umf_ba_linear_pool_t *pool, size_t size) { umf_ba_next_linear_pool_t *new_pool = (umf_ba_next_linear_pool_t *)ba_os_alloc(pool_size); if (!new_pool) { - util_mutex_unlock(&pool->metadata.lock); + utils_mutex_unlock(&pool->metadata.lock); return NULL; } @@ -149,7 +149,7 @@ void *umf_ba_linear_alloc(umf_ba_linear_pool_t *pool, size_t size) { void *data_ptr = &new_pool->data; size_t size_left = new_pool->pool_size - offsetof(umf_ba_next_linear_pool_t, data); - util_align_ptr_size(&data_ptr, &size_left, MEMORY_ALIGNMENT); + utils_align_ptr_size(&data_ptr, &size_left, MEMORY_ALIGNMENT); pool->metadata.data_ptr = data_ptr; pool->metadata.size_left = size_left; @@ -171,7 +171,7 @@ void *umf_ba_linear_alloc(umf_ba_linear_pool_t *pool, size_t size) { } _DEBUG_EXECUTE(pool->metadata.global_n_allocs++); _DEBUG_EXECUTE(ba_debug_checks(pool)); - util_mutex_unlock(&pool->metadata.lock); + utils_mutex_unlock(&pool->metadata.lock); return ptr; } @@ -188,7 +188,7 @@ static inline int pool_contains_ptr(void *pool, size_t pool_size, // 0 - ptr belonged to the pool and was freed // -1 - ptr doesn't belong to the pool and wasn't freed int umf_ba_linear_free(umf_ba_linear_pool_t *pool, void *ptr) { - util_mutex_lock(&pool->metadata.lock); + utils_mutex_lock(&pool->metadata.lock); _DEBUG_EXECUTE(ba_debug_checks(pool)); if (pool_contains_ptr(pool, pool->metadata.pool_size, pool->data, ptr)) { pool->metadata.pool_n_allocs--; @@ -204,7 +204,7 @@ int umf_ba_linear_free(umf_ba_linear_pool_t *pool, void *ptr) { pool->metadata.pool_size = page_size; } _DEBUG_EXECUTE(ba_debug_checks(pool)); - util_mutex_unlock(&pool->metadata.lock); + utils_mutex_unlock(&pool->metadata.lock); return 0; } @@ -227,14 +227,14 @@ int umf_ba_linear_free(umf_ba_linear_pool_t *pool, void *ptr) { ba_os_free(next_pool_ptr, size); } _DEBUG_EXECUTE(ba_debug_checks(pool)); - util_mutex_unlock(&pool->metadata.lock); + utils_mutex_unlock(&pool->metadata.lock); return 0; } prev_pool = next_pool; next_pool = next_pool->next_pool; } - util_mutex_unlock(&pool->metadata.lock); + utils_mutex_unlock(&pool->metadata.lock); // ptr doesn't belong to the pool and wasn't freed return -1; } @@ -243,7 +243,7 @@ void umf_ba_linear_destroy(umf_ba_linear_pool_t *pool) { // Do not destroy if we are running in the proxy library, // because it may need those resources till // the very end of exiting the application. - if (util_is_running_in_proxy_lib()) { + if (utils_is_running_in_proxy_lib()) { return; } @@ -262,7 +262,7 @@ void umf_ba_linear_destroy(umf_ba_linear_pool_t *pool) { ba_os_free(current_pool, current_pool->pool_size); } - util_mutex_destroy_not_free(&pool->metadata.lock); + utils_mutex_destroy_not_free(&pool->metadata.lock); ba_os_free(pool, pool->metadata.pool_size); } @@ -272,12 +272,12 @@ void umf_ba_linear_destroy(umf_ba_linear_pool_t *pool) { // to the end of the pool if ptr belongs to the pool size_t umf_ba_linear_pool_contains_pointer(umf_ba_linear_pool_t *pool, void *ptr) { - util_mutex_lock(&pool->metadata.lock); + utils_mutex_lock(&pool->metadata.lock); char *cptr = (char *)ptr; if (cptr >= pool->data && cptr < ((char *)(pool)) + pool->metadata.pool_size) { size_t size = ((char *)(pool)) + pool->metadata.pool_size - cptr; - util_mutex_unlock(&pool->metadata.lock); + utils_mutex_unlock(&pool->metadata.lock); return size; } @@ -286,12 +286,12 @@ size_t umf_ba_linear_pool_contains_pointer(umf_ba_linear_pool_t *pool, if (cptr >= next_pool->data && cptr < ((char *)(next_pool)) + next_pool->pool_size) { size_t size = ((char *)(next_pool)) + next_pool->pool_size - cptr; - util_mutex_unlock(&pool->metadata.lock); + utils_mutex_unlock(&pool->metadata.lock); return size; } next_pool = next_pool->next_pool; } - util_mutex_unlock(&pool->metadata.lock); + utils_mutex_unlock(&pool->metadata.lock); return 0; } diff --git a/src/base_alloc/base_alloc_linux.c b/src/base_alloc/base_alloc_linux.c index 3e5456b2c..260eec5aa 100644 --- a/src/base_alloc/base_alloc_linux.c +++ b/src/base_alloc/base_alloc_linux.c @@ -37,6 +37,6 @@ void ba_os_free(void *ptr, size_t size) { static void _ba_os_init_page_size(void) { Page_size = sysconf(_SC_PAGE_SIZE); } size_t ba_os_get_page_size(void) { - util_init_once(&Page_size_is_initialized, _ba_os_init_page_size); + utils_init_once(&Page_size_is_initialized, _ba_os_init_page_size); return Page_size; } diff --git a/src/base_alloc/base_alloc_windows.c b/src/base_alloc/base_alloc_windows.c index 6f6c58fbc..2e9da23d9 100644 --- a/src/base_alloc/base_alloc_windows.c +++ b/src/base_alloc/base_alloc_windows.c @@ -28,6 +28,6 @@ static void _ba_os_init_page_size(void) { } size_t ba_os_get_page_size(void) { - util_init_once(&Page_size_is_initialized, _ba_os_init_page_size); + utils_init_once(&Page_size_is_initialized, _ba_os_init_page_size); return Page_size; } diff --git a/src/critnib/critnib.c b/src/critnib/critnib.c index 965ca03b9..62d14af73 100644 --- a/src/critnib/critnib.c +++ b/src/critnib/critnib.c @@ -130,25 +130,25 @@ struct critnib { uint64_t remove_count; - struct os_mutex_t mutex; /* writes/removes */ + struct utils_mutex_t mutex; /* writes/removes */ }; /* * atomic load */ static void load(void *src, void *dst) { - util_atomic_load_acquire((word *)src, (word *)dst); + utils_atomic_load_acquire((word *)src, (word *)dst); } static void load64(uint64_t *src, uint64_t *dst) { - util_atomic_load_acquire(src, dst); + utils_atomic_load_acquire(src, dst); } /* * atomic store */ static void store(void *dst, void *src) { - util_atomic_store_release((word *)dst, (word)src); + utils_atomic_store_release((word *)dst, (word)src); } /* @@ -187,7 +187,7 @@ struct critnib *critnib_new(void) { memset(c, 0, sizeof(struct critnib)); - void *mutex_ptr = util_mutex_init(&c->mutex); + void *mutex_ptr = utils_mutex_init(&c->mutex); if (!mutex_ptr) { goto err_free_critnib; } @@ -226,7 +226,7 @@ void critnib_delete(struct critnib *c) { delete_node(c, c->root); } - util_mutex_destroy_not_free(&c->mutex); + utils_mutex_destroy_not_free(&c->mutex); for (struct critnib_node *m = c->deleted_node; m;) { struct critnib_node *mm = m->child[0]; @@ -325,11 +325,11 @@ static struct critnib_leaf *alloc_leaf(struct critnib *__restrict c) { * Takes a global write lock but doesn't stall any readers. */ int critnib_insert(struct critnib *c, word key, void *value, int update) { - util_mutex_lock(&c->mutex); + utils_mutex_lock(&c->mutex); struct critnib_leaf *k = alloc_leaf(c); if (!k) { - util_mutex_unlock(&c->mutex); + utils_mutex_unlock(&c->mutex); return ENOMEM; } @@ -345,7 +345,7 @@ int critnib_insert(struct critnib *c, word key, void *value, int update) { if (!n) { store(&c->root, kn); - util_mutex_unlock(&c->mutex); + utils_mutex_unlock(&c->mutex); return 0; } @@ -363,7 +363,7 @@ int critnib_insert(struct critnib *c, word key, void *value, int update) { n = prev; store(&n->child[slice_index(key, n->shift)], kn); - util_mutex_unlock(&c->mutex); + utils_mutex_unlock(&c->mutex); return 0; } @@ -377,22 +377,22 @@ int critnib_insert(struct critnib *c, word key, void *value, int update) { if (update) { to_leaf(n)->value = value; - util_mutex_unlock(&c->mutex); + utils_mutex_unlock(&c->mutex); return 0; } else { - util_mutex_unlock(&c->mutex); + utils_mutex_unlock(&c->mutex); return EEXIST; } } /* and convert that to an index. */ - sh_t sh = util_mssb_index(at) & (sh_t) ~(SLICE - 1); + sh_t sh = utils_mssb_index(at) & (sh_t) ~(SLICE - 1); struct critnib_node *m = alloc_node(c); if (!m) { free_leaf(c, to_leaf(kn)); - util_mutex_unlock(&c->mutex); + utils_mutex_unlock(&c->mutex); return ENOMEM; } @@ -408,7 +408,7 @@ int critnib_insert(struct critnib *c, word key, void *value, int update) { m->path = key & path_mask(sh); store(parent, m); - util_mutex_unlock(&c->mutex); + utils_mutex_unlock(&c->mutex); return 0; } @@ -420,14 +420,14 @@ void *critnib_remove(struct critnib *c, word key) { struct critnib_leaf *k; void *value = NULL; - util_mutex_lock(&c->mutex); + utils_mutex_lock(&c->mutex); struct critnib_node *n = c->root; if (!n) { goto not_found; } - word del = (util_atomic_increment(&c->remove_count) - 1) % DELETED_LIFE; + word del = (utils_atomic_increment(&c->remove_count) - 1) % DELETED_LIFE; free_node(c, c->pending_del_nodes[del]); free_leaf(c, c->pending_del_leaves[del]); c->pending_del_nodes[del] = NULL; @@ -490,7 +490,7 @@ void *critnib_remove(struct critnib *c, word key) { c->pending_del_leaves[del] = k; not_found: - util_mutex_unlock(&c->mutex); + utils_mutex_unlock(&c->mutex); return value; } @@ -813,9 +813,9 @@ static int iter(struct critnib_node *__restrict n, word min, word max, void critnib_iter(critnib *c, uintptr_t min, uintptr_t max, int (*func)(uintptr_t key, void *value, void *privdata), void *privdata) { - util_mutex_lock(&c->mutex); + utils_mutex_lock(&c->mutex); if (c->root) { iter(c->root, min, max, func, privdata); } - util_mutex_unlock(&c->mutex); + utils_mutex_unlock(&c->mutex); } diff --git a/src/libumf.c b/src/libumf.c index 1d99ab26a..2fcda07a0 100644 --- a/src/libumf.c +++ b/src/libumf.c @@ -22,8 +22,8 @@ umf_memory_tracker_handle_t TRACKER = NULL; static unsigned long long umfRefCount = 0; int umfInit(void) { - if (util_fetch_and_add64(&umfRefCount, 1) == 0) { - util_log_init(); + if (utils_fetch_and_add64(&umfRefCount, 1) == 0) { + utils_log_init(); TRACKER = umfMemoryTrackerCreate(); } @@ -31,7 +31,7 @@ int umfInit(void) { } void umfTearDown(void) { - if (util_fetch_and_add64(&umfRefCount, -1) == 1) { + if (utils_fetch_and_add64(&umfRefCount, -1) == 1) { #if !defined(_WIN32) && !defined(UMF_NO_HWLOC) umfMemspaceHostAllDestroy(); umfMemspaceHighestCapacityDestroy(); diff --git a/src/memspaces/memspace_highest_bandwidth.c b/src/memspaces/memspace_highest_bandwidth.c index 3fb721717..a6ea558d7 100644 --- a/src/memspaces/memspace_highest_bandwidth.c +++ b/src/memspaces/memspace_highest_bandwidth.c @@ -96,7 +96,7 @@ static void umfMemspaceHighestBandwidthInit(void) { } umf_const_memspace_handle_t umfMemspaceHighestBandwidthGet(void) { - util_init_once(&UMF_MEMSPACE_HBW_INITIALIZED, - umfMemspaceHighestBandwidthInit); + utils_init_once(&UMF_MEMSPACE_HBW_INITIALIZED, + umfMemspaceHighestBandwidthInit); return UMF_MEMSPACE_HIGHEST_BANDWIDTH; } diff --git a/src/memspaces/memspace_highest_capacity.c b/src/memspaces/memspace_highest_capacity.c index 2469ba496..8a4e19148 100644 --- a/src/memspaces/memspace_highest_capacity.c +++ b/src/memspaces/memspace_highest_capacity.c @@ -68,7 +68,7 @@ static void umfMemspaceHighestCapacityInit(void) { } umf_const_memspace_handle_t umfMemspaceHighestCapacityGet(void) { - util_init_once(&UMF_MEMSPACE_HIGHEST_CAPACITY_INITIALIZED, - umfMemspaceHighestCapacityInit); + utils_init_once(&UMF_MEMSPACE_HIGHEST_CAPACITY_INITIALIZED, + umfMemspaceHighestCapacityInit); return UMF_MEMSPACE_HIGHEST_CAPACITY; } diff --git a/src/memspaces/memspace_host_all.c b/src/memspaces/memspace_host_all.c index 63d4611a8..09d5877c3 100644 --- a/src/memspaces/memspace_host_all.c +++ b/src/memspaces/memspace_host_all.c @@ -90,6 +90,6 @@ static void umfMemspaceHostAllInit(void) { } umf_const_memspace_handle_t umfMemspaceHostAllGet(void) { - util_init_once(&UMF_MEMSPACE_HOST_ALL_INITIALIZED, umfMemspaceHostAllInit); + utils_init_once(&UMF_MEMSPACE_HOST_ALL_INITIALIZED, umfMemspaceHostAllInit); return UMF_MEMSPACE_HOST_ALL; } diff --git a/src/memspaces/memspace_lowest_latency.c b/src/memspaces/memspace_lowest_latency.c index 9a34e3f83..52f8e7f36 100644 --- a/src/memspaces/memspace_lowest_latency.c +++ b/src/memspaces/memspace_lowest_latency.c @@ -96,7 +96,7 @@ static void umfMemspaceLowestLatencyInit(void) { } umf_const_memspace_handle_t umfMemspaceLowestLatencyGet(void) { - util_init_once(&UMF_MEMSPACE_LOWEST_LATENCY_INITIALIZED, - umfMemspaceLowestLatencyInit); + utils_init_once(&UMF_MEMSPACE_LOWEST_LATENCY_INITIALIZED, + umfMemspaceLowestLatencyInit); return UMF_MEMSPACE_LOWEST_LATENCY; } diff --git a/src/pool/pool_scalable.c b/src/pool/pool_scalable.c index cb5d5b157..ebf42493c 100644 --- a/src/pool/pool_scalable.c +++ b/src/pool/pool_scalable.c @@ -106,7 +106,7 @@ static int init_tbb_callbacks(tbb_callbacks_t *tbb_callbacks) { assert(tbb_callbacks); const char *lib_name = tbb_symbol[TBB_LIB_NAME]; - tbb_callbacks->lib_handle = util_open_library(lib_name, 0); + tbb_callbacks->lib_handle = utils_open_library(lib_name, 0); if (!tbb_callbacks->lib_handle) { LOG_ERR("%s required by Scalable Pool not found - install TBB malloc " "or make sure it is in the default search paths.", @@ -114,22 +114,22 @@ static int init_tbb_callbacks(tbb_callbacks_t *tbb_callbacks) { return -1; } - *(void **)&tbb_callbacks->pool_malloc = util_get_symbol_addr( + *(void **)&tbb_callbacks->pool_malloc = utils_get_symbol_addr( tbb_callbacks->lib_handle, tbb_symbol[TBB_POOL_MALLOC], lib_name); - *(void **)&tbb_callbacks->pool_realloc = util_get_symbol_addr( + *(void **)&tbb_callbacks->pool_realloc = utils_get_symbol_addr( tbb_callbacks->lib_handle, tbb_symbol[TBB_POOL_REALLOC], lib_name); *(void **)&tbb_callbacks->pool_aligned_malloc = - util_get_symbol_addr(tbb_callbacks->lib_handle, - tbb_symbol[TBB_POOL_ALIGNED_MALLOC], lib_name); - *(void **)&tbb_callbacks->pool_free = util_get_symbol_addr( + utils_get_symbol_addr(tbb_callbacks->lib_handle, + tbb_symbol[TBB_POOL_ALIGNED_MALLOC], lib_name); + *(void **)&tbb_callbacks->pool_free = utils_get_symbol_addr( tbb_callbacks->lib_handle, tbb_symbol[TBB_POOL_FREE], lib_name); - *(void **)&tbb_callbacks->pool_create_v1 = util_get_symbol_addr( + *(void **)&tbb_callbacks->pool_create_v1 = utils_get_symbol_addr( tbb_callbacks->lib_handle, tbb_symbol[TBB_POOL_CREATE_V1], lib_name); - *(void **)&tbb_callbacks->pool_destroy = util_get_symbol_addr( + *(void **)&tbb_callbacks->pool_destroy = utils_get_symbol_addr( tbb_callbacks->lib_handle, tbb_symbol[TBB_POOL_DESTROY], lib_name); - *(void **)&tbb_callbacks->pool_identify = util_get_symbol_addr( + *(void **)&tbb_callbacks->pool_identify = utils_get_symbol_addr( tbb_callbacks->lib_handle, tbb_symbol[TBB_POOL_IDENTIFY], lib_name); - *(void **)&tbb_callbacks->pool_msize = util_get_symbol_addr( + *(void **)&tbb_callbacks->pool_msize = utils_get_symbol_addr( tbb_callbacks->lib_handle, tbb_symbol[TBB_POOL_MSIZE], lib_name); if (!tbb_callbacks->pool_malloc || !tbb_callbacks->pool_realloc || @@ -137,7 +137,7 @@ static int init_tbb_callbacks(tbb_callbacks_t *tbb_callbacks) { !tbb_callbacks->pool_create_v1 || !tbb_callbacks->pool_destroy || !tbb_callbacks->pool_identify) { LOG_ERR("Could not find symbols in %s", lib_name); - util_close_library(tbb_callbacks->lib_handle); + utils_close_library(tbb_callbacks->lib_handle); return -1; } @@ -208,7 +208,7 @@ static umf_result_t tbb_pool_initialize(umf_memory_provider_handle_t provider, static void tbb_pool_finalize(void *pool) { tbb_memory_pool_t *pool_data = (tbb_memory_pool_t *)pool; pool_data->tbb_callbacks.pool_destroy(pool_data->tbb_pool); - util_close_library(pool_data->tbb_callbacks.lib_handle); + utils_close_library(pool_data->tbb_callbacks.lib_handle); umf_ba_global_free(pool_data); } diff --git a/src/provider/provider_cuda.c b/src/provider/provider_cuda.c index d72c47022..b7c4a308d 100644 --- a/src/provider/provider_cuda.c +++ b/src/provider/provider_cuda.c @@ -93,21 +93,21 @@ static void init_cu_global_state(void) { // NOTE: some symbols defined in the lib have _vX postfixes - it is // important to load the proper version of functions *(void **)&g_cu_ops.cuMemGetAllocationGranularity = - util_get_symbol_addr(0, "cuMemGetAllocationGranularity", lib_name); + utils_get_symbol_addr(0, "cuMemGetAllocationGranularity", lib_name); *(void **)&g_cu_ops.cuMemAlloc = - util_get_symbol_addr(0, "cuMemAlloc_v2", lib_name); + utils_get_symbol_addr(0, "cuMemAlloc_v2", lib_name); *(void **)&g_cu_ops.cuMemAllocHost = - util_get_symbol_addr(0, "cuMemAllocHost_v2", lib_name); + utils_get_symbol_addr(0, "cuMemAllocHost_v2", lib_name); *(void **)&g_cu_ops.cuMemAllocManaged = - util_get_symbol_addr(0, "cuMemAllocManaged", lib_name); + utils_get_symbol_addr(0, "cuMemAllocManaged", lib_name); *(void **)&g_cu_ops.cuMemFree = - util_get_symbol_addr(0, "cuMemFree_v2", lib_name); + utils_get_symbol_addr(0, "cuMemFree_v2", lib_name); *(void **)&g_cu_ops.cuMemFreeHost = - util_get_symbol_addr(0, "cuMemFreeHost", lib_name); + utils_get_symbol_addr(0, "cuMemFreeHost", lib_name); *(void **)&g_cu_ops.cuGetErrorName = - util_get_symbol_addr(0, "cuGetErrorName", lib_name); + utils_get_symbol_addr(0, "cuGetErrorName", lib_name); *(void **)&g_cu_ops.cuGetErrorString = - util_get_symbol_addr(0, "cuGetErrorString", lib_name); + utils_get_symbol_addr(0, "cuGetErrorString", lib_name); if (!g_cu_ops.cuMemGetAllocationGranularity || !g_cu_ops.cuMemAlloc || !g_cu_ops.cuMemAllocHost || !g_cu_ops.cuMemAllocManaged || @@ -136,7 +136,7 @@ static umf_result_t cu_memory_provider_initialize(void *params, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - util_init_once(&cu_is_initialized, init_cu_global_state); + utils_init_once(&cu_is_initialized, init_cu_global_state); if (Init_cu_global_state_failed) { LOG_ERR("Loading CUDA symbols failed"); return UMF_RESULT_ERROR_UNKNOWN; diff --git a/src/provider/provider_devdax_memory.c b/src/provider/provider_devdax_memory.c index 321c68d9c..ed0c2a25d 100644 --- a/src/provider/provider_devdax_memory.c +++ b/src/provider/provider_devdax_memory.c @@ -31,7 +31,7 @@ typedef struct devdax_memory_provider_t { size_t size; // size of the file used for memory mapping void *base; // base address of memory mapping size_t offset; // offset in the file used for memory mapping - os_mutex_t lock; // lock of ptr and offset + utils_mutex_t lock; // lock of ptr and offset unsigned protection; // combination of OS-specific protection flags } devdax_memory_provider_t; @@ -119,7 +119,7 @@ static umf_result_t devdax_initialize(void *params, void **provider) { } devdax_provider->size = in_params->size; - if (util_copy_path(in_params->path, devdax_provider->path, PATH_MAX)) { + if (utils_copy_path(in_params->path, devdax_provider->path, PATH_MAX)) { goto err_free_devdax_provider; } @@ -143,7 +143,7 @@ static umf_result_t devdax_initialize(void *params, void **provider) { LOG_DEBUG("devdax memory mapped (path=%s, size=%zu, addr=%p)", in_params->path, devdax_provider->size, devdax_provider->base); - if (util_mutex_init(&devdax_provider->lock) == NULL) { + if (utils_mutex_init(&devdax_provider->lock) == NULL) { LOG_ERR("lock init failed"); ret = UMF_RESULT_ERROR_UNKNOWN; goto err_unmap_devdax; @@ -167,17 +167,17 @@ static void devdax_finalize(void *provider) { } devdax_memory_provider_t *devdax_provider = provider; - util_mutex_destroy_not_free(&devdax_provider->lock); + utils_mutex_destroy_not_free(&devdax_provider->lock); utils_munmap(devdax_provider->base, devdax_provider->size); umf_ba_global_free(devdax_provider); } static int devdax_alloc_aligned(size_t length, size_t alignment, void *base, - size_t size, os_mutex_t *lock, void **out_addr, - size_t *offset) { + size_t size, utils_mutex_t *lock, + void **out_addr, size_t *offset) { assert(out_addr); - if (util_mutex_lock(lock)) { + if (utils_mutex_lock(lock)) { LOG_ERR("locking file offset failed"); return -1; } @@ -192,7 +192,7 @@ static int devdax_alloc_aligned(size_t length, size_t alignment, void *base, size_t new_offset = ptr - (uintptr_t)base + length; if (new_offset > size) { - util_mutex_unlock(lock); + utils_mutex_unlock(lock); LOG_ERR("cannot allocate more memory than the device DAX size: %zu", size); return -1; @@ -201,7 +201,7 @@ static int devdax_alloc_aligned(size_t length, size_t alignment, void *base, *offset = new_offset; *out_addr = (void *)ptr; - util_mutex_unlock(lock); + utils_mutex_unlock(lock); return 0; } @@ -295,7 +295,7 @@ static umf_result_t devdax_get_recommended_page_size(void *provider, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - *page_size = util_get_page_size(); + *page_size = utils_get_page_size(); return UMF_RESULT_SUCCESS; } diff --git a/src/provider/provider_file_memory.c b/src/provider/provider_file_memory.c index 0936daaf0..757dcb1d0 100644 --- a/src/provider/provider_file_memory.c +++ b/src/provider/provider_file_memory.c @@ -26,7 +26,7 @@ #define TLS_MSG_BUF_LEN 1024 typedef struct file_memory_provider_t { - os_mutex_t lock; // lock for file parameters (size and offsets) + utils_mutex_t lock; // lock for file parameters (size and offsets) char path[PATH_MAX]; // a path to the file int fd; // file descriptor for memory mapping @@ -114,7 +114,7 @@ static umf_result_t file_initialize(void *params, void **provider) { umf_file_memory_provider_params_t *in_params = (umf_file_memory_provider_params_t *)params; - size_t page_size = util_get_page_size(); + size_t page_size = utils_get_page_size(); if (in_params->path == NULL) { LOG_ERR("file path is missing"); @@ -136,7 +136,7 @@ static umf_result_t file_initialize(void *params, void **provider) { goto err_free_file_provider; } - if (util_copy_path(in_params->path, file_provider->path, PATH_MAX)) { + if (utils_copy_path(in_params->path, file_provider->path, PATH_MAX)) { goto err_free_file_provider; } @@ -158,7 +158,7 @@ static umf_result_t file_initialize(void *params, void **provider) { LOG_DEBUG("size of the file %s is: %zu", in_params->path, file_provider->size_fd); - if (util_mutex_init(&file_provider->lock) == NULL) { + if (utils_mutex_init(&file_provider->lock) == NULL) { LOG_ERR("lock init failed"); ret = UMF_RESULT_ERROR_UNKNOWN; goto err_close_fd; @@ -185,7 +185,7 @@ static umf_result_t file_initialize(void *params, void **provider) { err_delete_fd_offset_map: critnib_delete(file_provider->fd_offset_map); err_mutex_destroy_not_free: - util_mutex_destroy_not_free(&file_provider->lock); + utils_mutex_destroy_not_free(&file_provider->lock); err_close_fd: utils_close_fd(file_provider->fd); err_free_file_provider: @@ -211,7 +211,7 @@ static void file_finalize(void *provider) { key = rkey; } - util_mutex_destroy_not_free(&file_provider->lock); + utils_mutex_destroy_not_free(&file_provider->lock); utils_close_fd(file_provider->fd); critnib_delete(file_provider->fd_offset_map); critnib_delete(file_provider->mmaps); @@ -291,7 +291,7 @@ static umf_result_t file_alloc_aligned(file_memory_provider_t *file_provider, umf_result_t umf_result; - if (util_mutex_lock(&file_provider->lock)) { + if (utils_mutex_lock(&file_provider->lock)) { LOG_ERR("locking file data failed"); return UMF_RESULT_ERROR_UNKNOWN; } @@ -299,7 +299,7 @@ static umf_result_t file_alloc_aligned(file_memory_provider_t *file_provider, if (file_provider->size_mmap - file_provider->offset_mmap < size) { umf_result = file_mmap_aligned(file_provider, size, alignment); if (umf_result != UMF_RESULT_SUCCESS) { - util_mutex_unlock(&file_provider->lock); + utils_mutex_unlock(&file_provider->lock); return umf_result; } } @@ -321,7 +321,7 @@ static umf_result_t file_alloc_aligned(file_memory_provider_t *file_provider, if (file_provider->size_mmap - new_offset_mmap < size) { umf_result = file_mmap_aligned(file_provider, size, alignment); if (umf_result != UMF_RESULT_SUCCESS) { - util_mutex_unlock(&file_provider->lock); + utils_mutex_unlock(&file_provider->lock); return umf_result; } } @@ -334,7 +334,7 @@ static umf_result_t file_alloc_aligned(file_memory_provider_t *file_provider, *out_addr = (void *)new_aligned_ptr; - util_mutex_unlock(&file_provider->lock); + utils_mutex_unlock(&file_provider->lock); return UMF_RESULT_SUCCESS; } @@ -436,7 +436,7 @@ static umf_result_t file_get_recommended_page_size(void *provider, size_t size, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - *page_size = util_get_page_size(); + *page_size = utils_get_page_size(); return UMF_RESULT_SUCCESS; } diff --git a/src/provider/provider_level_zero.c b/src/provider/provider_level_zero.c index 19a0dfb0d..6c2cf84b1 100644 --- a/src/provider/provider_level_zero.c +++ b/src/provider/provider_level_zero.c @@ -92,25 +92,25 @@ static void init_ze_global_state(void) { // check if Level Zero shared library is already loaded // we pass 0 as a handle to search the global symbol table *(void **)&g_ze_ops.zeMemAllocHost = - util_get_symbol_addr(0, "zeMemAllocHost", lib_name); + utils_get_symbol_addr(0, "zeMemAllocHost", lib_name); *(void **)&g_ze_ops.zeMemAllocDevice = - util_get_symbol_addr(0, "zeMemAllocDevice", lib_name); + utils_get_symbol_addr(0, "zeMemAllocDevice", lib_name); *(void **)&g_ze_ops.zeMemAllocShared = - util_get_symbol_addr(0, "zeMemAllocShared", lib_name); + utils_get_symbol_addr(0, "zeMemAllocShared", lib_name); *(void **)&g_ze_ops.zeMemFree = - util_get_symbol_addr(0, "zeMemFree", lib_name); + utils_get_symbol_addr(0, "zeMemFree", lib_name); *(void **)&g_ze_ops.zeMemGetIpcHandle = - util_get_symbol_addr(0, "zeMemGetIpcHandle", lib_name); + utils_get_symbol_addr(0, "zeMemGetIpcHandle", lib_name); *(void **)&g_ze_ops.zeMemPutIpcHandle = - util_get_symbol_addr(0, "zeMemPutIpcHandle", lib_name); + utils_get_symbol_addr(0, "zeMemPutIpcHandle", lib_name); *(void **)&g_ze_ops.zeMemOpenIpcHandle = - util_get_symbol_addr(0, "zeMemOpenIpcHandle", lib_name); + utils_get_symbol_addr(0, "zeMemOpenIpcHandle", lib_name); *(void **)&g_ze_ops.zeMemCloseIpcHandle = - util_get_symbol_addr(0, "zeMemCloseIpcHandle", lib_name); + utils_get_symbol_addr(0, "zeMemCloseIpcHandle", lib_name); *(void **)&g_ze_ops.zeContextMakeMemoryResident = - util_get_symbol_addr(0, "zeContextMakeMemoryResident", lib_name); + utils_get_symbol_addr(0, "zeContextMakeMemoryResident", lib_name); *(void **)&g_ze_ops.zeDeviceGetProperties = - util_get_symbol_addr(0, "zeDeviceGetProperties", lib_name); + utils_get_symbol_addr(0, "zeDeviceGetProperties", lib_name); if (!g_ze_ops.zeMemAllocHost || !g_ze_ops.zeMemAllocDevice || !g_ze_ops.zeMemAllocShared || !g_ze_ops.zeMemFree || @@ -148,7 +148,7 @@ static umf_result_t ze_memory_provider_initialize(void *params, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - util_init_once(&ze_is_initialized, init_ze_global_state); + utils_init_once(&ze_is_initialized, init_ze_global_state); if (Init_ze_global_state_failed) { LOG_ERR("Loading Level Zero symbols failed"); return UMF_RESULT_ERROR_UNKNOWN; @@ -188,7 +188,7 @@ static void ze_memory_provider_finalize(void *provider) { return; } - util_init_once(&ze_is_initialized, init_ze_global_state); + utils_init_once(&ze_is_initialized, init_ze_global_state); umf_ba_global_free(provider); // portable version of "ze_is_initialized = UTIL_ONCE_FLAG_INIT;" diff --git a/src/provider/provider_os_memory.c b/src/provider/provider_os_memory.c index fe2505dce..8c18e98cc 100644 --- a/src/provider/provider_os_memory.c +++ b/src/provider/provider_os_memory.c @@ -501,7 +501,7 @@ static umf_result_t os_initialize(void *params, void **provider) { } if (os_provider->fd > 0) { - if (util_mutex_init(&os_provider->lock_fd) == NULL) { + if (utils_mutex_init(&os_provider->lock_fd) == NULL) { LOG_ERR("initializing the file size lock failed"); ret = UMF_RESULT_ERROR_UNKNOWN; goto err_destroy_bitmaps; @@ -546,7 +546,7 @@ static void os_finalize(void *provider) { os_memory_provider_t *os_provider = provider; if (os_provider->fd > 0) { - util_mutex_destroy_not_free(&os_provider->lock_fd); + utils_mutex_destroy_not_free(&os_provider->lock_fd); } critnib_delete(os_provider->fd_offset_map); @@ -611,7 +611,7 @@ static inline void assert_is_page_aligned(uintptr_t ptr, size_t page_size) { static int utils_mmap_aligned(void *hint_addr, size_t length, size_t alignment, size_t page_size, int prot, int flag, int fd, - size_t max_fd_size, os_mutex_t *lock_fd, + size_t max_fd_size, utils_mutex_t *lock_fd, void **out_addr, size_t *fd_size, size_t *fd_offset) { assert(out_addr); @@ -629,20 +629,20 @@ static int utils_mmap_aligned(void *hint_addr, size_t length, size_t alignment, *fd_offset = 0; if (fd > 0) { - if (util_mutex_lock(lock_fd)) { + if (utils_mutex_lock(lock_fd)) { LOG_ERR("locking file size failed"); return -1; } if (*fd_size + extended_length > max_fd_size) { - util_mutex_unlock(lock_fd); + utils_mutex_unlock(lock_fd); LOG_ERR("cannot grow a file size beyond %zu", max_fd_size); return -1; } *fd_offset = *fd_size; *fd_size += extended_length; - util_mutex_unlock(lock_fd); + utils_mutex_unlock(lock_fd); } void *ptr = @@ -815,7 +815,7 @@ static membind_t membindFirst(os_memory_provider_t *provider, void *addr, if (provider->mode == UMF_NUMA_MODE_INTERLEAVE) { assert(provider->part_size != 0); - size_t s = util_fetch_and_add64(&provider->alloc_sum, size); + size_t s = utils_fetch_and_add64(&provider->alloc_sum, size); membind.node = (s / provider->part_size) % provider->nodeset_len; membind.bitmap = provider->nodeset[membind.node]; membind.bind_size = ALIGN_UP(provider->part_size, membind.page_size); @@ -1034,7 +1034,7 @@ static umf_result_t os_get_recommended_page_size(void *provider, size_t size, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - *page_size = util_get_page_size(); + *page_size = utils_get_page_size(); return UMF_RESULT_SUCCESS; } diff --git a/src/provider/provider_os_memory_internal.h b/src/provider/provider_os_memory_internal.h index e01a3de75..41b4ea11a 100644 --- a/src/provider/provider_os_memory_internal.h +++ b/src/provider/provider_os_memory_internal.h @@ -31,10 +31,10 @@ typedef struct os_memory_provider_t { unsigned visibility; // memory visibility mode // a name of a shared memory file (valid only in case of the shared memory visibility) char shm_name[NAME_MAX]; - int fd; // file descriptor for memory mapping - size_t size_fd; // size of file used for memory mapping - size_t max_size_fd; // maximum size of file used for memory mapping - os_mutex_t lock_fd; // lock for updating file size + int fd; // file descriptor for memory mapping + size_t size_fd; // size of file used for memory mapping + size_t max_size_fd; // maximum size of file used for memory mapping + utils_mutex_t lock_fd; // lock for updating file size // A critnib map storing (ptr, fd_offset + 1) pairs. We add 1 to fd_offset // in order to be able to store fd_offset equal 0, because diff --git a/src/provider/provider_tracking.c b/src/provider/provider_tracking.c index 726f7d4e8..5e1db9d14 100644 --- a/src/provider/provider_tracking.c +++ b/src/provider/provider_tracking.c @@ -184,7 +184,7 @@ static umf_result_t trackingAllocationSplit(void *hProvider, void *ptr, splitValue->pool = provider->pool; splitValue->size = firstSize; - int r = util_mutex_lock(&provider->hTracker->splitMergeMutex); + int r = utils_mutex_lock(&provider->hTracker->splitMergeMutex); if (r) { goto err_lock; } @@ -235,12 +235,12 @@ static umf_result_t trackingAllocationSplit(void *hProvider, void *ptr, // free the original value umf_ba_free(provider->hTracker->tracker_allocator, value); - util_mutex_unlock(&provider->hTracker->splitMergeMutex); + utils_mutex_unlock(&provider->hTracker->splitMergeMutex); return UMF_RESULT_SUCCESS; err: - util_mutex_unlock(&provider->hTracker->splitMergeMutex); + utils_mutex_unlock(&provider->hTracker->splitMergeMutex); err_lock: umf_ba_free(provider->hTracker->tracker_allocator, splitValue); return ret; @@ -262,7 +262,7 @@ static umf_result_t trackingAllocationMerge(void *hProvider, void *lowPtr, mergedValue->pool = provider->pool; mergedValue->size = totalSize; - int r = util_mutex_lock(&provider->hTracker->splitMergeMutex); + int r = utils_mutex_lock(&provider->hTracker->splitMergeMutex); if (r) { goto err_lock; } @@ -316,12 +316,12 @@ static umf_result_t trackingAllocationMerge(void *hProvider, void *lowPtr, umf_ba_free(provider->hTracker->tracker_allocator, erasedhighValue); - util_mutex_unlock(&provider->hTracker->splitMergeMutex); + utils_mutex_unlock(&provider->hTracker->splitMergeMutex); return UMF_RESULT_SUCCESS; err: - util_mutex_unlock(&provider->hTracker->splitMergeMutex); + utils_mutex_unlock(&provider->hTracker->splitMergeMutex); err_lock: umf_ba_free(provider->hTracker->tracker_allocator, mergedValue); return ret; @@ -414,7 +414,7 @@ static void check_if_tracker_is_empty(umf_memory_tracker_handle_t hTracker, // Do not assert if we are running in the proxy library, // because it may need those resources till // the very end of exiting the application. - if (!util_is_running_in_proxy_lib()) { + if (!utils_is_running_in_proxy_lib()) { if (pool) { LOG_ERR("tracking provider of pool %p is not empty! " "(%zu items left)", @@ -710,7 +710,7 @@ umf_memory_tracker_handle_t umfMemoryTrackerCreate(void) { handle->tracker_allocator = tracker_allocator; - void *mutex_ptr = util_mutex_init(&handle->splitMergeMutex); + void *mutex_ptr = utils_mutex_init(&handle->splitMergeMutex); if (!mutex_ptr) { goto err_destroy_tracker_allocator; } @@ -726,7 +726,7 @@ umf_memory_tracker_handle_t umfMemoryTrackerCreate(void) { return handle; err_destroy_mutex: - util_mutex_destroy_not_free(&handle->splitMergeMutex); + utils_mutex_destroy_not_free(&handle->splitMergeMutex); err_destroy_tracker_allocator: umf_ba_destroy(tracker_allocator); err_free_handle: @@ -742,7 +742,7 @@ void umfMemoryTrackerDestroy(umf_memory_tracker_handle_t handle) { // Do not destroy if we are running in the proxy library, // because it may need those resources till // the very end of exiting the application. - if (util_is_running_in_proxy_lib()) { + if (utils_is_running_in_proxy_lib()) { return; } @@ -755,7 +755,7 @@ void umfMemoryTrackerDestroy(umf_memory_tracker_handle_t handle) { // and used in many places. critnib_delete(handle->map); handle->map = NULL; - util_mutex_destroy_not_free(&handle->splitMergeMutex); + utils_mutex_destroy_not_free(&handle->splitMergeMutex); umf_ba_destroy(handle->tracker_allocator); handle->tracker_allocator = NULL; umf_ba_global_free(handle); diff --git a/src/provider/provider_tracking.h b/src/provider/provider_tracking.h index 585b4fe5c..f020c3da8 100644 --- a/src/provider/provider_tracking.h +++ b/src/provider/provider_tracking.h @@ -28,7 +28,7 @@ extern "C" { struct umf_memory_tracker_t { umf_ba_pool_t *tracker_allocator; critnib *map; - os_mutex_t splitMergeMutex; + utils_mutex_t splitMergeMutex; }; typedef struct umf_memory_tracker_t *umf_memory_tracker_handle_t; diff --git a/src/proxy_lib/proxy_lib.c b/src/proxy_lib/proxy_lib.c index 4819313d1..ca8d69315 100644 --- a/src/proxy_lib/proxy_lib.c +++ b/src/proxy_lib/proxy_lib.c @@ -59,7 +59,7 @@ #define UTIL_ONCE_FLAG INIT_ONCE #define UTIL_ONCE_FLAG_INIT INIT_ONCE_STATIC_INIT -void util_init_once(UTIL_ONCE_FLAG *flag, void (*onceCb)(void)); +void utils_init_once(UTIL_ONCE_FLAG *flag, void (*onceCb)(void)); #else /* Linux *************************************************/ @@ -108,7 +108,7 @@ static __TLS int was_called_from_umfPool = 0; /*****************************************************************************/ void proxy_lib_create_common(void) { - util_log_init(); + utils_log_init(); umf_os_memory_provider_params_t os_params = umfOsMemoryProviderParamsDefault(); umf_result_t umf_result; @@ -116,14 +116,14 @@ void proxy_lib_create_common(void) { #ifndef _WIN32 char shm_name[NAME_MAX]; - if (util_env_var_has_str("UMF_PROXY", "page.disposition=shared-fd")) { + if (utils_env_var_has_str("UMF_PROXY", "page.disposition=shared-fd")) { LOG_DEBUG("proxy_lib: using the MAP_SHARED visibility mode with the " "file descriptor duplication"); os_params.visibility = UMF_MEM_MAP_SHARED; os_params.shm_name = NULL; - } else if (util_env_var_has_str("UMF_PROXY", - "page.disposition=shared-shm")) { + } else if (utils_env_var_has_str("UMF_PROXY", + "page.disposition=shared-shm")) { LOG_DEBUG("proxy_lib: using the MAP_SHARED visibility mode with the " "named shared memory"); os_params.visibility = UMF_MEM_MAP_SHARED; @@ -157,7 +157,7 @@ void proxy_lib_create_common(void) { } void proxy_lib_destroy_common(void) { - if (util_is_running_in_proxy_lib()) { + if (utils_is_running_in_proxy_lib()) { // We cannot destroy 'Base_alloc_leak' nor 'Proxy_pool' nor 'OS_memory_provider', // because it could lead to use-after-free in the program's unloader // (for example _dl_fini() on Linux). @@ -209,7 +209,7 @@ static void ba_leak_create(void) { Base_alloc_leak = umf_ba_linear_create(0); } // it does not implement destroy(), because we cannot destroy non-freed memory static void ba_leak_init_once(void) { - util_init_once(&Base_alloc_leak_initialized, ba_leak_create); + utils_init_once(&Base_alloc_leak_initialized, ba_leak_create); } static inline void *ba_leak_malloc(size_t size) { diff --git a/src/topology.c b/src/topology.c index 79caffdb6..eab7992ce 100644 --- a/src/topology.c +++ b/src/topology.c @@ -41,6 +41,6 @@ static void umfCreateTopology(void) { } hwloc_topology_t umfGetTopology(void) { - util_init_once(&topology_initialized, umfCreateTopology); + utils_init_once(&topology_initialized, umfCreateTopology); return topology; } diff --git a/src/utils/utils_common.c b/src/utils/utils_common.c index 5ae1be3a1..cf1a953df 100644 --- a/src/utils/utils_common.c +++ b/src/utils/utils_common.c @@ -13,7 +13,7 @@ #include "utils_common.h" // align a pointer and a size -void util_align_ptr_size(void **ptr, size_t *size, size_t alignment) { +void utils_align_ptr_size(void **ptr, size_t *size, size_t alignment) { uintptr_t p = (uintptr_t)*ptr; size_t s = *size; @@ -31,7 +31,7 @@ void util_align_ptr_size(void **ptr, size_t *size, size_t alignment) { *size = s; } -int util_env_var_has_str(const char *envvar, const char *str) { +int utils_env_var_has_str(const char *envvar, const char *str) { char *value = getenv(envvar); if (value && strstr(value, str)) { return 1; @@ -41,12 +41,12 @@ int util_env_var_has_str(const char *envvar, const char *str) { } // check if we are running in the proxy library -int util_is_running_in_proxy_lib(void) { - return util_env_var_has_str("LD_PRELOAD", "libumf_proxy.so"); +int utils_is_running_in_proxy_lib(void) { + return utils_env_var_has_str("LD_PRELOAD", "libumf_proxy.so"); } -const char *util_parse_var(const char *var, const char *option, - const char **extraArg) { +const char *utils_parse_var(const char *var, const char *option, + const char **extraArg) { const char *found = strstr(var, option); // ensure that found string is first on list or it's a separating semicolon if (!found) { @@ -76,7 +76,7 @@ const char *util_parse_var(const char *var, const char *option, return found; } -int util_copy_path(const char *in_path, char out_path[], size_t path_max) { +int utils_copy_path(const char *in_path, char out_path[], size_t path_max) { // (- 1) because there should be a room for the terminating null byte ('\0') size_t max_len = path_max - 1; diff --git a/src/utils/utils_common.h b/src/utils/utils_common.h index a9796415f..a58614061 100644 --- a/src/utils/utils_common.h +++ b/src/utils/utils_common.h @@ -54,9 +54,9 @@ typedef enum umf_purge_advise_t { #endif /* _WIN32 */ // Check if the environment variable contains the given string. -int util_env_var_has_str(const char *envvar, const char *str); +int utils_env_var_has_str(const char *envvar, const char *str); -// util_parse_var - Parses var for a prefix, +// utils_parse_var - Parses var for a prefix, // optionally identifying a following argument. // Parameters: // - var: String to parse in "option1;option2,arg2;..." format, with options @@ -70,16 +70,16 @@ int util_env_var_has_str(const char *envvar, const char *str); // // IMPORTANT: Both extraArg and return values are pointers within var, // and are not null-terminated. -const char *util_parse_var(const char *var, const char *option, - const char **extraArg); +const char *utils_parse_var(const char *var, const char *option, + const char **extraArg); // check if we are running in the proxy library -int util_is_running_in_proxy_lib(void); +int utils_is_running_in_proxy_lib(void); -size_t util_get_page_size(void); +size_t utils_get_page_size(void); // align a pointer and a size -void util_align_ptr_size(void **ptr, size_t *size, size_t alignment); +void utils_align_ptr_size(void **ptr, size_t *size, size_t alignment); // get the current process ID int utils_getpid(void); @@ -93,7 +93,7 @@ int utils_close_fd(int fd); // obtain a duplicate of another process's file descriptor umf_result_t utils_duplicate_fd(int pid, int fd_in, int *fd_out); -int util_copy_path(const char *in_path, char out_path[], size_t path_max); +int utils_copy_path(const char *in_path, char out_path[], size_t path_max); umf_result_t utils_translate_flags(unsigned in_flags, unsigned max, umf_result_t (*translate_flag)(unsigned, diff --git a/src/utils/utils_concurrency.h b/src/utils/utils_concurrency.h index dcc67dc42..f48c6f910 100644 --- a/src/utils/utils_concurrency.h +++ b/src/utils/utils_concurrency.h @@ -36,19 +36,19 @@ extern "C" { #endif -typedef struct os_mutex_t { +typedef struct utils_mutex_t { #ifdef _WIN32 CRITICAL_SECTION lock; #else pthread_mutex_t lock; #endif -} os_mutex_t; +} utils_mutex_t; -size_t util_mutex_get_size(void); -os_mutex_t *util_mutex_init(void *ptr); -void util_mutex_destroy_not_free(os_mutex_t *m); -int util_mutex_lock(os_mutex_t *mutex); -int util_mutex_unlock(os_mutex_t *mutex); +size_t utils_mutex_get_size(void); +utils_mutex_t *utils_mutex_init(void *ptr); +void utils_mutex_destroy_not_free(utils_mutex_t *m); +int utils_mutex_lock(utils_mutex_t *mutex); +int utils_mutex_unlock(utils_mutex_t *mutex); #if defined(_WIN32) #define UTIL_ONCE_FLAG INIT_ONCE @@ -58,50 +58,50 @@ int util_mutex_unlock(os_mutex_t *mutex); #define UTIL_ONCE_FLAG_INIT PTHREAD_ONCE_INIT #endif -void util_init_once(UTIL_ONCE_FLAG *flag, void (*onceCb)(void)); +void utils_init_once(UTIL_ONCE_FLAG *flag, void (*onceCb)(void)); #if defined(_WIN32) -static __inline unsigned char util_lssb_index(long long value) { +static __inline unsigned char utils_lssb_index(long long value) { unsigned long ret; _BitScanForward64(&ret, value); return (unsigned char)ret; } -static __inline unsigned char util_mssb_index(long long value) { +static __inline unsigned char utils_mssb_index(long long value) { unsigned long ret; _BitScanReverse64(&ret, value); return (unsigned char)ret; } // There is no good way to do atomic_load on windows... -#define util_atomic_load_acquire(object, dest) \ +#define utils_atomic_load_acquire(object, dest) \ do { \ *dest = InterlockedOr64Acquire((LONG64 volatile *)object, 0); \ } while (0) -#define util_atomic_store_release(object, desired) \ +#define utils_atomic_store_release(object, desired) \ InterlockedExchange64((LONG64 volatile *)object, (LONG64)desired) -#define util_atomic_increment(object) \ +#define utils_atomic_increment(object) \ InterlockedIncrement64((LONG64 volatile *)object) -#define util_fetch_and_add64(ptr, value) \ +#define utils_fetch_and_add64(ptr, value) \ InterlockedExchangeAdd64((LONG64 *)(ptr), value) #else -#define util_lssb_index(x) ((unsigned char)__builtin_ctzll(x)) -#define util_mssb_index(x) ((unsigned char)(63 - __builtin_clzll(x))) -#define util_atomic_load_acquire(object, dest) \ +#define utils_lssb_index(x) ((unsigned char)__builtin_ctzll(x)) +#define utils_mssb_index(x) ((unsigned char)(63 - __builtin_clzll(x))) +#define utils_atomic_load_acquire(object, dest) \ do { \ utils_annotate_acquire((void *)object); \ __atomic_load(object, dest, memory_order_acquire); \ } while (0) -#define util_atomic_store_release(object, desired) \ +#define utils_atomic_store_release(object, desired) \ do { \ __atomic_store_n(object, desired, memory_order_release); \ utils_annotate_release((void *)object); \ } while (0) -#define util_atomic_increment(object) \ +#define utils_atomic_increment(object) \ __atomic_add_fetch(object, 1, __ATOMIC_ACQ_REL) -#define util_fetch_and_add64 __sync_fetch_and_add +#define utils_fetch_and_add64 __sync_fetch_and_add #endif #ifdef __cplusplus diff --git a/src/utils/utils_linux_common.c b/src/utils/utils_linux_common.c index 1ee5cccc8..f5f76be21 100644 --- a/src/utils/utils_linux_common.c +++ b/src/utils/utils_linux_common.c @@ -168,7 +168,7 @@ static int syscall_memfd_create(void) { int utils_create_anonymous_fd(void) { int fd = -1; - if (!util_env_var_has_str("UMF_MEM_FD_FUNC", "memfd_create")) { + if (!utils_env_var_has_str("UMF_MEM_FD_FUNC", "memfd_create")) { fd = syscall_memfd_secret(); if (fd > 0) { return fd; diff --git a/src/utils/utils_load_library.c b/src/utils/utils_load_library.c index cc5fe29fc..2c13acc8d 100644 --- a/src/utils/utils_load_library.c +++ b/src/utils/utils_load_library.c @@ -28,19 +28,19 @@ #ifdef _WIN32 -void *util_open_library(const char *filename, int userFlags) { +void *utils_open_library(const char *filename, int userFlags) { (void)userFlags; //unused for win return LoadLibrary(TEXT(filename)); } -int util_close_library(void *handle) { +int utils_close_library(void *handle) { // If the FreeLibrary function succeeds, the return value is nonzero. // If the FreeLibrary function fails, the return value is zero. return (FreeLibrary((HMODULE)handle) == 0); } -void *util_get_symbol_addr(void *handle, const char *symbol, - const char *libname) { +void *utils_get_symbol_addr(void *handle, const char *symbol, + const char *libname) { if (!handle) { if (libname == NULL) { return NULL; @@ -52,7 +52,7 @@ void *util_get_symbol_addr(void *handle, const char *symbol, #else /* Linux */ -void *util_open_library(const char *filename, int userFlags) { +void *utils_open_library(const char *filename, int userFlags) { int dlopenFlags = RTLD_LAZY; if (userFlags & UMF_UTIL_OPEN_LIBRARY_GLOBAL) { dlopenFlags |= RTLD_GLOBAL; @@ -60,10 +60,10 @@ void *util_open_library(const char *filename, int userFlags) { return dlopen(filename, dlopenFlags); } -int util_close_library(void *handle) { return dlclose(handle); } +int utils_close_library(void *handle) { return dlclose(handle); } -void *util_get_symbol_addr(void *handle, const char *symbol, - const char *libname) { +void *utils_get_symbol_addr(void *handle, const char *symbol, + const char *libname) { (void)libname; //unused if (!handle) { handle = RTLD_DEFAULT; diff --git a/src/utils/utils_load_library.h b/src/utils/utils_load_library.h index c066b548f..3206183f5 100644 --- a/src/utils/utils_load_library.h +++ b/src/utils/utils_load_library.h @@ -19,10 +19,10 @@ extern "C" { #endif #define UMF_UTIL_OPEN_LIBRARY_GLOBAL 1 -void *util_open_library(const char *filename, int userFlags); -int util_close_library(void *handle); -void *util_get_symbol_addr(void *handle, const char *symbol, - const char *libname); +void *utils_open_library(const char *filename, int userFlags); +int utils_close_library(void *handle); +void *utils_get_symbol_addr(void *handle, const char *symbol, + const char *libname); #ifdef __cplusplus } diff --git a/src/utils/utils_log.c b/src/utils/utils_log.c index ca16014f0..bdb9ce823 100644 --- a/src/utils/utils_log.c +++ b/src/utils/utils_log.c @@ -40,14 +40,14 @@ typedef struct { int timestamp; int pid; - util_log_level_t level; - util_log_level_t flushLevel; + utils_log_level_t level; + utils_log_level_t flushLevel; FILE *output; -} util_log_config_t; +} utils_log_config_t; -util_log_config_t loggerConfig = {0, 0, LOG_ERROR, LOG_ERROR, NULL}; +utils_log_config_t loggerConfig = {0, 0, LOG_ERROR, LOG_ERROR, NULL}; -static const char *level_to_str(util_log_level_t l) { +static const char *level_to_str(utils_log_level_t l) { switch (l) { case LOG_DEBUG: return "DEBUG"; @@ -73,9 +73,9 @@ static const char *level_to_str(util_log_level_t l) { #pragma warning(disable : 6262) #endif // _MSC_VER -static void util_log_internal(util_log_level_t level, int perror, - const char *func, const char *format, - va_list args) { +static void utils_log_internal(utils_log_level_t level, int perror, + const char *func, const char *format, + va_list args) { if (!loggerConfig.output && level != LOG_FATAL) { return; //logger not enabled } @@ -203,25 +203,25 @@ static void util_log_internal(util_log_level_t level, int perror, #pragma warning(pop) #endif // _MSC_VER -void util_log(util_log_level_t level, const char *func, const char *format, - ...) { +void utils_log(utils_log_level_t level, const char *func, const char *format, + ...) { va_list args; va_start(args, format); - util_log_internal(level, 0, func, format, args); + utils_log_internal(level, 0, func, format, args); va_end(args); } -void util_plog(util_log_level_t level, const char *func, const char *format, - ...) { +void utils_plog(utils_log_level_t level, const char *func, const char *format, + ...) { va_list args; va_start(args, format); - util_log_internal(level, 1, func, format, args); + utils_log_internal(level, 1, func, format, args); va_end(args); } static const char *bool_to_str(int b) { return b ? "yes" : "no"; } -void util_log_init(void) { +void utils_log_init(void) { const char *envVar = getenv("UMF_LOG"); if (!envVar) { @@ -229,11 +229,11 @@ void util_log_init(void) { } const char *arg; - if (util_parse_var(envVar, "output:stdout", NULL)) { + if (utils_parse_var(envVar, "output:stdout", NULL)) { loggerConfig.output = stdout; - } else if (util_parse_var(envVar, "output:stderr", NULL)) { + } else if (utils_parse_var(envVar, "output:stderr", NULL)) { loggerConfig.output = stderr; - } else if (util_parse_var(envVar, "output:file", &arg)) { + } else if (utils_parse_var(envVar, "output:file", &arg)) { loggerConfig.output = NULL; const char *argEnd = strstr(arg, ";"); char file[MAX_FILE_PATH + 1]; @@ -269,39 +269,39 @@ void util_log_init(void) { return; } - if (util_parse_var(envVar, "timestamp:yes", NULL)) { + if (utils_parse_var(envVar, "timestamp:yes", NULL)) { loggerConfig.timestamp = 1; - } else if (util_parse_var(envVar, "timestamp:no", NULL)) { + } else if (utils_parse_var(envVar, "timestamp:no", NULL)) { loggerConfig.timestamp = 0; } - if (util_parse_var(envVar, "pid:yes", NULL)) { + if (utils_parse_var(envVar, "pid:yes", NULL)) { loggerConfig.pid = 1; - } else if (util_parse_var(envVar, "pid:no", NULL)) { + } else if (utils_parse_var(envVar, "pid:no", NULL)) { loggerConfig.pid = 0; } - if (util_parse_var(envVar, "level:debug", NULL)) { + if (utils_parse_var(envVar, "level:debug", NULL)) { loggerConfig.level = LOG_DEBUG; - } else if (util_parse_var(envVar, "level:info", NULL)) { + } else if (utils_parse_var(envVar, "level:info", NULL)) { loggerConfig.level = LOG_INFO; - } else if (util_parse_var(envVar, "level:warning", NULL)) { + } else if (utils_parse_var(envVar, "level:warning", NULL)) { loggerConfig.level = LOG_WARNING; - } else if (util_parse_var(envVar, "level:error", NULL)) { + } else if (utils_parse_var(envVar, "level:error", NULL)) { loggerConfig.level = LOG_ERROR; - } else if (util_parse_var(envVar, "level:fatal", NULL)) { + } else if (utils_parse_var(envVar, "level:fatal", NULL)) { loggerConfig.level = LOG_FATAL; } - if (util_parse_var(envVar, "flush:debug", NULL)) { + if (utils_parse_var(envVar, "flush:debug", NULL)) { loggerConfig.flushLevel = LOG_DEBUG; - } else if (util_parse_var(envVar, "flush:info", NULL)) { + } else if (utils_parse_var(envVar, "flush:info", NULL)) { loggerConfig.flushLevel = LOG_INFO; - } else if (util_parse_var(envVar, "flush:warning", NULL)) { + } else if (utils_parse_var(envVar, "flush:warning", NULL)) { loggerConfig.flushLevel = LOG_WARNING; - } else if (util_parse_var(envVar, "flush:error", NULL)) { + } else if (utils_parse_var(envVar, "flush:error", NULL)) { loggerConfig.flushLevel = LOG_ERROR; - } else if (util_parse_var(envVar, "flush:fatal", NULL)) { + } else if (utils_parse_var(envVar, "flush:fatal", NULL)) { loggerConfig.flushLevel = LOG_FATAL; } diff --git a/src/utils/utils_log.h b/src/utils/utils_log.h index 4e9e98690..ab40121ce 100644 --- a/src/utils/utils_log.h +++ b/src/utils/utils_log.h @@ -20,31 +20,31 @@ typedef enum { LOG_WARNING, LOG_ERROR, LOG_FATAL -} util_log_level_t; +} utils_log_level_t; -#define LOG_DEBUG(...) util_log(LOG_DEBUG, __func__, __VA_ARGS__); -#define LOG_INFO(...) util_log(LOG_INFO, __func__, __VA_ARGS__); -#define LOG_WARN(...) util_log(LOG_WARNING, __func__, __VA_ARGS__); -#define LOG_ERR(...) util_log(LOG_ERROR, __func__, __VA_ARGS__); -#define LOG_FATAL(...) util_log(LOG_FATAL, __func__, __VA_ARGS__); +#define LOG_DEBUG(...) utils_log(LOG_DEBUG, __func__, __VA_ARGS__); +#define LOG_INFO(...) utils_log(LOG_INFO, __func__, __VA_ARGS__); +#define LOG_WARN(...) utils_log(LOG_WARNING, __func__, __VA_ARGS__); +#define LOG_ERR(...) utils_log(LOG_ERROR, __func__, __VA_ARGS__); +#define LOG_FATAL(...) utils_log(LOG_FATAL, __func__, __VA_ARGS__); -#define LOG_PDEBUG(...) util_plog(LOG_DEBUG, __func__, __VA_ARGS__); -#define LOG_PINFO(...) util_plog(LOG_INFO, __func__, __VA_ARGS__); -#define LOG_PWARN(...) util_plog(LOG_WARNING, __func__, __VA_ARGS__); -#define LOG_PERR(...) util_plog(LOG_ERROR, __func__, __VA_ARGS__); -#define LOG_PFATAL(...) util_plog(LOG_FATAL, __func__, __VA_ARGS__); +#define LOG_PDEBUG(...) utils_plog(LOG_DEBUG, __func__, __VA_ARGS__); +#define LOG_PINFO(...) utils_plog(LOG_INFO, __func__, __VA_ARGS__); +#define LOG_PWARN(...) utils_plog(LOG_WARNING, __func__, __VA_ARGS__); +#define LOG_PERR(...) utils_plog(LOG_ERROR, __func__, __VA_ARGS__); +#define LOG_PFATAL(...) utils_plog(LOG_FATAL, __func__, __VA_ARGS__); -void util_log_init(void); +void utils_log_init(void); #ifdef _WIN32 -void util_log(util_log_level_t level, const char *func, const char *format, - ...); -void util_plog(util_log_level_t level, const char *func, const char *format, +void utils_log(utils_log_level_t level, const char *func, const char *format, ...); +void utils_plog(utils_log_level_t level, const char *func, const char *format, + ...); #else -void util_log(util_log_level_t level, const char *func, const char *format, ...) - __attribute__((format(printf, 3, 4))); -void util_plog(util_log_level_t level, const char *func, const char *format, +void utils_log(utils_log_level_t level, const char *func, const char *format, ...) __attribute__((format(printf, 3, 4))); +void utils_plog(utils_log_level_t level, const char *func, const char *format, + ...) __attribute__((format(printf, 3, 4))); #endif #ifdef __cplusplus diff --git a/src/utils/utils_posix_common.c b/src/utils/utils_posix_common.c index 42a5d06f1..10c2473c2 100644 --- a/src/utils/utils_posix_common.c +++ b/src/utils/utils_posix_common.c @@ -39,10 +39,10 @@ static UTIL_ONCE_FLAG Page_size_is_initialized = UTIL_ONCE_FLAG_INIT; static size_t Page_size; -static void _util_get_page_size(void) { Page_size = sysconf(_SC_PAGE_SIZE); } +static void _utils_get_page_size(void) { Page_size = sysconf(_SC_PAGE_SIZE); } -size_t util_get_page_size(void) { - util_init_once(&Page_size_is_initialized, _util_get_page_size); +size_t utils_get_page_size(void) { + utils_init_once(&Page_size_is_initialized, _utils_get_page_size); return Page_size; } diff --git a/src/utils/utils_posix_concurrency.c b/src/utils/utils_posix_concurrency.c index 5f2b2569d..fcf04ed95 100644 --- a/src/utils/utils_posix_concurrency.c +++ b/src/utils/utils_posix_concurrency.c @@ -12,28 +12,28 @@ #include "utils_concurrency.h" -size_t util_mutex_get_size(void) { return sizeof(pthread_mutex_t); } +size_t utils_mutex_get_size(void) { return sizeof(pthread_mutex_t); } -os_mutex_t *util_mutex_init(void *ptr) { +utils_mutex_t *utils_mutex_init(void *ptr) { pthread_mutex_t *mutex = (pthread_mutex_t *)ptr; int ret = pthread_mutex_init(mutex, NULL); - return ret == 0 ? ((os_mutex_t *)mutex) : NULL; + return ret == 0 ? ((utils_mutex_t *)mutex) : NULL; } -void util_mutex_destroy_not_free(os_mutex_t *m) { +void utils_mutex_destroy_not_free(utils_mutex_t *m) { pthread_mutex_t *mutex = (pthread_mutex_t *)m; int ret = pthread_mutex_destroy(mutex); (void)ret; // TODO: add logging } -int util_mutex_lock(os_mutex_t *m) { +int utils_mutex_lock(utils_mutex_t *m) { return pthread_mutex_lock((pthread_mutex_t *)m); } -int util_mutex_unlock(os_mutex_t *m) { +int utils_mutex_unlock(utils_mutex_t *m) { return pthread_mutex_unlock((pthread_mutex_t *)m); } -void util_init_once(UTIL_ONCE_FLAG *flag, void (*oneCb)(void)) { +void utils_init_once(UTIL_ONCE_FLAG *flag, void (*oneCb)(void)) { pthread_once(flag, oneCb); } diff --git a/src/utils/utils_windows_common.c b/src/utils/utils_windows_common.c index f33b29e1b..33faa1b97 100644 --- a/src/utils/utils_windows_common.c +++ b/src/utils/utils_windows_common.c @@ -25,14 +25,14 @@ static UTIL_ONCE_FLAG Page_size_is_initialized = UTIL_ONCE_FLAG_INIT; static size_t Page_size; -static void _util_get_page_size(void) { +static void _utils_get_page_size(void) { SYSTEM_INFO SystemInfo; GetSystemInfo(&SystemInfo); Page_size = SystemInfo.dwPageSize; } -size_t util_get_page_size(void) { - util_init_once(&Page_size_is_initialized, _util_get_page_size); +size_t utils_get_page_size(void) { + utils_init_once(&Page_size_is_initialized, _utils_get_page_size); return Page_size; } diff --git a/src/utils/utils_windows_concurrency.c b/src/utils/utils_windows_concurrency.c index 50bc71c66..696f4523b 100644 --- a/src/utils/utils_windows_concurrency.c +++ b/src/utils/utils_windows_concurrency.c @@ -9,21 +9,21 @@ #include "utils_concurrency.h" -size_t util_mutex_get_size(void) { return sizeof(os_mutex_t); } +size_t utils_mutex_get_size(void) { return sizeof(utils_mutex_t); } -os_mutex_t *util_mutex_init(void *ptr) { - os_mutex_t *mutex_internal = (os_mutex_t *)ptr; +utils_mutex_t *utils_mutex_init(void *ptr) { + utils_mutex_t *mutex_internal = (utils_mutex_t *)ptr; InitializeCriticalSection(&mutex_internal->lock); - return (os_mutex_t *)mutex_internal; + return (utils_mutex_t *)mutex_internal; } -void util_mutex_destroy_not_free(os_mutex_t *mutex) { - os_mutex_t *mutex_internal = (os_mutex_t *)mutex; +void utils_mutex_destroy_not_free(utils_mutex_t *mutex) { + utils_mutex_t *mutex_internal = (utils_mutex_t *)mutex; DeleteCriticalSection(&mutex_internal->lock); } -int util_mutex_lock(os_mutex_t *mutex) { - os_mutex_t *mutex_internal = (os_mutex_t *)mutex; +int utils_mutex_lock(utils_mutex_t *mutex) { + utils_mutex_t *mutex_internal = (utils_mutex_t *)mutex; EnterCriticalSection(&mutex_internal->lock); if (mutex_internal->lock.RecursionCount > 1) { @@ -34,8 +34,8 @@ int util_mutex_lock(os_mutex_t *mutex) { return 0; } -int util_mutex_unlock(os_mutex_t *mutex) { - os_mutex_t *mutex_internal = (os_mutex_t *)mutex; +int utils_mutex_unlock(utils_mutex_t *mutex) { + utils_mutex_t *mutex_internal = (utils_mutex_t *)mutex; LeaveCriticalSection(&mutex_internal->lock); return 0; } @@ -50,6 +50,6 @@ static BOOL CALLBACK initOnceCb(PINIT_ONCE InitOnce, PVOID Parameter, return TRUE; } -void util_init_once(UTIL_ONCE_FLAG *flag, void (*onceCb)(void)) { +void utils_init_once(UTIL_ONCE_FLAG *flag, void (*onceCb)(void)) { InitOnceExecuteOnce(flag, initOnceCb, (void *)onceCb, NULL); } diff --git a/test/providers/cuda_helpers.cpp b/test/providers/cuda_helpers.cpp index 08584a45f..366efc197 100644 --- a/test/providers/cuda_helpers.cpp +++ b/test/providers/cuda_helpers.cpp @@ -36,7 +36,7 @@ struct libcu_ops { struct DlHandleCloser { void operator()(void *dlHandle) { if (dlHandle) { - util_close_library(dlHandle); + utils_close_library(dlHandle); } } }; @@ -52,77 +52,77 @@ int InitCUDAOps() { // NOTE that we use UMF_UTIL_OPEN_LIBRARY_GLOBAL which add all loaded // symbols to the global symbol table. cuDlHandle = std::unique_ptr( - util_open_library(lib_name, UMF_UTIL_OPEN_LIBRARY_GLOBAL)); + utils_open_library(lib_name, UMF_UTIL_OPEN_LIBRARY_GLOBAL)); // NOTE: some symbols defined in the lib have _vX postfixes - this is // important to load the proper version of functions *(void **)&libcu_ops.cuInit = - util_get_symbol_addr(cuDlHandle.get(), "cuInit", lib_name); + utils_get_symbol_addr(cuDlHandle.get(), "cuInit", lib_name); if (libcu_ops.cuInit == nullptr) { fprintf(stderr, "cuInit symbol not found in %s\n", lib_name); return -1; } *(void **)&libcu_ops.cuCtxCreate = - util_get_symbol_addr(cuDlHandle.get(), "cuCtxCreate_v2", lib_name); + utils_get_symbol_addr(cuDlHandle.get(), "cuCtxCreate_v2", lib_name); if (libcu_ops.cuCtxCreate == nullptr) { fprintf(stderr, "cuCtxCreate_v2 symbol not found in %s\n", lib_name); return -1; } *(void **)&libcu_ops.cuCtxDestroy = - util_get_symbol_addr(cuDlHandle.get(), "cuCtxDestroy_v2", lib_name); + utils_get_symbol_addr(cuDlHandle.get(), "cuCtxDestroy_v2", lib_name); if (libcu_ops.cuCtxDestroy == nullptr) { fprintf(stderr, "cuCtxDestroy symbol not found in %s\n", lib_name); return -1; } *(void **)&libcu_ops.cuDeviceGet = - util_get_symbol_addr(cuDlHandle.get(), "cuDeviceGet", lib_name); + utils_get_symbol_addr(cuDlHandle.get(), "cuDeviceGet", lib_name); if (libcu_ops.cuDeviceGet == nullptr) { fprintf(stderr, "cuDeviceGet symbol not found in %s\n", lib_name); return -1; } *(void **)&libcu_ops.cuMemAlloc = - util_get_symbol_addr(cuDlHandle.get(), "cuMemAlloc_v2", lib_name); + utils_get_symbol_addr(cuDlHandle.get(), "cuMemAlloc_v2", lib_name); if (libcu_ops.cuMemAlloc == nullptr) { fprintf(stderr, "cuMemAlloc_v2 symbol not found in %s\n", lib_name); return -1; } *(void **)&libcu_ops.cuMemFree = - util_get_symbol_addr(cuDlHandle.get(), "cuMemFree_v2", lib_name); + utils_get_symbol_addr(cuDlHandle.get(), "cuMemFree_v2", lib_name); if (libcu_ops.cuMemFree == nullptr) { fprintf(stderr, "cuMemFree_v2 symbol not found in %s\n", lib_name); return -1; } *(void **)&libcu_ops.cuMemAllocHost = - util_get_symbol_addr(cuDlHandle.get(), "cuMemAllocHost_v2", lib_name); + utils_get_symbol_addr(cuDlHandle.get(), "cuMemAllocHost_v2", lib_name); if (libcu_ops.cuMemAllocHost == nullptr) { fprintf(stderr, "cuMemAllocHost_v2 symbol not found in %s\n", lib_name); return -1; } *(void **)&libcu_ops.cuMemAllocManaged = - util_get_symbol_addr(cuDlHandle.get(), "cuMemAllocManaged", lib_name); + utils_get_symbol_addr(cuDlHandle.get(), "cuMemAllocManaged", lib_name); if (libcu_ops.cuMemAllocManaged == nullptr) { fprintf(stderr, "cuMemAllocManaged symbol not found in %s\n", lib_name); return -1; } *(void **)&libcu_ops.cuMemFreeHost = - util_get_symbol_addr(cuDlHandle.get(), "cuMemFreeHost", lib_name); + utils_get_symbol_addr(cuDlHandle.get(), "cuMemFreeHost", lib_name); if (libcu_ops.cuMemFreeHost == nullptr) { fprintf(stderr, "cuMemFreeHost symbol not found in %s\n", lib_name); return -1; } *(void **)&libcu_ops.cuMemsetD32 = - util_get_symbol_addr(cuDlHandle.get(), "cuMemsetD32_v2", lib_name); + utils_get_symbol_addr(cuDlHandle.get(), "cuMemsetD32_v2", lib_name); if (libcu_ops.cuMemsetD32 == nullptr) { fprintf(stderr, "cuMemsetD32_v2 symbol not found in %s\n", lib_name); return -1; } *(void **)&libcu_ops.cuMemcpyDtoH = - util_get_symbol_addr(cuDlHandle.get(), "cuMemcpyDtoH_v2", lib_name); + utils_get_symbol_addr(cuDlHandle.get(), "cuMemcpyDtoH_v2", lib_name); if (libcu_ops.cuMemcpyDtoH == nullptr) { fprintf(stderr, "cuMemcpyDtoH_v2 symbol not found in %s\n", lib_name); return -1; } - *(void **)&libcu_ops.cuPointerGetAttributes = util_get_symbol_addr( + *(void **)&libcu_ops.cuPointerGetAttributes = utils_get_symbol_addr( cuDlHandle.get(), "cuPointerGetAttributes", lib_name); if (libcu_ops.cuPointerGetAttributes == nullptr) { fprintf(stderr, "cuPointerGetAttributes symbol not found in %s\n", @@ -241,7 +241,7 @@ void init_cuda_once() { } int init_cuda() { - util_init_once(&cuda_init_flag, init_cuda_once); + utils_init_once(&cuda_init_flag, init_cuda_once); return InitResult; } diff --git a/test/providers/level_zero_helpers.cpp b/test/providers/level_zero_helpers.cpp index 06b3ae56e..4cd993956 100644 --- a/test/providers/level_zero_helpers.cpp +++ b/test/providers/level_zero_helpers.cpp @@ -66,7 +66,7 @@ struct libze_ops { struct DlHandleCloser { void operator()(void *dlHandle) { if (dlHandle) { - util_close_library(dlHandle); + utils_close_library(dlHandle); } } }; @@ -82,26 +82,26 @@ int InitLevelZeroOps() { // NOTE that we use UMF_UTIL_OPEN_LIBRARY_GLOBAL which add all loaded symbols to the // global symbol table. zeDlHandle = std::unique_ptr( - util_open_library(lib_name, UMF_UTIL_OPEN_LIBRARY_GLOBAL)); + utils_open_library(lib_name, UMF_UTIL_OPEN_LIBRARY_GLOBAL)); *(void **)&libze_ops.zeInit = - util_get_symbol_addr(zeDlHandle.get(), "zeInit", lib_name); + utils_get_symbol_addr(zeDlHandle.get(), "zeInit", lib_name); if (libze_ops.zeInit == nullptr) { fprintf(stderr, "zeInit symbol not found in %s\n", lib_name); return -1; } *(void **)&libze_ops.zeDriverGet = - util_get_symbol_addr(zeDlHandle.get(), "zeDriverGet", lib_name); + utils_get_symbol_addr(zeDlHandle.get(), "zeDriverGet", lib_name); if (libze_ops.zeDriverGet == nullptr) { fprintf(stderr, "zeDriverGet symbol not found in %s\n", lib_name); return -1; } *(void **)&libze_ops.zeDeviceGet = - util_get_symbol_addr(zeDlHandle.get(), "zeDeviceGet", lib_name); + utils_get_symbol_addr(zeDlHandle.get(), "zeDeviceGet", lib_name); if (libze_ops.zeDeviceGet == nullptr) { fprintf(stderr, "zeDeviceGet symbol not found in %s\n", lib_name); return -1; } - *(void **)&libze_ops.zeDeviceGetProperties = util_get_symbol_addr( + *(void **)&libze_ops.zeDeviceGetProperties = utils_get_symbol_addr( zeDlHandle.get(), "zeDeviceGetProperties", lib_name); if (libze_ops.zeDeviceGetProperties == nullptr) { fprintf(stderr, "zeDeviceGetProperties symbol not found in %s\n", @@ -109,25 +109,25 @@ int InitLevelZeroOps() { return -1; } *(void **)&libze_ops.zeContextCreate = - util_get_symbol_addr(zeDlHandle.get(), "zeContextCreate", lib_name); + utils_get_symbol_addr(zeDlHandle.get(), "zeContextCreate", lib_name); if (libze_ops.zeContextCreate == nullptr) { fprintf(stderr, "zeContextCreate symbol not found in %s\n", lib_name); return -1; } *(void **)&libze_ops.zeContextDestroy = - util_get_symbol_addr(zeDlHandle.get(), "zeContextDestroy", lib_name); + utils_get_symbol_addr(zeDlHandle.get(), "zeContextDestroy", lib_name); if (libze_ops.zeContextDestroy == nullptr) { fprintf(stderr, "zeContextDestroy symbol not found in %s\n", lib_name); return -1; } - *(void **)&libze_ops.zeCommandQueueCreate = util_get_symbol_addr( + *(void **)&libze_ops.zeCommandQueueCreate = utils_get_symbol_addr( zeDlHandle.get(), "zeCommandQueueCreate", lib_name); if (libze_ops.zeCommandQueueCreate == nullptr) { fprintf(stderr, "zeCommandQueueCreate symbol not found in %s\n", lib_name); return -1; } - *(void **)&libze_ops.zeCommandQueueDestroy = util_get_symbol_addr( + *(void **)&libze_ops.zeCommandQueueDestroy = utils_get_symbol_addr( zeDlHandle.get(), "zeCommandQueueDestroy", lib_name); if (libze_ops.zeCommandQueueDestroy == nullptr) { fprintf(stderr, "zeCommandQueueDestroy symbol not found in %s\n", @@ -135,29 +135,29 @@ int InitLevelZeroOps() { return -1; } *(void **)&libze_ops.zeCommandQueueExecuteCommandLists = - util_get_symbol_addr(zeDlHandle.get(), - "zeCommandQueueExecuteCommandLists", lib_name); + utils_get_symbol_addr(zeDlHandle.get(), + "zeCommandQueueExecuteCommandLists", lib_name); if (libze_ops.zeCommandQueueExecuteCommandLists == nullptr) { fprintf(stderr, "zeCommandQueueExecuteCommandLists symbol not found in %s\n", lib_name); return -1; } - *(void **)&libze_ops.zeCommandQueueSynchronize = util_get_symbol_addr( + *(void **)&libze_ops.zeCommandQueueSynchronize = utils_get_symbol_addr( zeDlHandle.get(), "zeCommandQueueSynchronize", lib_name); if (libze_ops.zeCommandQueueSynchronize == nullptr) { fprintf(stderr, "zeCommandQueueSynchronize symbol not found in %s\n", lib_name); return -1; } - *(void **)&libze_ops.zeCommandListCreate = - util_get_symbol_addr(zeDlHandle.get(), "zeCommandListCreate", lib_name); + *(void **)&libze_ops.zeCommandListCreate = utils_get_symbol_addr( + zeDlHandle.get(), "zeCommandListCreate", lib_name); if (libze_ops.zeCommandListCreate == nullptr) { fprintf(stderr, "zeCommandListCreate symbol not found in %s\n", lib_name); return -1; } - *(void **)&libze_ops.zeCommandListDestroy = util_get_symbol_addr( + *(void **)&libze_ops.zeCommandListDestroy = utils_get_symbol_addr( zeDlHandle.get(), "zeCommandListDestroy", lib_name); if (libze_ops.zeCommandListDestroy == nullptr) { fprintf(stderr, "zeCommandListDestroy symbol not found in %s\n", @@ -165,13 +165,13 @@ int InitLevelZeroOps() { return -1; } *(void **)&libze_ops.zeCommandListClose = - util_get_symbol_addr(zeDlHandle.get(), "zeCommandListClose", lib_name); + utils_get_symbol_addr(zeDlHandle.get(), "zeCommandListClose", lib_name); if (libze_ops.zeCommandListClose == nullptr) { fprintf(stderr, "zeCommandListClose symbol not found in %s\n", lib_name); return -1; } - *(void **)&libze_ops.zeCommandListAppendMemoryCopy = util_get_symbol_addr( + *(void **)&libze_ops.zeCommandListAppendMemoryCopy = utils_get_symbol_addr( zeDlHandle.get(), "zeCommandListAppendMemoryCopy", lib_name); if (libze_ops.zeCommandListAppendMemoryCopy == nullptr) { fprintf(stderr, @@ -179,7 +179,7 @@ int InitLevelZeroOps() { lib_name); return -1; } - *(void **)&libze_ops.zeCommandListAppendMemoryFill = util_get_symbol_addr( + *(void **)&libze_ops.zeCommandListAppendMemoryFill = utils_get_symbol_addr( zeDlHandle.get(), "zeCommandListAppendMemoryFill", lib_name); if (libze_ops.zeCommandListAppendMemoryFill == nullptr) { fprintf(stderr, @@ -187,7 +187,7 @@ int InitLevelZeroOps() { lib_name); return -1; } - *(void **)&libze_ops.zeMemGetAllocProperties = util_get_symbol_addr( + *(void **)&libze_ops.zeMemGetAllocProperties = utils_get_symbol_addr( zeDlHandle.get(), "zeMemGetAllocProperties", lib_name); if (libze_ops.zeMemGetAllocProperties == nullptr) { fprintf(stderr, "zeMemGetAllocProperties symbol not found in %s\n", @@ -195,13 +195,13 @@ int InitLevelZeroOps() { return -1; } *(void **)&libze_ops.zeMemAllocDevice = - util_get_symbol_addr(zeDlHandle.get(), "zeMemAllocDevice", lib_name); + utils_get_symbol_addr(zeDlHandle.get(), "zeMemAllocDevice", lib_name); if (libze_ops.zeMemAllocDevice == nullptr) { fprintf(stderr, "zeMemAllocDevice symbol not found in %s\n", lib_name); return -1; } *(void **)&libze_ops.zeMemFree = - util_get_symbol_addr(zeDlHandle.get(), "zeMemFree", lib_name); + utils_get_symbol_addr(zeDlHandle.get(), "zeMemFree", lib_name); if (libze_ops.zeMemFree == nullptr) { fprintf(stderr, "zeMemFree symbol not found in %s\n", lib_name); return -1; @@ -661,7 +661,7 @@ void init_level_zero_once() { } int init_level_zero() { - util_init_once(&level_zero_init_flag, init_level_zero_once); + utils_init_once(&level_zero_init_flag, init_level_zero_once); return InitResult; } diff --git a/test/test_base_alloc_linear.cpp b/test/test_base_alloc_linear.cpp index 94425fb03..3f8371d8d 100644 --- a/test/test_base_alloc_linear.cpp +++ b/test/test_base_alloc_linear.cpp @@ -60,7 +60,7 @@ TEST_F(test, baseAllocLinearMultiThreadedAllocMemset) { // but not big enough to hold all allocations, // so that there were more pools allocated. // This is needed to test freeing the first pool. - size_t pool_size = 2 * util_get_page_size(); + size_t pool_size = 2 * utils_get_page_size(); auto pool = std::shared_ptr( umf_ba_linear_create(pool_size), umf_ba_linear_destroy); diff --git a/test/utils/utils.cpp b/test/utils/utils.cpp index de4a71d65..302971f7e 100644 --- a/test/utils/utils.cpp +++ b/test/utils/utils.cpp @@ -8,52 +8,52 @@ using umf_test::test; -TEST_F(test, util_parse_var) { - EXPECT_FALSE(util_parse_var("", "test1", 0)); +TEST_F(test, utils_parse_var) { + EXPECT_FALSE(utils_parse_var("", "test1", 0)); - EXPECT_TRUE(util_parse_var("test1;test2;test3;test4", "test1", 0)); - EXPECT_TRUE(util_parse_var("test1;test2;test3;test4", "test2", 0)); - EXPECT_TRUE(util_parse_var("test1;test2;test3;test4", "test3", 0)); - EXPECT_TRUE(util_parse_var("test1;test2;test3;test4", "test4", 0)); + EXPECT_TRUE(utils_parse_var("test1;test2;test3;test4", "test1", 0)); + EXPECT_TRUE(utils_parse_var("test1;test2;test3;test4", "test2", 0)); + EXPECT_TRUE(utils_parse_var("test1;test2;test3;test4", "test3", 0)); + EXPECT_TRUE(utils_parse_var("test1;test2;test3;test4", "test4", 0)); - EXPECT_TRUE(util_parse_var(";test1;test2;test3;test4;", "test1", 0)); - EXPECT_TRUE(util_parse_var(";test1;test2;test3;test4;", "test2", 0)); - EXPECT_TRUE(util_parse_var(";test1;test2;test3;test4;", "test3", 0)); - EXPECT_TRUE(util_parse_var(";test1;test2;test3;test4;", "test4", 0)); + EXPECT_TRUE(utils_parse_var(";test1;test2;test3;test4;", "test1", 0)); + EXPECT_TRUE(utils_parse_var(";test1;test2;test3;test4;", "test2", 0)); + EXPECT_TRUE(utils_parse_var(";test1;test2;test3;test4;", "test3", 0)); + EXPECT_TRUE(utils_parse_var(";test1;test2;test3;test4;", "test4", 0)); - EXPECT_FALSE(util_parse_var("test1;test2;test3;test4", "test5", 0)); + EXPECT_FALSE(utils_parse_var("test1;test2;test3;test4", "test5", 0)); - EXPECT_FALSE(util_parse_var("test1test2test3test4", "test1", 0)); - EXPECT_FALSE(util_parse_var("test1test2test3test4", "test2", 0)); - EXPECT_FALSE(util_parse_var("test1test2test3test4", "test3", 0)); - EXPECT_FALSE(util_parse_var("test1test2test3test4", "test4", 0)); + EXPECT_FALSE(utils_parse_var("test1test2test3test4", "test1", 0)); + EXPECT_FALSE(utils_parse_var("test1test2test3test4", "test2", 0)); + EXPECT_FALSE(utils_parse_var("test1test2test3test4", "test3", 0)); + EXPECT_FALSE(utils_parse_var("test1test2test3test4", "test4", 0)); - EXPECT_FALSE(util_parse_var("test1:test2;test3:test4", "test1", 0)); - EXPECT_FALSE(util_parse_var("test1:test2;test3:test4", "test2", 0)); - EXPECT_FALSE(util_parse_var("test1:test2;test3:test4", "test3", 0)); - EXPECT_FALSE(util_parse_var("test1:test2;test3:test4", "test4", 0)); + EXPECT_FALSE(utils_parse_var("test1:test2;test3:test4", "test1", 0)); + EXPECT_FALSE(utils_parse_var("test1:test2;test3:test4", "test2", 0)); + EXPECT_FALSE(utils_parse_var("test1:test2;test3:test4", "test3", 0)); + EXPECT_FALSE(utils_parse_var("test1:test2;test3:test4", "test4", 0)); - EXPECT_TRUE(util_parse_var("test1:test2;test3:test4", "test1:test2", 0)); - EXPECT_TRUE(util_parse_var("test1:test2;test3:test4", "test3:test4", 0)); - EXPECT_FALSE(util_parse_var("test1:test2;test3:test4", "test2:test3'", 0)); + EXPECT_TRUE(utils_parse_var("test1:test2;test3:test4", "test1:test2", 0)); + EXPECT_TRUE(utils_parse_var("test1:test2;test3:test4", "test3:test4", 0)); + EXPECT_FALSE(utils_parse_var("test1:test2;test3:test4", "test2:test3'", 0)); EXPECT_TRUE( - util_parse_var("test1;;test2;invalid;test3;;;test4", "test1", 0)); + utils_parse_var("test1;;test2;invalid;test3;;;test4", "test1", 0)); EXPECT_TRUE( - util_parse_var("test1;;test2;invalid;test3;;;test4", "test2", 0)); + utils_parse_var("test1;;test2;invalid;test3;;;test4", "test2", 0)); EXPECT_TRUE( - util_parse_var("test1;;test2;invalid;test3;;;test4", "test3", 0)); + utils_parse_var("test1;;test2;invalid;test3;;;test4", "test3", 0)); EXPECT_TRUE( - util_parse_var("test1;;test2;invalid;test3;;;test4", "test4", 0)); + utils_parse_var("test1;;test2;invalid;test3;;;test4", "test4", 0)); const char *arg; - EXPECT_FALSE(util_parse_var("test1;test2;test3;test4", "test1", &arg)); - EXPECT_FALSE(util_parse_var("test1;test2;test3;test4", "test2", &arg)); - EXPECT_FALSE(util_parse_var("test1;test2;test3;test4", "test3", &arg)); - EXPECT_FALSE(util_parse_var("test1;test2;test3;test4", "test4", &arg)); - - EXPECT_TRUE(util_parse_var("test1,abc;test2;test3;test4", "test1", &arg)); - EXPECT_TRUE(util_parse_var("test1;test2,abc;test3;test4", "test2", &arg)); - EXPECT_TRUE(util_parse_var("test1;test2;test3,abc;test4", "test3", &arg)); - EXPECT_TRUE(util_parse_var("test1;test2;test3;test4,abc", "test4", &arg)); + EXPECT_FALSE(utils_parse_var("test1;test2;test3;test4", "test1", &arg)); + EXPECT_FALSE(utils_parse_var("test1;test2;test3;test4", "test2", &arg)); + EXPECT_FALSE(utils_parse_var("test1;test2;test3;test4", "test3", &arg)); + EXPECT_FALSE(utils_parse_var("test1;test2;test3;test4", "test4", &arg)); + + EXPECT_TRUE(utils_parse_var("test1,abc;test2;test3;test4", "test1", &arg)); + EXPECT_TRUE(utils_parse_var("test1;test2,abc;test3;test4", "test2", &arg)); + EXPECT_TRUE(utils_parse_var("test1;test2;test3,abc;test4", "test3", &arg)); + EXPECT_TRUE(utils_parse_var("test1;test2;test3;test4,abc", "test4", &arg)); } diff --git a/test/utils/utils_log.cpp b/test/utils/utils_log.cpp index f865b416b..c0f81abf0 100644 --- a/test/utils/utils_log.cpp +++ b/test/utils/utils_log.cpp @@ -19,7 +19,7 @@ FILE *mock_fopen(const char *filename, const char *mode) { } const std::string MOCK_FN_NAME = "MOCK_FUNCTION_NAME"; -std::string expected_message = "[ERROR UMF] util_log_init: Logging output not " +std::string expected_message = "[ERROR UMF] utils_log_init: Logging output not " "set - logging disabled (UMF_LOG = \"\")\n"; // The expected_message (above) is printed to stderr. FILE *expected_stream = stderr; @@ -98,7 +98,7 @@ const char *env_variable = ""; #define fopen(A, B) mock_fopen(A, B) #define fputs(A, B) mock_fputs(A, B) #define fflush(A) mock_fflush(A) -#define util_env_var(A, B, C) mock_util_env_var(A, B, C) +#define utils_env_var(A, B, C) mock_utils_env_var(A, B, C) #if defined(__APPLE__) #define strerror_r(A, B, C) mock_strerror_posix(A, B, C) #else @@ -111,7 +111,7 @@ const char *env_variable = ""; #define UMF_VERSION "test version" #endif #include "utils/utils_log.c" -#undef util_env_var +#undef utils_env_var #undef fopen #undef fputs #undef fflush @@ -122,13 +122,13 @@ void helper_log_init(const char *var) { env_variable = var; fopen_count = 0; fput_count = 0; - util_log_init(); + utils_log_init(); env_variable = NULL; EXPECT_EQ(fopen_count, expect_fopen_count); EXPECT_EQ(fput_count, expect_fput_count); } -void helper_checkConfig(util_log_config_t *expected, util_log_config_t *is) { +void helper_checkConfig(utils_log_config_t *expected, utils_log_config_t *is) { EXPECT_EQ(expected->level, is->level); EXPECT_EQ(expected->flushLevel, is->flushLevel); EXPECT_EQ(expected->output, is->output); @@ -142,7 +142,7 @@ TEST_F(test, parseEnv_errors) { expect_fput_count = 0; expected_stream = stderr; - util_log_config_t b = loggerConfig; + utils_log_config_t b = loggerConfig; helper_log_init(NULL); helper_checkConfig(&b, &loggerConfig); @@ -156,13 +156,13 @@ TEST_F(test, parseEnv_errors) { helper_log_init("_level:debug"); helper_checkConfig(&b, &loggerConfig); expected_message = - "[ERROR UMF] util_log_init: Cannot open output file - path too long\n"; + "[ERROR UMF] utils_log_init: Cannot open output file - path too long\n"; std::string test_env = "output:file," + std::string(300, 'x'); helper_log_init(test_env.c_str()); } TEST_F(test, parseEnv) { - util_log_config_t b = loggerConfig; + utils_log_config_t b = loggerConfig; expected_message = ""; std::vector> logLevels = { @@ -228,9 +228,9 @@ TEST_F(test, parseEnv) { expected_stream = output.second; b.timestamp = timestamp.second; b.pid = pid.second; - b.flushLevel = (util_log_level_t)flushLevel.second; + b.flushLevel = (utils_log_level_t)flushLevel.second; - b.level = (util_log_level_t)logLevel.second; + b.level = (utils_log_level_t)logLevel.second; if (logLevel.second <= LOG_INFO) { expect_fput_count = 1; } @@ -238,7 +238,7 @@ TEST_F(test, parseEnv) { expect_fput_count = 1; if (expected_filename.size() > MAX_FILE_PATH) { expected_message = - "[ERROR UMF] util_log_init: Cannot open " + "[ERROR UMF] utils_log_init: Cannot open " "output file - path too long\n"; } } @@ -254,7 +254,7 @@ TEST_F(test, parseEnv) { template void helper_test_log(Args... args) { fput_count = 0; fflush_count = 0; - util_log(args...); + utils_log(args...); EXPECT_EQ(fput_count, expect_fput_count); EXPECT_EQ(fflush_count, expect_fflush_count); } @@ -281,7 +281,7 @@ TEST_F(test, log_levels) { expected_stream = stderr; for (int i = LOG_DEBUG; i <= LOG_ERROR; i++) { for (int j = LOG_DEBUG; j <= LOG_ERROR; j++) { - loggerConfig = {0, 0, (util_log_level_t)i, LOG_DEBUG, stderr}; + loggerConfig = {0, 0, (utils_log_level_t)i, LOG_DEBUG, stderr}; if (i > j) { expect_fput_count = 0; expect_fflush_count = 0; @@ -292,7 +292,7 @@ TEST_F(test, log_levels) { } expected_message = "[" + helper_log_str(j) + " UMF] " + MOCK_FN_NAME + ": example log\n"; - helper_test_log((util_log_level_t)j, MOCK_FN_NAME.c_str(), "%s", + helper_test_log((utils_log_level_t)j, MOCK_FN_NAME.c_str(), "%s", "example log"); } } @@ -315,7 +315,7 @@ TEST_F(test, flush_levels) { expect_fput_count = 1; for (int i = LOG_DEBUG; i <= LOG_ERROR; i++) { for (int j = LOG_DEBUG; j <= LOG_ERROR; j++) { - loggerConfig = {0, 0, LOG_DEBUG, (util_log_level_t)i, stderr}; + loggerConfig = {0, 0, LOG_DEBUG, (utils_log_level_t)i, stderr}; if (i > j) { expect_fflush_count = 0; } else { @@ -323,7 +323,7 @@ TEST_F(test, flush_levels) { } expected_message = "[" + helper_log_str(j) + " UMF] " + MOCK_FN_NAME + ": example log\n"; - helper_test_log((util_log_level_t)j, MOCK_FN_NAME.c_str(), "%s", + helper_test_log((utils_log_level_t)j, MOCK_FN_NAME.c_str(), "%s", "example log"); } } @@ -420,7 +420,7 @@ TEST_F(test, log_macros) { template void helper_test_plog(Args... args) { fput_count = 0; fflush_count = 0; - util_plog(args...); + utils_plog(args...); EXPECT_EQ(fput_count, expect_fput_count); EXPECT_EQ(fflush_count, expect_fflush_count); } From cb1ea1db05f3cdca8ec4eee177ed0ad9f7f74923 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Fri, 20 Sep 2024 11:02:05 +0200 Subject: [PATCH 109/352] Remove unneeded functions Remove unneeded functions. All those functions have utils_* counterparts in the same file. They were left here by mistake. Signed-off-by: Lukasz Dorau --- src/utils/utils_macosx_common.c | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/src/utils/utils_macosx_common.c b/src/utils/utils_macosx_common.c index 1ab5c4c85..9c91e2b01 100644 --- a/src/utils/utils_macosx_common.c +++ b/src/utils/utils_macosx_common.c @@ -90,31 +90,3 @@ int utils_shm_unlink(const char *shm_name) { int utils_create_anonymous_fd(void) { return 0; // ignored on MacOSX } - -int os_get_file_size(int fd, size_t *size) { - (void)fd; // unused - (void)size; // unused - return -1; // not supported on MacOSX -} - -int os_set_file_size(int fd, size_t size) { - (void)fd; // unused - (void)size; // unused - return 0; // ignored on MacOSX -} - -void *os_devdax_mmap(void *hint_addr, size_t length, int prot, int fd) { - (void)hint_addr; // unused - (void)length; // unused - (void)prot; // unused - (void)fd; // unused - return NULL; // not supported on Windows -} - -int os_fallocate(int fd, long offset, long len) { - (void)fd; // unused - (void)offset; // unused - (void)len; // unused - - return -1; -} From 77f9221af4305f59b71fbba7304907fa68184583 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Fri, 20 Sep 2024 21:00:46 +0200 Subject: [PATCH 110/352] Add UMF_MEM_MAP_SYNC for MAP_SYNC on Linux only Signed-off-by: Lukasz Dorau --- include/umf/memory_provider.h | 3 ++- src/utils/utils_linux_common.c | 3 +++ src/utils/utils_macosx_common.c | 2 ++ src/utils/utils_windows_common.c | 2 ++ 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/umf/memory_provider.h b/include/umf/memory_provider.h index fb217a0e8..073b04efb 100644 --- a/include/umf/memory_provider.h +++ b/include/umf/memory_provider.h @@ -20,7 +20,8 @@ extern "C" { /// @brief Memory visibility mode typedef enum umf_memory_visibility_t { UMF_MEM_MAP_PRIVATE = 1, ///< private memory mapping - UMF_MEM_MAP_SHARED, ///< shared memory mapping (supported on Linux only) + UMF_MEM_MAP_SHARED, ///< shared memory mapping (Linux only) + UMF_MEM_MAP_SYNC, ///< direct mapping of persistent memory (supported only for files supporting DAX, Linux only) } umf_memory_visibility_t; /// @brief Protection of the memory allocations diff --git a/src/utils/utils_linux_common.c b/src/utils/utils_linux_common.c index f5f76be21..0c9347f92 100644 --- a/src/utils/utils_linux_common.c +++ b/src/utils/utils_linux_common.c @@ -31,6 +31,9 @@ utils_translate_mem_visibility_flag(umf_memory_visibility_t in_flag, case UMF_MEM_MAP_SHARED: *out_flag = MAP_SHARED; return UMF_RESULT_SUCCESS; + case UMF_MEM_MAP_SYNC: + *out_flag = MAP_SYNC; + return UMF_RESULT_SUCCESS; } return UMF_RESULT_ERROR_INVALID_ARGUMENT; } diff --git a/src/utils/utils_macosx_common.c b/src/utils/utils_macosx_common.c index 9c91e2b01..d54b346b2 100644 --- a/src/utils/utils_macosx_common.c +++ b/src/utils/utils_macosx_common.c @@ -23,6 +23,8 @@ utils_translate_mem_visibility_flag(umf_memory_visibility_t in_flag, return UMF_RESULT_SUCCESS; case UMF_MEM_MAP_SHARED: return UMF_RESULT_ERROR_NOT_SUPPORTED; // not supported on MacOSX + case UMF_MEM_MAP_SYNC: + return UMF_RESULT_ERROR_NOT_SUPPORTED; // not supported on MacOSX } return UMF_RESULT_ERROR_INVALID_ARGUMENT; } diff --git a/src/utils/utils_windows_common.c b/src/utils/utils_windows_common.c index 33faa1b97..fa1b76c9d 100644 --- a/src/utils/utils_windows_common.c +++ b/src/utils/utils_windows_common.c @@ -96,6 +96,8 @@ utils_translate_mem_visibility_flag(umf_memory_visibility_t in_flag, return UMF_RESULT_SUCCESS; case UMF_MEM_MAP_SHARED: return UMF_RESULT_ERROR_NOT_SUPPORTED; // not supported on Windows yet + case UMF_MEM_MAP_SYNC: + return UMF_RESULT_ERROR_NOT_SUPPORTED; // not supported on Windows yet } return UMF_RESULT_ERROR_INVALID_ARGUMENT; } From be40351796175b57938252878d8d0ebe54ceab78 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 23 Sep 2024 10:35:16 +0200 Subject: [PATCH 111/352] Set UMF_TESTS_DEVDAX_SIZE from ndctl-list output Signed-off-by: Lukasz Dorau --- .github/workflows/devdax.yml | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/.github/workflows/devdax.yml b/.github/workflows/devdax.yml index 3f2b3afc9..e8a4dc3bd 100644 --- a/.github/workflows/devdax.yml +++ b/.github/workflows/devdax.yml @@ -1,7 +1,7 @@ # This workflow builds and tests the devdax memory provider. # It requires a DAX device (e.g. /dev/dax0.0) configured in the OS. -# This DAX device should be specified using UMF_TESTS_DEVDAX_PATH and UMF_TESTS_DEVDAX_SIZE -# CI environment variables. +# This DAX device should be specified using the +# UMF_TESTS_DEVDAX_PATH and UMF_TESTS_DEVDAX_SIZE environment variables. name: DevDax @@ -11,8 +11,7 @@ permissions: contents: read env: - UMF_TESTS_DEVDAX_PATH : "/dev/dax0.0" - UMF_TESTS_DEVDAX_SIZE : 1054867456 + UMF_TESTS_DEVDAX_NAMESPACE : "0.0" BUILD_DIR : "${{github.workspace}}/build" INSTL_DIR : "${{github.workspace}}/../install-dir" @@ -28,10 +27,12 @@ jobs: runs-on: ["DSS-DEVDAX", "DSS-Ubuntu"] steps: - - name: Check if the devdax exists + - name: Check if the devdax exists, print out UMF_TESTS_DEVDAX_PATH and UMF_TESTS_DEVDAX_SIZE run: | ndctl list -N --device-dax - ls -al ${{env.UMF_TESTS_DEVDAX_PATH}} + ls -al /dev/dax${UMF_TESTS_DEVDAX_NAMESPACE} + echo UMF_TESTS_DEVDAX_PATH="/dev/dax${UMF_TESTS_DEVDAX_NAMESPACE}" + echo UMF_TESTS_DEVDAX_SIZE="$(ndctl list --namespace=namespace${UMF_TESTS_DEVDAX_NAMESPACE} | grep size | cut -d':' -f2 | cut -d',' -f1)" - name: Checkout uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 @@ -63,4 +64,7 @@ jobs: - name: Run only devdax tests working-directory: ${{env.BUILD_DIR}} - run: ctest -C ${{matrix.build_type}} -R devdax -V + run: > + UMF_TESTS_DEVDAX_PATH="/dev/dax${UMF_TESTS_DEVDAX_NAMESPACE}" + UMF_TESTS_DEVDAX_SIZE="$(ndctl list --namespace=namespace${UMF_TESTS_DEVDAX_NAMESPACE} | grep size | cut -d':' -f2 | cut -d',' -f1)" + ctest -C ${{matrix.build_type}} -R devdax -V From c03f5f6d6adf7a50ed2f4df6d8e2771600e1cdce Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 23 Sep 2024 12:04:55 +0200 Subject: [PATCH 112/352] Rename utils_devdax_mmap to utils_mmap_file and improve it Rename utils_devdax_mmap to utils_mmap_file and improve it: - add support for MAP_PRIVATE - add flags and fd_offset arguments Signed-off-by: Lukasz Dorau --- src/provider/provider_devdax_memory.c | 18 +++++-- src/utils/utils_common.h | 3 +- src/utils/utils_linux_common.c | 67 ++++++++++++++++++++------- src/utils/utils_macosx_common.c | 5 +- src/utils/utils_windows_common.c | 7 ++- 5 files changed, 75 insertions(+), 25 deletions(-) diff --git a/src/provider/provider_devdax_memory.c b/src/provider/provider_devdax_memory.c index ed0c2a25d..45fc725cc 100644 --- a/src/provider/provider_devdax_memory.c +++ b/src/provider/provider_devdax_memory.c @@ -130,8 +130,13 @@ static umf_result_t devdax_initialize(void *params, void **provider) { goto err_free_devdax_provider; } - devdax_provider->base = utils_devdax_mmap(NULL, devdax_provider->size, - devdax_provider->protection, fd); + unsigned map_sync_flag = 0; + utils_translate_mem_visibility_flag(UMF_MEM_MAP_SYNC, &map_sync_flag); + + // mmap /dev/dax with the MAP_SYNC xor MAP_SHARED flag (if MAP_SYNC fails) + devdax_provider->base = utils_mmap_file(NULL, devdax_provider->size, + devdax_provider->protection, + map_sync_flag, fd, 0 /* offset */); utils_close_fd(fd); if (devdax_provider->base == NULL) { LOG_PDEBUG("devdax memory mapping failed (path=%s, size=%zu)", @@ -458,8 +463,13 @@ static umf_result_t devdax_open_ipc_handle(void *provider, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - char *base = utils_devdax_mmap(NULL, devdax_provider->size, - devdax_provider->protection, fd); + unsigned map_sync_flag = 0; + utils_translate_mem_visibility_flag(UMF_MEM_MAP_SYNC, &map_sync_flag); + + // mmap /dev/dax with the MAP_SYNC xor MAP_SHARED flag (if MAP_SYNC fails) + char *base = utils_mmap_file(NULL, devdax_provider->size, + devdax_provider->protection, map_sync_flag, fd, + 0 /* offset */); if (base == NULL) { devdax_store_last_native_error(UMF_DEVDAX_RESULT_ERROR_ALLOC_FAILED, errno); diff --git a/src/utils/utils_common.h b/src/utils/utils_common.h index a58614061..999fc5745 100644 --- a/src/utils/utils_common.h +++ b/src/utils/utils_common.h @@ -124,7 +124,8 @@ int utils_set_file_size(int fd, size_t size); void *utils_mmap(void *hint_addr, size_t length, int prot, int flag, int fd, size_t fd_offset); -void *utils_devdax_mmap(void *hint_addr, size_t length, int prot, int fd); +void *utils_mmap_file(void *hint_addr, size_t length, int prot, int flags, + int fd, size_t fd_offset); int utils_munmap(void *addr, size_t length); diff --git a/src/utils/utils_linux_common.c b/src/utils/utils_linux_common.c index 0c9347f92..f1e6beb5d 100644 --- a/src/utils/utils_linux_common.c +++ b/src/utils/utils_linux_common.c @@ -39,24 +39,57 @@ utils_translate_mem_visibility_flag(umf_memory_visibility_t in_flag, } /* - * MMap a /dev/dax device. - * First try to mmap with (MAP_SHARED_VALIDATE | MAP_SYNC) flags - * which allows flushing from the user-space. If MAP_SYNC fails - * try to mmap with MAP_SHARED flag (without MAP_SYNC). + * Map given file into memory. + * If (flags & MAP_PRIVATE) it uses just mmap. Otherwise, if (flags & MAP_SYNC) + * it tries to mmap with (flags | MAP_SHARED_VALIDATE | MAP_SYNC) + * which allows flushing from the user-space. If MAP_SYNC fails and the user + * did not specify it by himself it tries to mmap with (flags | MAP_SHARED). */ -void *utils_devdax_mmap(void *hint_addr, size_t length, int prot, int fd) { - void *ptr = utils_mmap(hint_addr, length, prot, - MAP_SHARED_VALIDATE | MAP_SYNC, fd, 0); - if (ptr) { - LOG_DEBUG( - "devdax mapped with the (MAP_SHARED_VALIDATE | MAP_SYNC) flags"); - return ptr; - } - - ptr = utils_mmap(hint_addr, length, prot, MAP_SHARED, fd, 0); - if (ptr) { - LOG_DEBUG("devdax mapped with the MAP_SHARED flag"); - return ptr; +void *utils_mmap_file(void *hint_addr, size_t length, int prot, int flags, + int fd, size_t fd_offset) { + void *addr; + + /* + * MAP_PRIVATE and MAP_SHARED are mutually exclusive, + * therefore mmap with MAP_PRIVATE is executed separately. + */ + if (flags & MAP_PRIVATE) { + addr = utils_mmap(hint_addr, length, prot, flags, fd, fd_offset); + if (addr == MAP_FAILED) { + LOG_PERR("mapping file with the MAP_PRIVATE flag failed"); + return NULL; + } + + LOG_DEBUG("file mapped with the MAP_PRIVATE flag"); + return addr; + } + + errno = 0; + + if (flags & MAP_SYNC) { + /* try to mmap with MAP_SYNC flag */ + const int sync_flags = MAP_SHARED_VALIDATE | MAP_SYNC; + addr = utils_mmap(hint_addr, length, prot, flags | sync_flags, fd, + fd_offset); + if (addr) { + LOG_DEBUG("file mapped with the MAP_SYNC flag"); + return addr; + } + + LOG_PERR("mapping file with the MAP_SYNC flag failed"); + } + + if ((!(flags & MAP_SYNC)) || errno == EINVAL || errno == ENOTSUP || + errno == EOPNOTSUPP) { + /* try to mmap with MAP_SHARED flag (without MAP_SYNC) */ + const int shared_flags = (flags & (~MAP_SYNC)) | MAP_SHARED; + addr = utils_mmap(hint_addr, length, prot, shared_flags, fd, fd_offset); + if (addr) { + LOG_DEBUG("file mapped with the MAP_SHARED flag"); + return addr; + } + + LOG_PERR("mapping file with the MAP_SHARED flag failed"); } return NULL; diff --git a/src/utils/utils_macosx_common.c b/src/utils/utils_macosx_common.c index d54b346b2..586f0fa52 100644 --- a/src/utils/utils_macosx_common.c +++ b/src/utils/utils_macosx_common.c @@ -29,11 +29,14 @@ utils_translate_mem_visibility_flag(umf_memory_visibility_t in_flag, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } -void *utils_devdax_mmap(void *hint_addr, size_t length, int prot, int fd) { +void *utils_mmap_file(void *hint_addr, size_t length, int prot, int flags, + int fd, size_t fd_offset) { (void)hint_addr; // unused (void)length; // unused (void)prot; // unused + (void)flags; // unused (void)fd; // unused + (void)fd_offset; // unused return NULL; // not supported } diff --git a/src/utils/utils_windows_common.c b/src/utils/utils_windows_common.c index fa1b76c9d..4646b6f55 100644 --- a/src/utils/utils_windows_common.c +++ b/src/utils/utils_windows_common.c @@ -147,12 +147,15 @@ void *utils_mmap(void *hint_addr, size_t length, int prot, int flag, int fd, return VirtualAlloc(hint_addr, length, MEM_RESERVE | MEM_COMMIT, prot); } -void *utils_devdax_mmap(void *hint_addr, size_t length, int prot, int fd) { +void *utils_mmap_file(void *hint_addr, size_t length, int prot, int flags, + int fd, size_t fd_offset) { (void)hint_addr; // unused (void)length; // unused (void)prot; // unused + (void)flags; // unused (void)fd; // unused - return NULL; // not supported on Windows + (void)fd_offset; // unused + return NULL; // not supported } int utils_munmap(void *addr, size_t length) { From dadb2b6f74c75af2aaf842e5e4fdc1a8e5876f07 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Fri, 20 Sep 2024 11:51:53 +0200 Subject: [PATCH 113/352] Add support for mapping with MAP_SYNC to file provider Add support for mapping with MAP_SYNC to file provider: use utils_mmap_file() instead of utils_mmap(). Signed-off-by: Lukasz Dorau --- README.md | 2 ++ src/provider/provider_file_memory.c | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0cfc50cdc..048bcfaf7 100644 --- a/README.md +++ b/README.md @@ -200,6 +200,8 @@ so it should be used with a pool manager that will take over the managing of the provided memory - for example the jemalloc pool with the `disable_provider_free` parameter set to true. +The memory visibility mode parameter must be set to `UMF_MEM_MAP_SYNC` in case of FSDAX. + ##### Requirements 1) Linux OS diff --git a/src/provider/provider_file_memory.c b/src/provider/provider_file_memory.c index 757dcb1d0..ed9b23164 100644 --- a/src/provider/provider_file_memory.c +++ b/src/provider/provider_file_memory.c @@ -261,7 +261,7 @@ static umf_result_t file_mmap_aligned(file_memory_provider_t *file_provider, ASSERT_IS_ALIGNED(extended_size, page_size); ASSERT_IS_ALIGNED(offset_fd, page_size); - void *ptr = utils_mmap(NULL, extended_size, prot, flag, fd, offset_fd); + void *ptr = utils_mmap_file(NULL, extended_size, prot, flag, fd, offset_fd); if (ptr == NULL) { LOG_PERR("memory mapping failed"); return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; @@ -612,8 +612,9 @@ static umf_result_t file_open_ipc_handle(void *provider, void *providerIpcData, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - *ptr = utils_mmap(NULL, file_ipc_data->size, file_provider->protection, - file_provider->visibility, fd, file_ipc_data->offset_fd); + *ptr = utils_mmap_file(NULL, file_ipc_data->size, file_provider->protection, + file_provider->visibility, fd, + file_ipc_data->offset_fd); (void)utils_close_fd(fd); if (*ptr == NULL) { file_store_last_native_error(UMF_FILE_RESULT_ERROR_ALLOC_FAILED, errno); From 4b1b5cb6f34f0a35faa6185b4ed2971cd8dae46e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Mon, 23 Sep 2024 16:59:33 +0200 Subject: [PATCH 114/352] [CI] Switch MacOS job from old 12 to new 14 --- .github/workflows/basic.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/basic.yml b/.github/workflows/basic.yml index a2e41aa5e..cd06ad3bf 100644 --- a/.github/workflows/basic.yml +++ b/.github/workflows/basic.yml @@ -429,7 +429,7 @@ jobs: name: MacOS strategy: matrix: - os: ['macos-12', 'macos-13'] + os: ['macos-13', 'macos-14'] env: BUILD_TYPE : "Release" runs-on: ${{matrix.os}} From e50a99629e089bbe71a8d5f2cd5277eb935dbab1 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 23 Sep 2024 11:33:11 +0200 Subject: [PATCH 115/352] Rename devdax.yml to dax.yml Rename devdax.yml to dax.yml and add info about FSDAX. Signed-off-by: Lukasz Dorau --- .github/workflows/{devdax.yml => dax.yml} | 40 +++++++++++++++-------- .github/workflows/pr_push.yml | 2 +- 2 files changed, 27 insertions(+), 15 deletions(-) rename .github/workflows/{devdax.yml => dax.yml} (62%) diff --git a/.github/workflows/devdax.yml b/.github/workflows/dax.yml similarity index 62% rename from .github/workflows/devdax.yml rename to .github/workflows/dax.yml index e8a4dc3bd..db4e5768e 100644 --- a/.github/workflows/devdax.yml +++ b/.github/workflows/dax.yml @@ -1,9 +1,20 @@ -# This workflow builds and tests the devdax memory provider. -# It requires a DAX device (e.g. /dev/dax0.0) configured in the OS. -# This DAX device should be specified using the +# +# This workflow builds and tests the DEVDAX memory provider +# and the file memory provider with FSDAX. +# It requires: +# - a DAX device (e.g. /dev/dax0.0) and +# - a FSDAX device (e.g. /dev/pmem1) +# configured and mounted in the OS. +# +# The DAX device should be specified using the # UMF_TESTS_DEVDAX_PATH and UMF_TESTS_DEVDAX_SIZE environment variables. +# +# The FSDAX device should be mounted in the OS (e.g. /mnt/pmem1) +# and the UMF_TESTS_FSDAX_PATH environment variable +# should contain a path to a file o this FSDAX device. +# -name: DevDax +name: Dax on: [workflow_call] @@ -11,12 +22,12 @@ permissions: contents: read env: - UMF_TESTS_DEVDAX_NAMESPACE : "0.0" + DEVDAX_NAMESPACE : "0.0" BUILD_DIR : "${{github.workspace}}/build" INSTL_DIR : "${{github.workspace}}/../install-dir" jobs: - devdax: + dax: name: Build # run only on upstream; forks may not have a DAX device if: github.repository == 'oneapi-src/unified-memory-framework' @@ -27,12 +38,13 @@ jobs: runs-on: ["DSS-DEVDAX", "DSS-Ubuntu"] steps: - - name: Check if the devdax exists, print out UMF_TESTS_DEVDAX_PATH and UMF_TESTS_DEVDAX_SIZE + - name: Check configuration of the DEVDAX run: | - ndctl list -N --device-dax - ls -al /dev/dax${UMF_TESTS_DEVDAX_NAMESPACE} - echo UMF_TESTS_DEVDAX_PATH="/dev/dax${UMF_TESTS_DEVDAX_NAMESPACE}" - echo UMF_TESTS_DEVDAX_SIZE="$(ndctl list --namespace=namespace${UMF_TESTS_DEVDAX_NAMESPACE} | grep size | cut -d':' -f2 | cut -d',' -f1)" + echo DEVDAX_NAMESPACE="${{env.DEVDAX_NAMESPACE}}" + ndctl list --namespace=namespace${{env.DEVDAX_NAMESPACE}} --device-dax + ls -al /dev/dax${{env.DEVDAX_NAMESPACE}} + echo UMF_TESTS_DEVDAX_PATH="/dev/dax${{env.DEVDAX_NAMESPACE}}" + echo UMF_TESTS_DEVDAX_SIZE="$(ndctl list --namespace=namespace${{env.DEVDAX_NAMESPACE}} | grep size | cut -d':' -f2 | cut -d',' -f1)" - name: Checkout uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 @@ -62,9 +74,9 @@ jobs: - name: Build UMF run: cmake --build ${{env.BUILD_DIR}} --config ${{matrix.build_type}} -j $(nproc) - - name: Run only devdax tests + - name: Run the DEVDAX tests working-directory: ${{env.BUILD_DIR}} run: > - UMF_TESTS_DEVDAX_PATH="/dev/dax${UMF_TESTS_DEVDAX_NAMESPACE}" - UMF_TESTS_DEVDAX_SIZE="$(ndctl list --namespace=namespace${UMF_TESTS_DEVDAX_NAMESPACE} | grep size | cut -d':' -f2 | cut -d',' -f1)" + UMF_TESTS_DEVDAX_PATH="/dev/dax${{env.DEVDAX_NAMESPACE}}" + UMF_TESTS_DEVDAX_SIZE="$(ndctl list --namespace=namespace${{env.DEVDAX_NAMESPACE}} | grep size | cut -d':' -f2 | cut -d',' -f1)" ctest -C ${{matrix.build_type}} -R devdax -V diff --git a/.github/workflows/pr_push.yml b/.github/workflows/pr_push.yml index 02b7adf9f..c921eced6 100644 --- a/.github/workflows/pr_push.yml +++ b/.github/workflows/pr_push.yml @@ -88,7 +88,7 @@ jobs: uses: ./.github/workflows/basic.yml DevDax: needs: [FastBuild] - uses: ./.github/workflows/devdax.yml + uses: ./.github/workflows/dax.yml Sanitizers: needs: [FastBuild] uses: ./.github/workflows/sanitizers.yml From 64de5507fb1b0cf58e979d826f344251f6c4a9a5 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Tue, 24 Sep 2024 10:26:38 +0200 Subject: [PATCH 116/352] Add test if FSDAX is mapped with the MAP_SYNC flag Signed-off-by: Lukasz Dorau --- .github/workflows/dax.yml | 19 +++++++++ test/common/CMakeLists.txt | 4 ++ test/common/test_helpers_linux.c | 67 ++++++++++++++++++++++++++++++++ test/common/test_helpers_linux.h | 21 ++++++++++ test/provider_devdax_memory.cpp | 50 ++---------------------- test/provider_file_memory.cpp | 38 ++++++++++++++++++ 6 files changed, 153 insertions(+), 46 deletions(-) create mode 100644 test/common/test_helpers_linux.c create mode 100644 test/common/test_helpers_linux.h diff --git a/.github/workflows/dax.yml b/.github/workflows/dax.yml index db4e5768e..889825eaa 100644 --- a/.github/workflows/dax.yml +++ b/.github/workflows/dax.yml @@ -23,6 +23,9 @@ permissions: env: DEVDAX_NAMESPACE : "0.0" + FSDAX_NAMESPACE : "1.0" + FSDAX_PMEM: "pmem1" + UMF_TESTS_FSDAX_PATH: "/mnt/pmem1/file" BUILD_DIR : "${{github.workspace}}/build" INSTL_DIR : "${{github.workspace}}/../install-dir" @@ -46,6 +49,16 @@ jobs: echo UMF_TESTS_DEVDAX_PATH="/dev/dax${{env.DEVDAX_NAMESPACE}}" echo UMF_TESTS_DEVDAX_SIZE="$(ndctl list --namespace=namespace${{env.DEVDAX_NAMESPACE}} | grep size | cut -d':' -f2 | cut -d',' -f1)" + - name: Check configuration of the FSDAX + run: | + echo FSDAX_NAMESPACE="${{env.FSDAX_NAMESPACE}}" + echo UMF_TESTS_FSDAX_PATH="${{env.UMF_TESTS_FSDAX_PATH}}" + ndctl list --namespace=namespace${{env.FSDAX_NAMESPACE}} + ls -al /dev/${{env.FSDAX_PMEM}} /mnt/${{env.FSDAX_PMEM}} + mount | grep -e "/dev/${{env.FSDAX_PMEM}}" + touch ${{env.UMF_TESTS_FSDAX_PATH}} + rm -f ${{env.UMF_TESTS_FSDAX_PATH}} + - name: Checkout uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: @@ -80,3 +93,9 @@ jobs: UMF_TESTS_DEVDAX_PATH="/dev/dax${{env.DEVDAX_NAMESPACE}}" UMF_TESTS_DEVDAX_SIZE="$(ndctl list --namespace=namespace${{env.DEVDAX_NAMESPACE}} | grep size | cut -d':' -f2 | cut -d',' -f1)" ctest -C ${{matrix.build_type}} -R devdax -V + + - name: Run the FSDAX tests + working-directory: ${{env.BUILD_DIR}} + run: > + UMF_TESTS_FSDAX_PATH=${{env.UMF_TESTS_FSDAX_PATH}} + ctest -C ${{matrix.build_type}} -R umf-provider_file_memory -V diff --git a/test/common/CMakeLists.txt b/test/common/CMakeLists.txt index 4f88fd7d8..6cffe5cfe 100644 --- a/test/common/CMakeLists.txt +++ b/test/common/CMakeLists.txt @@ -9,6 +9,10 @@ set(COMMON_SOURCES provider_null.c provider_trace.c) +if(LINUX) + set(COMMON_SOURCES ${COMMON_SOURCES} test_helpers_linux.c) +endif(LINUX) + add_umf_library( NAME umf_test_common TYPE STATIC diff --git a/test/common/test_helpers_linux.c b/test/common/test_helpers_linux.c new file mode 100644 index 000000000..9f7606b09 --- /dev/null +++ b/test/common/test_helpers_linux.c @@ -0,0 +1,67 @@ +// Copyright (C) 2024 Intel Corporation +// Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// This file contains tests for UMF pool API + +#include +#include +#include +#include +#include +#include + +#include "test_helpers_linux.h" + +// Check if the file given by the 'path' argument was mapped with the MAP_SYNC flag: +// 1) Open and read the /proc/self/smaps file. +// 2) Look for the section of the 'path' file. +// 3) Check if the VmFlags of the 'path' file contains the "sf" flag +// marking that the file was mapped with the MAP_SYNC flag. +bool is_mapped_with_MAP_SYNC(char *path, char *buf, size_t size_buf) { + memset(buf, 0, size_buf); + + int fd = open("/proc/self/smaps", O_RDONLY); + if (fd == -1) { + return false; + } + + // number of bytes read from the file + ssize_t nbytes = 1; + // string starting from the path of the smaps + char *smaps = NULL; + + // Read the "/proc/self/smaps" file + // until the path of the smaps is found + // or EOF is reached. + while (nbytes > 0 && smaps == NULL) { + memset(buf, 0, nbytes); // erase previous data + nbytes = read(fd, buf, size_buf); + // look for the path of the smaps + smaps = strstr(buf, path); + } + + // String starting from the "sf" flag + // marking that memory was mapped with the MAP_SYNC flag. + char *sf_flag = NULL; + + if (smaps) { + // look for the "VmFlags:" string + char *VmFlags = strstr(smaps, "VmFlags:"); + if (VmFlags) { + // look for the EOL + char *eol = strstr(VmFlags, "\n"); + if (eol) { + // End the VmFlags string at EOL. + *eol = 0; + // Now the VmFlags string contains only one line with all VmFlags. + + // Look for the "sf" flag in VmFlags + // marking that memory was mapped + // with the MAP_SYNC flag. + sf_flag = strstr(VmFlags, "sf"); + } + } + } + + return (sf_flag != NULL); +} diff --git a/test/common/test_helpers_linux.h b/test/common/test_helpers_linux.h new file mode 100644 index 000000000..7755408b7 --- /dev/null +++ b/test/common/test_helpers_linux.h @@ -0,0 +1,21 @@ +// Copyright (C) 2024 Intel Corporation +// Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// This file contains helpers for tests for UMF pool API + +#ifndef UMF_TEST_HELPERS_LINUX_H +#define UMF_TEST_HELPERS_LINUX_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +bool is_mapped_with_MAP_SYNC(char *path, char *buf, size_t size_buf); + +#ifdef __cplusplus +} +#endif + +#endif /* UMF_TEST_HELPERS_LINUX_H */ diff --git a/test/provider_devdax_memory.cpp b/test/provider_devdax_memory.cpp index 1fdd53b08..6ed5f241e 100644 --- a/test/provider_devdax_memory.cpp +++ b/test/provider_devdax_memory.cpp @@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #ifndef _WIN32 +#include "test_helpers_linux.h" #include #include #include @@ -11,6 +12,7 @@ #include "base.hpp" #include "cpp_helpers.hpp" +#include "test_helpers.h" #include #include @@ -137,10 +139,6 @@ static void test_alloc_failure(umf_memory_provider_handle_t provider, // TESTS // Test checking if devdax was mapped with the MAP_SYNC flag: -// 1) Open and read the /proc/self/smaps file. -// 2) Look for the section of the devdax (the /dev/daxX.Y path). -// 3) Check if the VmFlags of the /dev/daxX.Y contains the "sf" flag -// marking that the devdax was mapped with the MAP_SYNC flag. TEST_F(test, test_if_mapped_with_MAP_SYNC) { umf_memory_provider_handle_t hProvider = nullptr; umf_result_t umf_result; @@ -167,48 +165,8 @@ TEST_F(test, test_if_mapped_with_MAP_SYNC) { umf_result = umfMemoryProviderAlloc(hProvider, size, 0, (void **)&buf); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(buf, nullptr); - memset(buf, 0, size); - - int fd = open("/proc/self/smaps", O_RDONLY); - ASSERT_NE(fd, -1); - - // number of bytes read from the file - ssize_t nbytes = 1; - // string starting from the path of the devdax - char *devdax = nullptr; - - // Read the "/proc/self/smaps" file - // until the path of the devdax is found - // or EOF is reached. - while (nbytes > 0 && devdax == nullptr) { - memset(buf, 0, nbytes); // erase previous data - nbytes = read(fd, buf, size); - // look for the path of the devdax - devdax = strstr(buf, path); - } - // String starting from the "sf" flag - // marking that memory was mapped with the MAP_SYNC flag. - char *sf_flag = nullptr; - - if (devdax) { - // look for the "VmFlags:" string - char *VmFlags = strstr(devdax, "VmFlags:"); - if (VmFlags) { - // look for the EOL - char *eol = strstr(VmFlags, "\n"); - if (eol) { - // End the VmFlags string at EOL. - *eol = 0; - // Now the VmFlags string contains only one line with all VmFlags. - - // Look for the "sf" flag in VmFlags - // marking that memory was mapped - // with the MAP_SYNC flag. - sf_flag = strstr(VmFlags, "sf"); - } - } - } + bool flag_found = is_mapped_with_MAP_SYNC(path, buf, size); umf_result = umfMemoryProviderFree(hProvider, buf, size); ASSERT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); @@ -216,7 +174,7 @@ TEST_F(test, test_if_mapped_with_MAP_SYNC) { umfMemoryProviderDestroy(hProvider); // fail test if the "sf" flag was not found - ASSERT_NE(sf_flag, nullptr); + ASSERT_EQ(flag_found, true); } // positive tests using test_alloc_free_success diff --git a/test/provider_file_memory.cpp b/test/provider_file_memory.cpp index 3903febe7..3ec7b849e 100644 --- a/test/provider_file_memory.cpp +++ b/test/provider_file_memory.cpp @@ -6,6 +6,9 @@ #include "cpp_helpers.hpp" #include "test_helpers.h" +#ifndef _WIN32 +#include "test_helpers_linux.h" +#endif #include #include @@ -121,6 +124,41 @@ static void test_alloc_failure(umf_memory_provider_handle_t provider, // TESTS +// Test checking if FSDAX was mapped with the MAP_SYNC flag: +TEST_F(test, test_if_mapped_with_MAP_SYNC) { + umf_memory_provider_handle_t hProvider = nullptr; + umf_result_t umf_result; + + char *path = getenv("UMF_TESTS_FSDAX_PATH"); + if (path == nullptr || path[0] == 0) { + GTEST_SKIP() << "Test skipped, UMF_TESTS_FSDAX_PATH is not set"; + } + + auto params = umfFileMemoryProviderParamsDefault(path); + params.visibility = UMF_MEM_MAP_SYNC; + + umf_result = umfMemoryProviderCreate(umfFileMemoryProviderOps(), ¶ms, + &hProvider); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(hProvider, nullptr); + + char *buf; + size_t size = 2 * 1024 * 1024; // 2MB + umf_result = umfMemoryProviderAlloc(hProvider, size, 0, (void **)&buf); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(buf, nullptr); + + bool flag_found = is_mapped_with_MAP_SYNC(path, buf, size); + + umf_result = umfMemoryProviderFree(hProvider, buf, size); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); + + umfMemoryProviderDestroy(hProvider); + + // fail test if the "sf" flag was not found + ASSERT_EQ(flag_found, true); +} + // positive tests using test_alloc_free_success umf_file_memory_provider_params_t get_file_params_shared(char *path) { From cccc1ef81c5d8a0330c265b0804594a4d13825d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Tue, 24 Sep 2024 12:43:36 +0200 Subject: [PATCH 117/352] [CI] Install python deps in venv in macos job the latest distros now do not allow global pip installation. --- .github/workflows/basic.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/basic.yml b/.github/workflows/basic.yml index cd06ad3bf..6a12c025f 100644 --- a/.github/workflows/basic.yml +++ b/.github/workflows/basic.yml @@ -440,8 +440,13 @@ jobs: with: fetch-depth: 0 - - name: Install Python requirements - run: python3 -m pip install -r third_party/requirements.txt + # Latest distros do not allow global pip installation + - name: Install Python requirements in venv + run: | + python3 -m venv .venv + . .venv/bin/activate + echo "$PATH" >> $GITHUB_PATH + python3 -m pip install -r third_party/requirements.txt - name: Install hwloc run: brew install hwloc jemalloc tbb From c9d8273435a835c8e62e95fe4f01a1bad5381996 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Tue, 24 Sep 2024 16:05:23 +0200 Subject: [PATCH 118/352] Fix cuda_shared_memory standalone example Signed-off-by: Lukasz Dorau --- examples/cmake/FindCUDA.cmake | 35 ++++++++++++++++++++++ examples/cuda_shared_memory/CMakeLists.txt | 16 +++++++--- 2 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 examples/cmake/FindCUDA.cmake diff --git a/examples/cmake/FindCUDA.cmake b/examples/cmake/FindCUDA.cmake new file mode 100644 index 000000000..92ef5c830 --- /dev/null +++ b/examples/cmake/FindCUDA.cmake @@ -0,0 +1,35 @@ +# Copyright (C) 2024 Intel Corporation +# Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +message(STATUS "Checking for module 'cuda' using find_library()") + +find_library(CUDA_LIBRARY NAMES libcuda cuda) +set(CUDA_LIBRARIES ${CUDA_LIBRARY}) + +get_filename_component(CUDA_LIB_DIR ${CUDA_LIBRARIES} DIRECTORY) +set(CUDA_LIBRARY_DIRS ${CUDA_LIB_DIR}) + +if(WINDOWS) + find_file(CUDA_DLL NAMES "bin/cuda.dll" "cuda.dll") + get_filename_component(CUDA_DLL_DIR ${CUDA_DLL} DIRECTORY) + set(CUDA_DLL_DIRS ${CUDA_DLL_DIR}) +endif() + +if(CUDA_LIBRARY) + message(STATUS " Found cuda using find_library()") + message(STATUS " CUDA_LIBRARIES = ${CUDA_LIBRARIES}") + message(STATUS " CUDA_INCLUDE_DIRS = ${CUDA_INCLUDE_DIRS}") + message(STATUS " CUDA_LIBRARY_DIRS = ${CUDA_LIBRARY_DIRS}") + if(WINDOWS) + message(STATUS " CUDA_DLL_DIRS = ${CUDA_DLL_DIRS}") + endif() +else() + set(MSG_NOT_FOUND "cuda NOT found (set CMAKE_PREFIX_PATH to point the " + "location)") + if(CUDA_FIND_REQUIRED) + message(FATAL_ERROR ${MSG_NOT_FOUND}) + else() + message(WARNING ${MSG_NOT_FOUND}) + endif() +endif() diff --git a/examples/cuda_shared_memory/CMakeLists.txt b/examples/cuda_shared_memory/CMakeLists.txt index a30621887..8a5300910 100644 --- a/examples/cuda_shared_memory/CMakeLists.txt +++ b/examples/cuda_shared_memory/CMakeLists.txt @@ -21,6 +21,8 @@ if(NOT LIBHWLOC_FOUND) find_package(LIBHWLOC 2.3.0 REQUIRED hwloc) endif() +find_package(CUDA REQUIRED cuda) + include(FetchContent) set(CUDA_REPO "https://gitlab.com/nvidia/headers/cuda-individual/cudart.git") @@ -43,17 +45,23 @@ set(CUDA_INCLUDE_DIRS ${cuda-headers_SOURCE_DIR} CACHE PATH "Path to CUDA headers") message(STATUS "CUDA include directory: ${CUDA_INCLUDE_DIRS}") + # build the example set(EXAMPLE_NAME umf_example_cuda_shared_memory) add_executable(${EXAMPLE_NAME} cuda_shared_memory.c) target_include_directories( ${EXAMPLE_NAME} PRIVATE ${CUDA_INCLUDE_DIRS} ${LIBUMF_INCLUDE_DIRS} ${UMF_EXAMPLE_DIR}/common) -target_link_directories(${EXAMPLE_NAME} PRIVATE ${LIBUMF_LIBRARY_DIRS} - ${LIBHWLOC_LIBRARY_DIRS}) +target_link_directories( + ${EXAMPLE_NAME} + PRIVATE + ${LIBUMF_LIBRARY_DIRS} + ${LIBHWLOC_LIBRARY_DIRS} + ${CUDA_LIBRARY_DIRS}) target_link_options(${EXAMPLE_NAME} PRIVATE "-Wl,--start-group") -target_link_libraries(${EXAMPLE_NAME} PRIVATE stdc++ libdisjoint_pool.a cuda - ${LIBUMF_LIBRARIES}) +target_link_libraries( + ${EXAMPLE_NAME} PRIVATE stdc++ libdisjoint_pool.a ${CUDA_LIBRARIES} + ${LIBUMF_LIBRARIES}) # an optional part - adds a test of this example add_test( From 7e0467eaa24019f24b3b5afd4195fac5f742421d Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 25 Sep 2024 11:33:21 +0200 Subject: [PATCH 119/352] Fix name of the umf-standalone_examples test Replace umf_standalone_examples with umf-standalone_examples. Signed-off-by: Lukasz Dorau --- test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 22599dad4..6bbd7c54a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -552,7 +552,7 @@ if(LINUX if(EXAMPLES AND NOT UMF_DISABLE_HWLOC) add_test( - NAME umf_standalone_examples + NAME umf-standalone_examples COMMAND ${UMF_CMAKE_SOURCE_DIR}/test/test_examples.sh ${UMF_CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} From 303f8cb722ccc888a8dd642f2a3ffe1fc81635ce Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 25 Sep 2024 12:23:29 +0200 Subject: [PATCH 120/352] Rename the custom_provider example to custom_file_provider Rename the directory of the example: - from custom_provider to custom_file_provider and rename the source code file of the example: - from file_provider.c to custom_file_provider.c Signed-off-by: Lukasz Dorau --- examples/CMakeLists.txt | 5 +++-- .../custom_file_provider.c} | 0 scripts/docs_config/examples.rst | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) rename examples/{custom_provider/file_provider.c => custom_file_provider/custom_file_provider.c} (100%) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 763d11670..acb118941 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -251,11 +251,12 @@ if(LINUX) set_tests_properties(${EXAMPLE_NAME} PROPERTIES SKIP_RETURN_CODE ${UMF_TEST_SKIP_RETURN_CODE}) - set(EXAMPLE_NAME umf_example_file_provider) + + set(EXAMPLE_NAME umf_example_custom_file_provider) add_umf_executable( NAME ${EXAMPLE_NAME} - SRCS custom_provider/file_provider.c + SRCS custom_file_provider/custom_file_provider.c LIBS umf ${LIBHWLOC_LIBRARIES}) target_include_directories( diff --git a/examples/custom_provider/file_provider.c b/examples/custom_file_provider/custom_file_provider.c similarity index 100% rename from examples/custom_provider/file_provider.c rename to examples/custom_file_provider/custom_file_provider.c diff --git a/scripts/docs_config/examples.rst b/scripts/docs_config/examples.rst index 0f88fcc40..5e2ff71fa 100644 --- a/scripts/docs_config/examples.rst +++ b/scripts/docs_config/examples.rst @@ -127,7 +127,7 @@ TODO Custom memory provider ============================================================================== -You can find the full examples code in the `examples/custom_provider/file_provider.c`_ file +You can find the full examples code in the `examples/custom_file_provider/custom_file_provider.c`_ file in the UMF repository. TODO @@ -212,7 +212,7 @@ the :any:`umfCloseIPCHandle` function is called. .. _examples/level_zero_shared_memory/level_zero_shared_memory.c: https://github.com/oneapi-src/unified-memory-framework/blob/main/examples/level_zero_shared_memory/level_zero_shared_memory.c .. _examples/cuda_shared_memory/cuda_shared_memory.c: https://github.com/oneapi-src/unified-memory-framework/blob/main/examples/cuda_shared_memory/cuda_shared_memory.c .. _examples/ipc_level_zero/ipc_level_zero.c: https://github.com/oneapi-src/unified-memory-framework/blob/main/examples/ipc_level_zero/ipc_level_zero.c -.. _examples/custom_provider/file_provider.c: https://github.com/oneapi-src/unified-memory-framework/blob/main/examples/custom_provider/file_provider.c +.. _examples/custom_file_provider/custom_file_provider.c: https://github.com/oneapi-src/unified-memory-framework/blob/main/examples/custom_file_provider/custom_file_provider.c .. _examples/memspace: https://github.com/oneapi-src/unified-memory-framework/blob/main/examples/memspace/ .. _README: https://github.com/oneapi-src/unified-memory-framework/blob/main/README.md#memory-pool-managers .. _umf/ipc.h: https://github.com/oneapi-src/unified-memory-framework/blob/main/include/umf/ipc.h From 7da769627c637b11481082d2d01e70ee89ef67f3 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 25 Sep 2024 14:44:58 +0200 Subject: [PATCH 121/352] Move memspace examples into two separate directories Signed-off-by: Lukasz Dorau --- examples/CMakeLists.txt | 4 ++-- examples/{memspace => memspace_hmat}/memspace_hmat.c | 0 examples/{memspace => memspace_numa}/memspace_numa.c | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename examples/{memspace => memspace_hmat}/memspace_hmat.c (100%) rename examples/{memspace => memspace_numa}/memspace_numa.c (100%) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 763d11670..3acf16d88 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -210,7 +210,7 @@ if(LINUX) add_umf_executable( NAME ${EXAMPLE_NAME} - SRCS memspace/memspace_numa.c + SRCS memspace_numa/memspace_numa.c LIBS umf ${LIBHWLOC_LIBRARIES} numa) target_include_directories( @@ -233,7 +233,7 @@ if(LINUX) add_umf_executable( NAME ${EXAMPLE_NAME} - SRCS memspace/memspace_hmat.c + SRCS memspace_hmat/memspace_hmat.c LIBS umf ${LIBHWLOC_LIBRARIES} numa) target_include_directories( diff --git a/examples/memspace/memspace_hmat.c b/examples/memspace_hmat/memspace_hmat.c similarity index 100% rename from examples/memspace/memspace_hmat.c rename to examples/memspace_hmat/memspace_hmat.c diff --git a/examples/memspace/memspace_numa.c b/examples/memspace_numa/memspace_numa.c similarity index 100% rename from examples/memspace/memspace_numa.c rename to examples/memspace_numa/memspace_numa.c From b42dd42e7de555f42ed8dc95342e1c0f63e55250 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 25 Sep 2024 15:10:46 +0200 Subject: [PATCH 122/352] Make memspace_hmat and memspace_numa examples standalone Signed-off-by: Lukasz Dorau --- examples/cmake/FindLIBNUMA.cmake | 20 +++++++++ examples/memspace_hmat/CMakeLists.txt | 58 +++++++++++++++++++++++++++ examples/memspace_numa/CMakeLists.txt | 58 +++++++++++++++++++++++++++ test/CMakeLists.txt | 9 +++++ 4 files changed, 145 insertions(+) create mode 100644 examples/cmake/FindLIBNUMA.cmake create mode 100644 examples/memspace_hmat/CMakeLists.txt create mode 100644 examples/memspace_numa/CMakeLists.txt diff --git a/examples/cmake/FindLIBNUMA.cmake b/examples/cmake/FindLIBNUMA.cmake new file mode 100644 index 000000000..8c23f481c --- /dev/null +++ b/examples/cmake/FindLIBNUMA.cmake @@ -0,0 +1,20 @@ +# Copyright (C) 2024 Intel Corporation +# Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +message(STATUS "Checking for module 'libnuma' using find_library()") + +find_library(LIBNUMA_LIBRARY NAMES libnuma numa) +set(LIBNUMA_LIBRARIES ${LIBNUMA_LIBRARY}) + +if(LIBNUMA_LIBRARY) + message(STATUS " Found libnuma using find_library()") +else() + set(MSG_NOT_FOUND + "libnuma NOT found (set CMAKE_PREFIX_PATH to point the location)") + if(LIBNUMA_FIND_REQUIRED) + message(FATAL_ERROR ${MSG_NOT_FOUND}) + else() + message(WARNING ${MSG_NOT_FOUND}) + endif() +endif() diff --git a/examples/memspace_hmat/CMakeLists.txt b/examples/memspace_hmat/CMakeLists.txt new file mode 100644 index 000000000..5f0fffaa1 --- /dev/null +++ b/examples/memspace_hmat/CMakeLists.txt @@ -0,0 +1,58 @@ +# Copyright (C) 2024 Intel Corporation +# Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 3.14.0 FATAL_ERROR) +project(umf_example_memspace_hmat LANGUAGES C) +enable_testing() + +set(UMF_EXAMPLE_DIR "${CMAKE_SOURCE_DIR}/..") +list(APPEND CMAKE_MODULE_PATH "${UMF_EXAMPLE_DIR}/cmake") +message(STATUS "CMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}") + +find_package(PkgConfig) +pkg_check_modules(LIBUMF libumf) +if(NOT LIBUMF_FOUND) + find_package(LIBUMF REQUIRED libumf) +endif() + +pkg_check_modules(LIBHWLOC hwloc>=2.3.0) +if(NOT LIBHWLOC_FOUND) + find_package(LIBHWLOC 2.3.0 REQUIRED hwloc) +endif() + +pkg_check_modules(LIBNUMA numa) +if(NOT LIBNUMA_FOUND) + find_package(LIBNUMA REQUIRED numa) +endif() + +# build the example +set(EXAMPLE_NAME umf_example_memspace_hmat) +add_executable(${EXAMPLE_NAME} memspace_hmat.c) +target_include_directories(${EXAMPLE_NAME} PRIVATE ${LIBUMF_INCLUDE_DIRS} + ../common) +target_link_directories(${EXAMPLE_NAME} PRIVATE ${LIBHWLOC_LIBRARY_DIRS} + ${LIBNUMA_LIBRARY_DIRS}) +target_link_libraries( + ${EXAMPLE_NAME} PRIVATE ${LIBUMF_LIBRARIES} ${LIBHWLOC_LIBRARIES} + ${LIBNUMA_LIBRARIES}) + +add_test( + NAME ${EXAMPLE_NAME} + COMMAND ${EXAMPLE_NAME} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + +set(UMF_TEST_SKIP_RETURN_CODE 125) +set_tests_properties(${EXAMPLE_NAME} PROPERTIES LABELS "example-standalone") +set_tests_properties(${EXAMPLE_NAME} PROPERTIES SKIP_RETURN_CODE + ${UMF_TEST_SKIP_RETURN_CODE}) + +if(LINUX) + # set LD_LIBRARY_PATH + set_property( + TEST ${EXAMPLE_NAME} + PROPERTY + ENVIRONMENT_MODIFICATION + "LD_LIBRARY_PATH=path_list_append:${LIBUMF_LIBRARY_DIRS};LD_LIBRARY_PATH=path_list_append:${LIBHWLOC_LIBRARY_DIRS};LD_LIBRARY_PATH=path_list_append:${LIBNUMA_LIBRARY_DIRS}" + ) +endif() diff --git a/examples/memspace_numa/CMakeLists.txt b/examples/memspace_numa/CMakeLists.txt new file mode 100644 index 000000000..d9c41a843 --- /dev/null +++ b/examples/memspace_numa/CMakeLists.txt @@ -0,0 +1,58 @@ +# Copyright (C) 2024 Intel Corporation +# Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 3.14.0 FATAL_ERROR) +project(umf_example_memspace_numa LANGUAGES C) +enable_testing() + +set(UMF_EXAMPLE_DIR "${CMAKE_SOURCE_DIR}/..") +list(APPEND CMAKE_MODULE_PATH "${UMF_EXAMPLE_DIR}/cmake") +message(STATUS "CMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}") + +find_package(PkgConfig) +pkg_check_modules(LIBUMF libumf) +if(NOT LIBUMF_FOUND) + find_package(LIBUMF REQUIRED libumf) +endif() + +pkg_check_modules(LIBHWLOC hwloc>=2.3.0) +if(NOT LIBHWLOC_FOUND) + find_package(LIBHWLOC 2.3.0 REQUIRED hwloc) +endif() + +pkg_check_modules(LIBNUMA numa) +if(NOT LIBNUMA_FOUND) + find_package(LIBNUMA REQUIRED numa) +endif() + +# build the example +set(EXAMPLE_NAME umf_example_memspace_numa) +add_executable(${EXAMPLE_NAME} memspace_numa.c) +target_include_directories(${EXAMPLE_NAME} PRIVATE ${LIBUMF_INCLUDE_DIRS} + ../common) +target_link_directories(${EXAMPLE_NAME} PRIVATE ${LIBHWLOC_LIBRARY_DIRS} + ${LIBNUMA_LIBRARY_DIRS}) +target_link_libraries( + ${EXAMPLE_NAME} PRIVATE ${LIBUMF_LIBRARIES} ${LIBHWLOC_LIBRARIES} + ${LIBNUMA_LIBRARIES}) + +add_test( + NAME ${EXAMPLE_NAME} + COMMAND ${EXAMPLE_NAME} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + +set(UMF_TEST_SKIP_RETURN_CODE 125) +set_tests_properties(${EXAMPLE_NAME} PROPERTIES LABELS "example-standalone") +set_tests_properties(${EXAMPLE_NAME} PROPERTIES SKIP_RETURN_CODE + ${UMF_TEST_SKIP_RETURN_CODE}) + +if(LINUX) + # set LD_LIBRARY_PATH + set_property( + TEST ${EXAMPLE_NAME} + PROPERTY + ENVIRONMENT_MODIFICATION + "LD_LIBRARY_PATH=path_list_append:${LIBUMF_LIBRARY_DIRS};LD_LIBRARY_PATH=path_list_append:${LIBHWLOC_LIBRARY_DIRS};LD_LIBRARY_PATH=path_list_append:${LIBNUMA_LIBRARY_DIRS}" + ) +endif() diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 22599dad4..4123e1e55 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -504,6 +504,15 @@ if(LINUX ) endif() + if(LIBNUMA_LIBRARIES) + set(EXAMPLES ${EXAMPLES} memspace_hmat memspace_numa) + else() + message( + STATUS + "The memspace_hmat and memspace_numa examples require libnuma to be installed and added to the default library search path - skipping" + ) + endif() + if(UMF_BUILD_GPU_EXAMPLES AND UMF_BUILD_LIBUMF_POOL_DISJOINT AND UMF_BUILD_LEVEL_ZERO_PROVIDER) From 66c85f210a6beef24e4498348e92ce2bc202be0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Plewa?= Date: Thu, 19 Sep 2024 17:25:31 +0200 Subject: [PATCH 123/352] add memspace filter functions --- include/umf/base.h | 5 +- include/umf/memspace.h | 54 ++++++++++ include/umf/memtarget.h | 7 ++ src/libumf.def.in | 13 ++- src/libumf.map.in | 11 +- src/memspace.c | 150 +++++++++++++++++++++++++++ src/memspace_internal.h | 6 -- src/memtarget.c | 9 ++ src/memtarget_ops.h | 1 + src/memtargets/memtarget_numa.c | 10 ++ src/provider/provider_level_zero.c | 5 - test/memspaces/memspace_fixtures.hpp | 12 +++ test/memspaces/memspace_numa.cpp | 149 ++++++++++++++++++++++++++ test/memspaces/memtarget.cpp | 39 ++++++- 14 files changed, 446 insertions(+), 25 deletions(-) diff --git a/include/umf/base.h b/include/umf/base.h index 854688a86..53378195d 100644 --- a/include/umf/base.h +++ b/include/umf/base.h @@ -1,6 +1,6 @@ /* * - * Copyright (C) 2023 Intel Corporation + * 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 @@ -43,7 +43,8 @@ typedef enum umf_result_t { UMF_RESULT_ERROR_INVALID_ALIGNMENT = 4, ///< Invalid alignment of an argument UMF_RESULT_ERROR_NOT_SUPPORTED = 5, ///< Operation not supported - + UMF_RESULT_ERROR_USER_SPECIFIC = + 6, ///< Failure in user provider code (i.e in user provided callback) UMF_RESULT_ERROR_UNKNOWN = 0x7ffffffe ///< Unknown or internal error } umf_result_t; diff --git a/include/umf/memspace.h b/include/umf/memspace.h index 49eb5278e..85b6b3681 100644 --- a/include/umf/memspace.h +++ b/include/umf/memspace.h @@ -131,6 +131,60 @@ umf_result_t umfMemspaceMemtargetRemove(umf_memspace_handle_t hMemspace, umf_const_memtarget_handle_t hMemtarget); +/// \brief Clones memspace. +/// +/// \param hMemspace handle to memspace +/// \param hNewMemspace [out] handle to the newly created memspace +/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +/// +umf_result_t umfMemspaceClone(umf_const_memspace_handle_t hMemspace, + umf_memspace_handle_t *hNewMemspace); + +/// \brief Custom filter function for umfMemspaceUserFilter +/// +/// \param hMemspace handle to memspace +/// \param hMemtarget handle to memory target +/// \param args user provided arguments +/// \return zero if hMemtarget should be removed from memspace, positive otherwise, and negative on error +/// +typedef int (*umf_memspace_filter_func_t)( + umf_const_memspace_handle_t hMemspace, + umf_const_memtarget_handle_t hMemtarget, void *args); + +/// \brief Removes all memory targets with non-matching numa node ids. +/// +/// \param hMemspace handle to memspace +/// \param ids array of numa node ids +/// \param size size of the array +/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +/// If the error code is UMF_RESULT_UNKNOWN the memspace is corrupted, otherwise the memspace is not modified. +/// +umf_result_t umfMemspaceFilterById(umf_memspace_handle_t hMemspace, + unsigned *ids, size_t size); + +/// \brief Filters out memory targets that capacity is less than specified size. +/// +/// \param hMemspace handle to memspace +/// \param size minimum capacity of memory target +/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +/// If the error code is UMF_RESULT_UNKNOWN the memspace is corrupted, otherwise the memspace is not modified. +/// \details Negative values of size parameters are reserved for future +/// extension of functionality of this function. +/// +umf_result_t umfMemspaceFilterByCapacity(umf_memspace_handle_t hMemspace, + int64_t size); + +/// \brief Filters out memory targets based on user provided function +/// +/// \param hMemspace handle to memspace +/// \param filter user provided function +/// \param args user provided arguments +/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +/// If the error code is UMF_RESULT_UNKNOWN the memspace is corrupted, otherwise the memspace is not modified. +/// +umf_result_t umfMemspaceUserFilter(umf_memspace_handle_t hMemspace, + umf_memspace_filter_func_t filter, + void *args); #ifdef __cplusplus } #endif diff --git a/include/umf/memtarget.h b/include/umf/memtarget.h index a4902b98d..d74947f14 100644 --- a/include/umf/memtarget.h +++ b/include/umf/memtarget.h @@ -39,6 +39,13 @@ umf_result_t umfMemtargetGetType(umf_const_memtarget_handle_t hMemtarget, umf_result_t umfMemtargetGetCapacity(umf_const_memtarget_handle_t hMemtarget, size_t *capacity); +/// \brief Get physical ID of the memory target. +/// \param hMemtarget handle to the memory target +/// \param id [out] id of the memory target +/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfMemtargetGetId(umf_const_memtarget_handle_t hMemtarget, + unsigned *id); + #ifdef __cplusplus } #endif diff --git a/src/libumf.def.in b/src/libumf.def.in index 8e2fe4b93..e0a43042e 100644 --- a/src/libumf.def.in +++ b/src/libumf.def.in @@ -40,13 +40,18 @@ EXPORTS umfMempolicyDestroy umfMempolicySetCustomSplitPartitions umfMempolicySetInterleavePartSize - umfMemspaceNew + umfMemspaceClone umfMemspaceDestroy - umfMemspaceMemtargetNum - umfMemspaceMemtargetGet - umfMemtargetGetCapacity + umfMemspaceFilterByCapacity + umfMemspaceFilterById umfMemspaceMemtargetAdd + umfMemspaceMemtargetGet + umfMemspaceMemtargetNum umfMemspaceMemtargetRemove + umfMemspaceNew + umfMemspaceUserFilter + umfMemtargetGetCapacity + umfMemtargetGetId umfMemtargetGetType umfOpenIPCHandle umfPoolAlignedMalloc diff --git a/src/libumf.map.in b/src/libumf.map.in index c078b24c9..59fbe3cf3 100644 --- a/src/libumf.map.in +++ b/src/libumf.map.in @@ -34,14 +34,19 @@ UMF_1.0 { umfMempolicyDestroy; umfMempolicySetCustomSplitPartitions; umfMempolicySetInterleavePartSize; - umfMemspaceNew; + umfMemspaceClone; umfMemspaceCreateFromNumaArray; umfMemspaceDestroy; + umfMemspaceFilterByCapacity; + umfMemspaceFilterById; umfMemspaceMemtargetAdd; - umfMemspaceMemtargetRemove; - umfMemspaceMemtargetNum; umfMemspaceMemtargetGet; + umfMemspaceMemtargetNum; + umfMemspaceMemtargetRemove; + umfMemspaceNew; + umfMemspaceUserFilter; umfMemtargetGetCapacity; + umfMemtargetGetId; umfMemtargetGetType; umfOpenIPCHandle; umfPoolAlignedMalloc; diff --git a/src/memspace.c b/src/memspace.c index f21ecbc4e..1cd80e1fa 100644 --- a/src/memspace.c +++ b/src/memspace.c @@ -426,3 +426,153 @@ umfMemspaceMemtargetRemove(umf_memspace_handle_t hMemspace, hMemspace->size--; return UMF_RESULT_SUCCESS; } + +// Helper function - returns zero on success, negative in case of error in filter function +// and positive error code, in case of other errors. +static int umfMemspaceFilterHelper(umf_memspace_handle_t memspace, + umf_memspace_filter_func_t filter, + void *args) { + + if (!memspace || !filter) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + size_t idx = 0; + int ret; + umf_memtarget_handle_t *nodesToRemove = + umf_ba_global_alloc(sizeof(*nodesToRemove) * memspace->size); + if (!nodesToRemove) { + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + for (size_t i = 0; i < memspace->size; i++) { + ret = filter(memspace, memspace->nodes[i], args); + if (ret < 0) { + LOG_ERR("filter function failed"); + goto free_mem; + } else if (ret == 0) { + nodesToRemove[idx++] = memspace->nodes[i]; + } + } + + size_t i = 0; + for (; i < idx; i++) { + ret = umfMemspaceMemtargetRemove(memspace, nodesToRemove[i]); + if (ret != UMF_RESULT_SUCCESS) { + goto re_add; + } + } + + umf_ba_global_free(nodesToRemove); + return UMF_RESULT_SUCCESS; + +re_add: + // If target removal failed, add back previously removed targets. + for (size_t j = 0; j < i; j++) { + umf_result_t ret2 = umfMemspaceMemtargetAdd(memspace, nodesToRemove[j]); + if (ret2 != UMF_RESULT_SUCCESS) { + ret = + UMF_RESULT_ERROR_UNKNOWN; // indicate that memspace is corrupted + break; + } + } +free_mem: + umf_ba_global_free(nodesToRemove); + return ret; +} + +umf_result_t umfMemspaceUserFilter(umf_memspace_handle_t memspace, + umf_memspace_filter_func_t filter, + void *args) { + + if (!memspace || !filter) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + int ret = umfMemspaceFilterHelper(memspace, filter, args); + if (ret < 0) { + return UMF_RESULT_ERROR_USER_SPECIFIC; + } + + return ret; +} + +typedef struct filter_by_id_args { + unsigned *ids; // array of numa nodes ids + size_t size; // size of the array +} filter_by_id_args_t; + +/* + * The following predefined filter callbacks returns umf_result_t codes as negative value + * because only negative values are treated as errors. umfMemspaceFilterHelper() will pass + * this error code through and umfMemspaceFilterBy*() functions will translate this code to positive + * umf_result_t code. + */ + +static int filterById(umf_const_memspace_handle_t memspace, + umf_const_memtarget_handle_t target, void *args) { + if (!memspace || !target || !args) { + return -UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + filter_by_id_args_t *filterArgs = args; + for (size_t i = 0; i < filterArgs->size; i++) { + unsigned id; + umf_result_t ret = umfMemtargetGetId(target, &id); + if (ret != UMF_RESULT_SUCCESS) { + return -ret; + } + + if (id == filterArgs->ids[i]) { + return 1; + } + } + return 0; +} + +static int filterByCapacity(umf_const_memspace_handle_t memspace, + umf_const_memtarget_handle_t target, void *args) { + if (!memspace || !target || !args) { + return -UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + size_t capacity; + umf_result_t ret = umfMemtargetGetCapacity(target, &capacity); + if (ret != UMF_RESULT_SUCCESS) { + return -ret; + } + + size_t *targetCapacity = args; + return (capacity >= *targetCapacity) ? 1 : 0; +} + +umf_result_t umfMemspaceFilterById(umf_memspace_handle_t memspace, + unsigned *ids, size_t size) { + if (!memspace || !ids || size == 0) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + filter_by_id_args_t args = {ids, size}; + int ret = umfMemspaceFilterHelper(memspace, &filterById, &args); + + // if umfMemspaceFilter() returned negative umf_result_t change it to positive + return ret < 0 ? -ret : ret; +} + +umf_result_t umfMemspaceFilterByCapacity(umf_memspace_handle_t memspace, + int64_t capacity) { + if (!memspace) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + // TODO: At this moment this function filters out memory targets that capacity is + // less than specified size. We can extend this function to support reverse filter, + // by using negative values of capacity parameter. + // For now we just return invalid argument. + if (capacity < 0) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + int ret = umfMemspaceFilterHelper(memspace, &filterByCapacity, &capacity); + + // if umfMemspaceFilter() returned negative umf_result_t change it to positive + return ret < 0 ? -ret : ret; +} diff --git a/src/memspace_internal.h b/src/memspace_internal.h index 8f678ff7d..e31898e84 100644 --- a/src/memspace_internal.h +++ b/src/memspace_internal.h @@ -24,12 +24,6 @@ struct umf_memspace_t { umf_memtarget_handle_t *nodes; }; -/// -/// \brief Clones memspace -/// -umf_result_t umfMemspaceClone(umf_const_memspace_handle_t hMemspace, - umf_memspace_handle_t *outHandle); - typedef umf_result_t (*umfGetPropertyFn)(umf_const_memtarget_handle_t, uint64_t *); diff --git a/src/memtarget.c b/src/memtarget.c index a79ec2a6c..a89708460 100644 --- a/src/memtarget.c +++ b/src/memtarget.c @@ -107,6 +107,15 @@ umf_result_t umfMemtargetGetLatency(umf_memtarget_handle_t srcMemoryTarget, dstMemoryTarget->priv, latency); } +umf_result_t umfMemtargetGetId(umf_const_memtarget_handle_t hMemtarget, + unsigned *id) { + if (!hMemtarget || !id) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + return hMemtarget->ops->get_id(hMemtarget->priv, id); +} + umf_result_t umfMemtargetGetType(umf_const_memtarget_handle_t memoryTarget, umf_memtarget_type_t *type) { if (!memoryTarget || !type) { diff --git a/src/memtarget_ops.h b/src/memtarget_ops.h index 43c66ce92..75e16447e 100644 --- a/src/memtarget_ops.h +++ b/src/memtarget_ops.h @@ -45,6 +45,7 @@ typedef struct umf_memtarget_ops_t { size_t *latency); umf_result_t (*get_type)(void *memoryTarget, umf_memtarget_type_t *type); + umf_result_t (*get_id)(void *memoryTarget, unsigned *type); umf_result_t (*compare)(void *memTarget, void *otherMemTarget, int *result); } umf_memtarget_ops_t; diff --git a/src/memtargets/memtarget_numa.c b/src/memtargets/memtarget_numa.c index 08be3f883..cb0e4ce00 100644 --- a/src/memtargets/memtarget_numa.c +++ b/src/memtargets/memtarget_numa.c @@ -326,6 +326,15 @@ static umf_result_t numa_get_type(void *memTarget, umf_memtarget_type_t *type) { return UMF_RESULT_SUCCESS; } +static umf_result_t numa_get_id(void *memTarget, unsigned *id) { + if (!memTarget || !id) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + *id = ((struct numa_memtarget_t *)memTarget)->physical_id; + return UMF_RESULT_SUCCESS; +} + static umf_result_t numa_compare(void *memTarget, void *otherMemTarget, int *result) { if (!memTarget || !otherMemTarget || !result) { @@ -350,6 +359,7 @@ struct umf_memtarget_ops_t UMF_MEMTARGET_NUMA_OPS = { .get_bandwidth = numa_get_bandwidth, .get_latency = numa_get_latency, .get_type = numa_get_type, + .get_id = numa_get_id, .compare = numa_compare, .memory_provider_create_from_memspace = numa_memory_provider_create_from_memspace}; diff --git a/src/provider/provider_level_zero.c b/src/provider/provider_level_zero.c index 6c2cf84b1..d9c4afe1f 100644 --- a/src/provider/provider_level_zero.c +++ b/src/provider/provider_level_zero.c @@ -188,12 +188,7 @@ static void ze_memory_provider_finalize(void *provider) { return; } - utils_init_once(&ze_is_initialized, init_ze_global_state); umf_ba_global_free(provider); - - // portable version of "ze_is_initialized = UTIL_ONCE_FLAG_INIT;" - static UTIL_ONCE_FLAG is_initialized = UTIL_ONCE_FLAG_INIT; - memcpy(&ze_is_initialized, &is_initialized, sizeof(ze_is_initialized)); } static bool use_relaxed_allocation(ze_memory_provider_t *ze_provider, diff --git a/test/memspaces/memspace_fixtures.hpp b/test/memspaces/memspace_fixtures.hpp index 116f3e5dc..d2886ee7e 100644 --- a/test/memspaces/memspace_fixtures.hpp +++ b/test/memspaces/memspace_fixtures.hpp @@ -102,6 +102,18 @@ struct memspaceProviderTest : ::memspaceGetTest { umf_memory_provider_handle_t hProvider = nullptr; }; +struct numaNodesCapacityTest : numaNodesTest { + void SetUp() override { + numaNodesTest::SetUp(); + + for (auto nodeId : nodeIds) { + capacities.push_back(numa_node_size64(nodeId, nullptr)); + } + } + + std::vector capacities; +}; + GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(memspaceGetTest); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(memspaceProviderTest); diff --git a/test/memspaces/memspace_numa.cpp b/test/memspaces/memspace_numa.cpp index 0065f710f..b10ed4e58 100644 --- a/test/memspaces/memspace_numa.cpp +++ b/test/memspaces/memspace_numa.cpp @@ -235,3 +235,152 @@ TEST_F(memspaceNumaProviderTest, allocFree) { ret = umfMemoryProviderFree(hProvider, ptr, size); ASSERT_EQ(ret, UMF_RESULT_SUCCESS); } + +TEST_F(numaNodesCapacityTest, CapacityFilter) { + if (capacities.size() <= 1) { + GTEST_SKIP() << "Not enough numa nodes - skipping the test"; + } + + umf_memspace_handle_t hMemspace; + auto ret = umfMemspaceClone(umfMemspaceHostAllGet(), &hMemspace); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(hMemspace, nullptr); + + std::sort(capacities.begin(), capacities.end()); + + size_t filter_size = capacities[capacities.size() / 2]; + ret = umfMemspaceFilterByCapacity(hMemspace, filter_size); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + ASSERT_EQ(umfMemspaceMemtargetNum(hMemspace), (capacities.size() + 1) / 2); + for (size_t i = 0; i < umfMemspaceMemtargetNum(hMemspace); i++) { + auto hTarget = umfMemspaceMemtargetGet(hMemspace, i); + ASSERT_NE(hTarget, nullptr); + size_t capacity; + auto ret = umfMemtargetGetCapacity(hTarget, &capacity); + EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + auto it = std::find(capacities.begin(), capacities.end(), capacity); + EXPECT_NE(it, capacities.end()); + EXPECT_GE(capacity, filter_size); + if (it != capacities.end()) { + capacities.erase(it); + } + } + umfMemspaceDestroy(hMemspace); +} + +TEST_F(numaNodesTest, idfilter) { + if (nodeIds.size() <= 1) { + GTEST_SKIP() << "Not enough numa nodes - skipping the test"; + } + + umf_memspace_handle_t hMemspace; + auto ret = umfMemspaceClone(umfMemspaceHostAllGet(), &hMemspace); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(hMemspace, nullptr); + + std::vector ids = {nodeIds[0], nodeIds[1]}; + ret = umfMemspaceFilterById(hMemspace, ids.data(), 2); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + ASSERT_EQ(umfMemspaceMemtargetNum(hMemspace), 2); + + for (size_t i = 0; i < umfMemspaceMemtargetNum(hMemspace); i++) { + auto hTarget = umfMemspaceMemtargetGet(hMemspace, i); + ASSERT_NE(hTarget, nullptr); + unsigned id; + auto ret = umfMemtargetGetId(hTarget, &id); + EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + auto it = std::find(ids.begin(), ids.end(), id); + EXPECT_NE(it, ids.end()); + if (it != ids.end()) { + ids.erase(it); + } + } + umfMemspaceDestroy(hMemspace); +} + +int customfilter(umf_const_memspace_handle_t memspace, + umf_const_memtarget_handle_t memtarget, void *args) { + static unsigned customFilterCounter = 0; + + EXPECT_NE(args, nullptr); + EXPECT_NE(memspace, nullptr); + EXPECT_NE(memtarget, nullptr); + + auto ids = (std::vector *)args; + if (customFilterCounter++ % 2) { + ids->push_back(memtarget); + return 1; + } else { + return 0; + } +} + +TEST_F(numaNodesTest, customfilter) { + if (nodeIds.size() <= 1) { + GTEST_SKIP() << "Not enough numa nodes - skipping the test"; + } + + umf_memspace_handle_t hMemspace; + auto ret = umfMemspaceClone(umfMemspaceHostAllGet(), &hMemspace); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(hMemspace, nullptr); + + std::vector vec; + ret = umfMemspaceUserFilter(hMemspace, &customfilter, &vec); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + ASSERT_EQ(umfMemspaceMemtargetNum(hMemspace), nodeIds.size() / 2); + + for (size_t i = 0; i < umfMemspaceMemtargetNum(hMemspace); i++) { + auto hTarget = umfMemspaceMemtargetGet(hMemspace, i); + ASSERT_NE(hTarget, nullptr); + + EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + auto it = std::find(vec.begin(), vec.end(), hTarget); + EXPECT_NE(it, vec.end()); + if (it != vec.end()) { + vec.erase(it); + } + } + ASSERT_EQ(vec.size(), 0); + umfMemspaceDestroy(hMemspace); +} + +int invalidFilter(umf_const_memspace_handle_t memspace, + umf_const_memtarget_handle_t memtarget, void *args) { + EXPECT_EQ(args, nullptr); + EXPECT_NE(memspace, nullptr); + EXPECT_NE(memtarget, nullptr); + + return -1; +} + +TEST_F(numaNodesTest, invalidFilters) { + umf_memspace_handle_t hMemspace; + auto ret = umfMemspaceClone(umfMemspaceHostAllGet(), &hMemspace); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(hMemspace, nullptr); + + ret = umfMemspaceFilterByCapacity(nullptr, 0); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + ret = umfMemspaceFilterByCapacity(hMemspace, -1); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + ret = umfMemspaceFilterById(hMemspace, nullptr, 0); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + unsigned id = 0; + ret = umfMemspaceFilterById(nullptr, &id, 1); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + ret = umfMemspaceUserFilter(hMemspace, nullptr, nullptr); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + ret = umfMemspaceUserFilter(nullptr, invalidFilter, nullptr); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + ret = umfMemspaceUserFilter(hMemspace, invalidFilter, nullptr); + ASSERT_EQ(ret, UMF_RESULT_ERROR_USER_SPECIFIC); + umfMemspaceDestroy(hMemspace); +} diff --git a/test/memspaces/memtarget.cpp b/test/memspaces/memtarget.cpp index c4cc80a8f..325fa9d1d 100644 --- a/test/memspaces/memtarget.cpp +++ b/test/memspaces/memtarget.cpp @@ -24,13 +24,9 @@ TEST_F(test, memTargetNuma) { } } -TEST_F(numaNodesTest, getCapacity) { +TEST_F(numaNodesCapacityTest, getCapacity) { auto memspace = umfMemspaceHostAllGet(); ASSERT_NE(memspace, nullptr); - std::vector capacities; - for (auto nodeId : nodeIds) { - capacities.push_back(numa_node_size64(nodeId, nullptr)); - } for (size_t i = 0; i < umfMemspaceMemtargetNum(memspace); i++) { auto hTarget = umfMemspaceMemtargetGet(memspace, i); @@ -47,6 +43,25 @@ TEST_F(numaNodesTest, getCapacity) { ASSERT_EQ(capacities.size(), 0); } +TEST_F(numaNodesTest, getId) { + auto memspace = umfMemspaceHostAllGet(); + ASSERT_NE(memspace, nullptr); + + for (size_t i = 0; i < umfMemspaceMemtargetNum(memspace); i++) { + auto hTarget = umfMemspaceMemtargetGet(memspace, i); + ASSERT_NE(hTarget, nullptr); + unsigned id; + auto ret = umfMemtargetGetId(hTarget, &id); + EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + auto it = std::find(nodeIds.begin(), nodeIds.end(), id); + EXPECT_NE(it, nodeIds.end()); + if (it != nodeIds.end()) { + nodeIds.erase(it); + } + } + ASSERT_EQ(nodeIds.size(), 0); +} + TEST_F(numaNodesTest, getCapacityInvalid) { auto memspace = umfMemspaceHostAllGet(); ASSERT_NE(memspace, nullptr); @@ -74,3 +89,17 @@ TEST_F(test, memTargetInvalid) { ret = umfMemtargetGetType(hTarget, NULL); EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); } + +TEST_F(numaNodesTest, getIdInvalid) { + auto memspace = umfMemspaceHostAllGet(); + ASSERT_NE(memspace, nullptr); + unsigned id; + auto ret = umfMemtargetGetId(NULL, &id); + EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + ret = umfMemtargetGetId(NULL, NULL); + EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + auto hTarget = umfMemspaceMemtargetGet(memspace, 0); + ASSERT_NE(hTarget, nullptr); + ret = umfMemtargetGetId(hTarget, NULL); + EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} From 47bca4f05a9c4cc31d4508c25a1d11eeaf51588c Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 25 Sep 2024 17:08:54 +0200 Subject: [PATCH 124/352] Make the custom_file_provider example standalone Make the custom_file_provider example standalone: - add own standalone CMakeLists.txt file - add this example to the umf-standalone_examples test. Signed-off-by: Lukasz Dorau --- examples/custom_file_provider/CMakeLists.txt | 52 ++++++++++++++++++++ test/CMakeLists.txt | 6 ++- 2 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 examples/custom_file_provider/CMakeLists.txt diff --git a/examples/custom_file_provider/CMakeLists.txt b/examples/custom_file_provider/CMakeLists.txt new file mode 100644 index 000000000..9d4e336c7 --- /dev/null +++ b/examples/custom_file_provider/CMakeLists.txt @@ -0,0 +1,52 @@ +# Copyright (C) 2024 Intel Corporation +# Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 3.14.0 FATAL_ERROR) +project(umf_example_custom_file_provider LANGUAGES C) +enable_testing() + +set(UMF_EXAMPLE_DIR "${CMAKE_SOURCE_DIR}/..") +list(APPEND CMAKE_MODULE_PATH "${UMF_EXAMPLE_DIR}/cmake") +message(STATUS "CMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}") + +find_package(PkgConfig) +pkg_check_modules(LIBUMF libumf) +if(NOT LIBUMF_FOUND) + find_package(LIBUMF REQUIRED libumf) +endif() + +pkg_check_modules(LIBHWLOC hwloc>=2.3.0) +if(NOT LIBHWLOC_FOUND) + find_package(LIBHWLOC 2.3.0 REQUIRED hwloc) +endif() + +pkg_check_modules(TBB tbb) +if(NOT TBB_FOUND) + find_package(TBB REQUIRED tbb) +endif() + +# build the example +set(EXAMPLE_NAME umf_example_custom_file_provider) +add_executable(${EXAMPLE_NAME} custom_file_provider.c) +target_include_directories(${EXAMPLE_NAME} PRIVATE ${LIBUMF_INCLUDE_DIRS}) +target_link_directories(${EXAMPLE_NAME} PRIVATE ${LIBHWLOC_LIBRARY_DIRS}) +target_link_libraries(${EXAMPLE_NAME} PRIVATE ${LIBUMF_LIBRARIES} + ${LIBHWLOC_LIBRARIES}) + +add_test( + NAME ${EXAMPLE_NAME} + COMMAND ${EXAMPLE_NAME} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + +set_tests_properties(${EXAMPLE_NAME} PROPERTIES LABELS "example-standalone") + +if(LINUX) + # set LD_LIBRARY_PATH + set_property( + TEST ${EXAMPLE_NAME} + PROPERTY + ENVIRONMENT_MODIFICATION + "LD_LIBRARY_PATH=path_list_append:${LIBUMF_LIBRARY_DIRS};LD_LIBRARY_PATH=path_list_append:${LIBHWLOC_LIBRARY_DIRS}" + ) +endif() diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 22599dad4..c1877ddab 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -494,13 +494,15 @@ if(LINUX OR UMF_USE_UBSAN OR UMF_USE_TSAN OR UMF_USE_MSAN)) + set(EXAMPLES "") + if(UMF_POOL_SCALABLE_ENABLED) - set(EXAMPLES ${EXAMPLES} basic) + set(EXAMPLES ${EXAMPLES} basic custom_file_provider) else() message( STATUS - "The basic example requires TBB to be installed and added to the default library search path - skipping" + "The basic and custom_file_provider examples require TBB to be installed and added to the default library search path - skipping" ) endif() From 49a6a3f2c1604569f5af3317fd52caf5b7342017 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 25 Sep 2024 17:17:40 +0200 Subject: [PATCH 125/352] Fix test_valgrind.sh If a test fails, but there is no "ERROR SUMMARY" string in the LOG, the LOG is removed and the whole test fails with the following error message: ls: cannot access 'umf_test-*.log': No such file or directory This patch fixes that. Signed-off-by: Lukasz Dorau --- test/test_valgrind.sh | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/test/test_valgrind.sh b/test/test_valgrind.sh index bfe4275af..c52243b40 100755 --- a/test/test_valgrind.sh +++ b/test/test_valgrind.sh @@ -68,7 +68,7 @@ echo echo "Working directory: $(pwd)" echo "Running: \"valgrind $OPTION\" for the following tests:" -FAIL=0 +ANY_TEST_FAILED=0 rm -f umf_test-*.log umf_test-*.err for test in $(ls -1 umf_test-*); do @@ -121,8 +121,11 @@ for test in $(ls -1 umf_test-*); do [ "$FILTER" != "" ] && echo -n "($FILTER) " + LAST_TEST_FAILED=0 + if ! HWLOC_CPUID_PATH=./cpuid valgrind $OPTION $OPT_SUP --gen-suppressions=all ./$test $FILTER >$LOG 2>&1; then - FAIL=1 + LAST_TEST_FAILED=1 + ANY_TEST_FAILED=1 echo "(valgrind FAILED) " echo "Command: HWLOC_CPUID_PATH=./cpuid valgrind $OPTION $OPT_SUP --gen-suppressions=all ./$test $FILTER >$LOG 2>&1" echo "Output:" @@ -132,17 +135,17 @@ for test in $(ls -1 umf_test-*); do fi || true # grep for "ERROR SUMMARY" with errors (there can be many lines with "ERROR SUMMARY") grep -e "ERROR SUMMARY:" $LOG | grep -v -e "ERROR SUMMARY: 0 errors from 0 contexts" > $ERR || true - if [ $(cat $ERR | wc -l) -eq 0 ]; then + if [ $LAST_TEST_FAILED -eq 0 -a $(cat $ERR | wc -l) -eq 0 ]; then echo "- OK" rm -f $LOG $ERR else echo "- FAILED!" cat $ERR | cut -d' ' -f2- - FAIL=1 + ANY_TEST_FAILED=1 fi || true done -[ $FAIL -eq 0 ] && echo PASSED && exit 0 +[ $ANY_TEST_FAILED -eq 0 ] && echo PASSED && exit 0 echo echo "======================================================================" From c8766f08129e1b4b7ddc0f8511e3188ca968749b Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 25 Sep 2024 09:36:56 +0200 Subject: [PATCH 126/352] Pass STANDALONE_CMAKE_OPTIONS to standalone examples Signed-off-by: Lukasz Dorau --- test/CMakeLists.txt | 6 +++++- test/test_examples.sh | 10 ++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6bbd7c54a..e0c9e0730 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -551,13 +551,17 @@ if(LINUX endif() if(EXAMPLES AND NOT UMF_DISABLE_HWLOC) + set(STANDALONE_CMAKE_OPTIONS + "-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" + ) add_test( NAME umf-standalone_examples COMMAND ${UMF_CMAKE_SOURCE_DIR}/test/test_examples.sh ${UMF_CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/umf_standalone_examples/install-dir - "${CMAKE_INSTALL_PREFIX}" ${EXAMPLES} + "${CMAKE_INSTALL_PREFIX}" "${STANDALONE_CMAKE_OPTIONS}" + ${EXAMPLES} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) endif() endif() diff --git a/test/test_examples.sh b/test/test_examples.sh index 1d7e93ee1..efc86bcf9 100755 --- a/test/test_examples.sh +++ b/test/test_examples.sh @@ -9,15 +9,16 @@ SOURCE_DIR=$1 BUILD_DIR=$2 INSTALL_DIR=$3 CMAKE_INSTALL_PREFIX=$4 +STANDALONE_CMAKE_OPTIONS=$5 echo "Running: $0 $*" function print_usage() { echo "$(basename $0) - test all examples standalone" - echo "Usage: $(basename $0) " + echo "Usage: $(basename $0) " } -if [ "$5" = "" ]; then +if [ "$6" = "" ]; then print_usage echo -e "Error: too few arguments\n" exit 1 @@ -39,8 +40,9 @@ echo "SOURCE_DIR=$SOURCE_DIR" echo "BUILD_DIR=$BUILD_DIR" echo "CMAKE_INSTALL_PREFIX=$CMAKE_INSTALL_PREFIX" echo "INSTALL_DIR=$INSTALL_DIR" +echo "STANDALONE_CMAKE_OPTIONS=$STANDALONE_CMAKE_OPTIONS" -shift 4 +shift 5 EXAMPLES="$*" echo "Examples to run: $EXAMPLES" echo @@ -70,7 +72,7 @@ for ex in $EXAMPLES; do rm -rf $BLD_DIR mkdir -p $BLD_DIR cd $BLD_DIR - CMAKE_PREFIX_PATH="${INSTALL_DIR}/${CMAKE_INSTALL_PREFIX}" cmake $SRC_DIR + CMAKE_PREFIX_PATH="${INSTALL_DIR}/${CMAKE_INSTALL_PREFIX}" cmake $SRC_DIR $STANDALONE_CMAKE_OPTIONS make -j$(nproc) ctest --output-on-failure set +x From b2c18af31d1f73af05bb32cc09bb2491a7896b37 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Thu, 26 Sep 2024 09:18:15 +0200 Subject: [PATCH 127/352] Add dram_and_fsdax example Ref: #742 Signed-off-by: Lukasz Dorau --- .github/workflows/dax.yml | 8 +- CMakeLists.txt | 9 +- examples/CMakeLists.txt | 13 ++ examples/cmake/FindJEMALLOC.cmake | 52 +++++++ examples/dram_and_fsdax/CMakeLists.txt | 61 +++++++++ examples/dram_and_fsdax/dram_and_fsdax.c | 164 +++++++++++++++++++++++ test/CMakeLists.txt | 11 +- 7 files changed, 310 insertions(+), 8 deletions(-) create mode 100644 examples/cmake/FindJEMALLOC.cmake create mode 100644 examples/dram_and_fsdax/CMakeLists.txt create mode 100644 examples/dram_and_fsdax/dram_and_fsdax.c diff --git a/.github/workflows/dax.yml b/.github/workflows/dax.yml index 889825eaa..d3455df79 100644 --- a/.github/workflows/dax.yml +++ b/.github/workflows/dax.yml @@ -11,7 +11,7 @@ # # The FSDAX device should be mounted in the OS (e.g. /mnt/pmem1) # and the UMF_TESTS_FSDAX_PATH environment variable -# should contain a path to a file o this FSDAX device. +# should contain a path to a file on this FSDAX device. # name: Dax @@ -96,6 +96,6 @@ jobs: - name: Run the FSDAX tests working-directory: ${{env.BUILD_DIR}} - run: > - UMF_TESTS_FSDAX_PATH=${{env.UMF_TESTS_FSDAX_PATH}} - ctest -C ${{matrix.build_type}} -R umf-provider_file_memory -V + run: | + UMF_TESTS_FSDAX_PATH=${{env.UMF_TESTS_FSDAX_PATH}} ctest -C ${{matrix.build_type}} -R umf-provider_file_memory -V + UMF_TESTS_FSDAX_PATH=${{env.UMF_TESTS_FSDAX_PATH}} ctest -C ${{matrix.build_type}} -R umf_example_dram_and_fsdax -V diff --git a/CMakeLists.txt b/CMakeLists.txt index d926b7ec8..3ce5028c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -355,9 +355,12 @@ if(UMF_BUILD_LIBUMF_POOL_JEMALLOC) if(NOT JEMALLOC_FOUND) find_package(JEMALLOC REQUIRED jemalloc) endif() - # add PATH to DLL on Windows - set(DLL_PATH_LIST - "${DLL_PATH_LIST};PATH=path_list_append:${JEMALLOC_DLL_DIRS}") + if(JEMALLOC_FOUND OR JEMALLOC_LIBRARIES) + set(UMF_POOL_JEMALLOC_ENABLED TRUE) + # add PATH to DLL on Windows + set(DLL_PATH_LIST + "${DLL_PATH_LIST};PATH=path_list_append:${JEMALLOC_DLL_DIRS}") + endif() endif() if(WINDOWS) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 763d11670..99a1a58b0 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -269,6 +269,19 @@ if(LINUX) COMMAND ${EXAMPLE_NAME} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + if(UMF_POOL_JEMALLOC_ENABLED) + set(EXAMPLE_NAME umf_example_dram_and_fsdax) + + add_umf_executable( + NAME ${EXAMPLE_NAME} + SRCS dram_and_fsdax/dram_and_fsdax.c + LIBS umf jemalloc_pool) + + add_test( + NAME ${EXAMPLE_NAME} + COMMAND ${EXAMPLE_NAME} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + endif() else() message( STATUS "Memspace examples API are supported on Linux only - skipping") diff --git a/examples/cmake/FindJEMALLOC.cmake b/examples/cmake/FindJEMALLOC.cmake new file mode 100644 index 000000000..89d488ecc --- /dev/null +++ b/examples/cmake/FindJEMALLOC.cmake @@ -0,0 +1,52 @@ +# Copyright (C) 2024 Intel Corporation +# Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +message(STATUS "Checking for module 'jemalloc' using find_library()") + +find_library(JEMALLOC_LIBRARY NAMES libjemalloc jemalloc) +set(JEMALLOC_LIBRARIES ${JEMALLOC_LIBRARY}) + +get_filename_component(JEMALLOC_LIB_DIR ${JEMALLOC_LIBRARIES} DIRECTORY) +set(JEMALLOC_LIBRARY_DIRS ${JEMALLOC_LIB_DIR}) + +find_file(JEMALLOC_HEADER NAMES "jemalloc/jemalloc.h") +if(JEMALLOC_HEADER) + get_filename_component(JEMALLOC_INCLUDE_DIR_TBB ${JEMALLOC_HEADER} + DIRECTORY) + get_filename_component(JEMALLOC_INCLUDE_DIR ${JEMALLOC_INCLUDE_DIR_TBB} + DIRECTORY) + set(JEMALLOC_INCLUDE_DIRS ${JEMALLOC_INCLUDE_DIR}) +else() + set(MSG_NOT_FOUND " header NOT found " + "(set CMAKE_PREFIX_PATH to point the location)") + if(JEMALLOC_FIND_REQUIRED) + message(FATAL_ERROR ${MSG_NOT_FOUND}) + else() + message(WARNING ${MSG_NOT_FOUND}) + endif() +endif() + +if(WINDOWS) + find_file(JEMALLOC_DLL NAMES "bin/jemalloc.dll" "jemalloc.dll") + get_filename_component(JEMALLOC_DLL_DIR ${JEMALLOC_DLL} DIRECTORY) + set(JEMALLOC_DLL_DIRS ${JEMALLOC_DLL_DIR}) +endif() + +if(JEMALLOC_LIBRARY) + message(STATUS " Found jemalloc using find_library()") + message(STATUS " JEMALLOC_LIBRARIES = ${JEMALLOC_LIBRARIES}") + message(STATUS " JEMALLOC_INCLUDE_DIRS = ${JEMALLOC_INCLUDE_DIRS}") + message(STATUS " JEMALLOC_LIBRARY_DIRS = ${JEMALLOC_LIBRARY_DIRS}") + if(WINDOWS) + message(STATUS " JEMALLOC_DLL_DIRS = ${JEMALLOC_DLL_DIRS}") + endif() +else() + set(MSG_NOT_FOUND + "jemalloc NOT found (set CMAKE_PREFIX_PATH to point the location)") + if(JEMALLOC_FIND_REQUIRED) + message(FATAL_ERROR ${MSG_NOT_FOUND}) + else() + message(WARNING ${MSG_NOT_FOUND}) + endif() +endif() diff --git a/examples/dram_and_fsdax/CMakeLists.txt b/examples/dram_and_fsdax/CMakeLists.txt new file mode 100644 index 000000000..0d0bf2593 --- /dev/null +++ b/examples/dram_and_fsdax/CMakeLists.txt @@ -0,0 +1,61 @@ +# Copyright (C) 2024 Intel Corporation +# Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 3.14.0 FATAL_ERROR) +project(umf_example_dram_and_fsdax LANGUAGES C) +enable_testing() + +set(UMF_EXAMPLE_DIR "${CMAKE_SOURCE_DIR}/..") +list(APPEND CMAKE_MODULE_PATH "${UMF_EXAMPLE_DIR}/cmake") +message(STATUS "CMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}") + +find_package(PkgConfig) +pkg_check_modules(LIBUMF libumf) +if(NOT LIBUMF_FOUND) + find_package(LIBUMF REQUIRED libumf) +endif() + +pkg_check_modules(LIBHWLOC hwloc>=2.3.0) +if(NOT LIBHWLOC_FOUND) + find_package(LIBHWLOC 2.3.0 REQUIRED hwloc) +endif() + +pkg_check_modules(JEMALLOC jemalloc) +if(NOT JEMALLOC_FOUND) + find_package(JEMALLOC REQUIRED jemalloc) +endif() + +# build the example +set(EXAMPLE_NAME umf_example_dram_and_fsdax) +add_executable(${EXAMPLE_NAME} dram_and_fsdax.c) +target_include_directories(${EXAMPLE_NAME} PRIVATE ${LIBUMF_INCLUDE_DIRS}) + +target_link_directories( + ${EXAMPLE_NAME} + PRIVATE + ${LIBUMF_LIBRARY_DIRS} + ${LIBHWLOC_LIBRARY_DIRS} + ${JEMALLOC_LIBRARY_DIRS}) + +target_link_libraries( + ${EXAMPLE_NAME} PRIVATE hwloc jemalloc_pool ${JEMALLOC_LIBRARIES} + ${LIBUMF_LIBRARIES}) + +# an optional part - adds a test of this example +add_test( + NAME ${EXAMPLE_NAME} + COMMAND ${EXAMPLE_NAME} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + +set_tests_properties(${EXAMPLE_NAME} PROPERTIES LABELS "example-standalone") + +if(LINUX) + # set LD_LIBRARY_PATH + set_property( + TEST ${EXAMPLE_NAME} + PROPERTY + ENVIRONMENT_MODIFICATION + "LD_LIBRARY_PATH=path_list_append:${LIBUMF_LIBRARY_DIRS};LD_LIBRARY_PATH=path_list_append:${LIBHWLOC_LIBRARY_DIRS};LD_LIBRARY_PATH=path_list_append:${JEMALLOC_LIBRARY_DIRS}" + ) +endif() diff --git a/examples/dram_and_fsdax/dram_and_fsdax.c b/examples/dram_and_fsdax/dram_and_fsdax.c new file mode 100644 index 000000000..bc985692f --- /dev/null +++ b/examples/dram_and_fsdax/dram_and_fsdax.c @@ -0,0 +1,164 @@ +/* + * Copyright (C) 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 + +static umf_memory_pool_handle_t create_dram_pool(void) { + umf_memory_provider_handle_t provider_dram = NULL; + umf_memory_pool_handle_t pool_dram; + umf_result_t umf_result; + + umf_os_memory_provider_params_t params_dram = + umfOsMemoryProviderParamsDefault(); + + umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), ¶ms_dram, + &provider_dram); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Creation of the OS memory provider failed"); + return NULL; + } + + // Create a DRAM memory pool + umf_result = umfPoolCreate(umfJemallocPoolOps(), provider_dram, NULL, + UMF_POOL_CREATE_FLAG_OWN_PROVIDER, &pool_dram); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to create a DRAM memory pool!\n"); + umfMemoryProviderDestroy(provider_dram); + return NULL; + } + + return pool_dram; +} + +static umf_memory_pool_handle_t create_fsdax_pool(const char *path) { + umf_memory_provider_handle_t provider_fsdax = NULL; + umf_memory_pool_handle_t pool_fsdax; + umf_result_t umf_result; + + umf_file_memory_provider_params_t params_fsdax = + umfFileMemoryProviderParamsDefault(path); + // FSDAX requires mapping the UMF_MEM_MAP_SYNC flag + params_fsdax.visibility = UMF_MEM_MAP_SYNC; + + umf_result = umfMemoryProviderCreate(umfFileMemoryProviderOps(), + ¶ms_fsdax, &provider_fsdax); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to create the FSDAX file provider"); + return NULL; + } + + // Create an FSDAX memory pool + // + // The file memory provider does not support the free operation + // (`umfMemoryProviderFree()` always returns `UMF_RESULT_ERROR_NOT_SUPPORTED`), + // so it should be used with a pool manager that will take over + // the managing of the provided memory - for example the jemalloc pool + // with the `disable_provider_free` parameter set to true. + umf_jemalloc_pool_params_t pool_params; + pool_params.disable_provider_free = true; + + // Create an FSDAX memory pool + umf_result = + umfPoolCreate(umfJemallocPoolOps(), provider_fsdax, &pool_params, + UMF_POOL_CREATE_FLAG_OWN_PROVIDER, &pool_fsdax); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to create an FSDAX memory pool!\n"); + umfMemoryProviderDestroy(provider_fsdax); + return NULL; + } + + return pool_fsdax; +} + +int main(void) { + int ret = -1; + + // This example requires: + // - the FSDAX device to be mounted in the OS (e.g. /mnt/pmem1) and + // - the UMF_TESTS_FSDAX_PATH environment variable to contain + // a path to a file on this FSDAX device. + char *path = getenv("UMF_TESTS_FSDAX_PATH"); + if (path == NULL || path[0] == 0) { + fprintf( + stderr, + "Warning: UMF_TESTS_FSDAX_PATH is not set, skipping testing ...\n"); + return 0; + } + + umf_memory_pool_handle_t dram_pool = create_dram_pool(); + if (dram_pool == NULL) { + fprintf(stderr, "Failed to create a DRAM memory pool!\n"); + return -1; + } + + fprintf(stderr, "Created a DRAM memory pool\n"); + + umf_memory_pool_handle_t fsdax_pool = create_fsdax_pool(path); + if (fsdax_pool == NULL) { + fprintf(stderr, "Failed to create an FSDAX memory pool!\n"); + goto err_destroy_dram_pool; + } + + fprintf(stderr, "Created an FSDAX memory pool\n"); + + size_t size = 2 * 1024 * 1024; // == 2 MB + + // Allocate from the DRAM memory pool + char *dram_buf = umfPoolCalloc(dram_pool, 1, size); + if (dram_buf == NULL) { + fprintf(stderr, + "Failed to allocate memory from the DRAM memory pool!\n"); + goto err_destroy_pools; + } + + fprintf(stderr, "Allocated memory from the DRAM memory pool\n"); + + // Allocate from the FSDAX memory pool + char *fsdax_buf = umfPoolCalloc(fsdax_pool, 1, size); + if (fsdax_buf == NULL) { + fprintf(stderr, + "Failed to allocate memory from the FSDAX memory pool!\n"); + goto err_free_dram; + } + + fprintf(stderr, "Allocated memory from the FSDAX memory pool\n"); + + // Use the allocation from DRAM + dram_buf[0] = '.'; + + // Use the allocation from FSDAX + fsdax_buf[0] = '.'; + + // success + ret = 0; + + // The file memory provider does not support the free() operation, + // so we do not need to call: umfPoolFree(fsdax_pool, fsdax_buf); + +err_free_dram: + fprintf(stderr, "Freeing the allocation from the DRAM memory pool ...\n"); + umfPoolFree(dram_pool, dram_buf); + +err_destroy_pools: + fprintf(stderr, "Destroying the FSDAX memory pool ...\n"); + umfPoolDestroy(fsdax_pool); + +err_destroy_dram_pool: + fprintf(stderr, "Destroying the DRAM memory pool ...\n"); + umfPoolDestroy(dram_pool); + + return ret; +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e0c9e0730..96640cb1f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -541,7 +541,7 @@ if(LINUX ) endif() - if(LINUX AND UMF_POOL_SCALABLE_ENABLED) + if(UMF_POOL_SCALABLE_ENABLED) set(EXAMPLES ${EXAMPLES} ipc_ipcapi) else() message( @@ -550,6 +550,15 @@ if(LINUX ) endif() + if(UMF_POOL_JEMALLOC_ENABLED) + set(EXAMPLES ${EXAMPLES} dram_and_fsdax) + else() + message( + STATUS + "The dram_and_fsdax example is supported on Linux only and requires UMF_BUILD_LIBUMF_POOL_JEMALLOC to be turned ON - skipping" + ) + endif() + if(EXAMPLES AND NOT UMF_DISABLE_HWLOC) set(STANDALONE_CMAKE_OPTIONS "-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" From 3ea861415d2083f131a5bcb5dcb9716a416e05ad Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Thu, 26 Sep 2024 09:24:44 +0200 Subject: [PATCH 128/352] Close file descriptor in is_mapped_with_MAP_SYNC() Signed-off-by: Lukasz Dorau --- test/common/test_helpers_linux.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/common/test_helpers_linux.c b/test/common/test_helpers_linux.c index 9f7606b09..431880bf7 100644 --- a/test/common/test_helpers_linux.c +++ b/test/common/test_helpers_linux.c @@ -40,6 +40,8 @@ bool is_mapped_with_MAP_SYNC(char *path, char *buf, size_t size_buf) { smaps = strstr(buf, path); } + (void)close(fd); + // String starting from the "sf" flag // marking that memory was mapped with the MAP_SYNC flag. char *sf_flag = NULL; From 0d39b63dc1ef38a1437a226074c5bdcdc1b56ae6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Thu, 26 Sep 2024 13:53:56 +0200 Subject: [PATCH 129/352] Remove redundant, doubled function Ref. #745 --- src/utils/utils_macosx_common.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/utils/utils_macosx_common.c b/src/utils/utils_macosx_common.c index 586f0fa52..1356a2ef9 100644 --- a/src/utils/utils_macosx_common.c +++ b/src/utils/utils_macosx_common.c @@ -60,18 +60,6 @@ int utils_fallocate(int fd, long offset, long len) { return -1; } -umf_result_t os_translate_mem_visibility_flag(umf_memory_visibility_t in_flag, - unsigned *out_flag) { - switch (in_flag) { - case UMF_MEM_MAP_PRIVATE: - *out_flag = MAP_PRIVATE; - return UMF_RESULT_SUCCESS; - case UMF_MEM_MAP_SHARED: - return UMF_RESULT_ERROR_NOT_SUPPORTED; // not supported on MacOSX - } - return UMF_RESULT_ERROR_INVALID_ARGUMENT; -} - // create a shared memory file int utils_shm_create(const char *shm_name, size_t size) { (void)shm_name; // unused From 7a398cb853d4d51a7e538ebc8c404c183fdf6276 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Thu, 26 Sep 2024 14:00:46 +0200 Subject: [PATCH 130/352] Add IPC test for FSDAX Signed-off-by: Lukasz Dorau --- .github/workflows/dax.yml | 1 + test/CMakeLists.txt | 1 + test/ipc_file_prov_fsdax.sh | 37 +++++++++++++++++++++++++++++++++++++ test/test_valgrind.sh | 2 +- 4 files changed, 40 insertions(+), 1 deletion(-) create mode 100755 test/ipc_file_prov_fsdax.sh diff --git a/.github/workflows/dax.yml b/.github/workflows/dax.yml index d3455df79..04c36cf80 100644 --- a/.github/workflows/dax.yml +++ b/.github/workflows/dax.yml @@ -99,3 +99,4 @@ jobs: run: | UMF_TESTS_FSDAX_PATH=${{env.UMF_TESTS_FSDAX_PATH}} ctest -C ${{matrix.build_type}} -R umf-provider_file_memory -V UMF_TESTS_FSDAX_PATH=${{env.UMF_TESTS_FSDAX_PATH}} ctest -C ${{matrix.build_type}} -R umf_example_dram_and_fsdax -V + UMF_TESTS_FSDAX_PATH=${{env.UMF_TESTS_FSDAX_PATH}} ctest -C ${{matrix.build_type}} -R umf-ipc_file_prov_fsdax -V diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index dc2554b32..a10562038 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -433,6 +433,7 @@ if(LINUX) common/ipc_common.c common/ipc_os_prov_common.c) add_umf_ipc_test(TEST ipc_file_prov) + add_umf_ipc_test(TEST ipc_file_prov_fsdax) endif() # TODO add IPC tests for CUDA diff --git a/test/ipc_file_prov_fsdax.sh b/test/ipc_file_prov_fsdax.sh new file mode 100755 index 000000000..f2c799f11 --- /dev/null +++ b/test/ipc_file_prov_fsdax.sh @@ -0,0 +1,37 @@ +# +# Copyright (C) 2024 Intel Corporation +# +# Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +#!/bin/bash + +set -e + +if [ "$UMF_TESTS_FSDAX_PATH" = "" ]; then + echo "$0: Test skipped, UMF_TESTS_FSDAX_PATH is not set"; + exit 0 +fi + +FILE_NAME="$UMF_TESTS_FSDAX_PATH" + +# port should be a number from the range <1024, 65535> +PORT=$(( 1024 + ( $$ % ( 65535 - 1024 )))) + +UMF_LOG_VAL="level:debug;flush:debug;output:stderr;pid:yes" + +# make sure the temp file does not exist +rm -f ${FILE_NAME} + +echo "Starting ipc_file_prov_fsdax CONSUMER on port $PORT ..." +UMF_LOG=$UMF_LOG_VAL ./umf_test-ipc_file_prov_consumer $PORT $FILE_NAME & + +echo "Waiting 1 sec ..." +sleep 1 + +echo "Starting ipc_file_prov_fsdax PRODUCER on port $PORT ..." +UMF_LOG=$UMF_LOG_VAL ./umf_test-ipc_file_prov_producer $PORT $FILE_NAME + +# remove the SHM file +rm -f ${FILE_NAME} diff --git a/test/test_valgrind.sh b/test/test_valgrind.sh index c52243b40..4b8b25b3b 100755 --- a/test/test_valgrind.sh +++ b/test/test_valgrind.sh @@ -94,7 +94,7 @@ for test in $(ls -1 umf_test-*); do ;; umf_test-ipc_file_prov_*) echo "- SKIPPED" - continue; # skip testing helper binaries used by the ipc_file_prov test + continue; # skip testing helper binaries used by the ipc_file_prov_* tests ;; umf_test-memspace_host_all) FILTER='--gtest_filter="-*allocsSpreadAcrossAllNumaNodes"' From 5ed98826ac6588fb9eadfdec322806894e398c9a Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Thu, 26 Sep 2024 18:02:41 +0200 Subject: [PATCH 131/352] IPC API of OS memory provider requires UMF_MEM_MAP_SHARED visibility IPC API of OS memory provider requires the `UMF_MEM_MAP_SHARED` memory `visibility` mode (`UMF_RESULT_ERROR_INVALID_ARGUMENT` is returned otherwise). Signed-off-by: Lukasz Dorau --- README.md | 3 ++ src/provider/provider_os_memory.c | 30 +++++++++++++++++-- src/provider/provider_os_memory_internal.h | 6 ++++ test/provider_os_memory.cpp | 35 ++++++++++++++++++++++ 4 files changed, 71 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 048bcfaf7..605174bdc 100644 --- a/README.md +++ b/README.md @@ -143,6 +143,9 @@ OS memory provider supports two types of memory mappings (set by the `visibility 1) private memory mapping (`UMF_MEM_MAP_PRIVATE`) 2) shared memory mapping (`UMF_MEM_MAP_SHARED` - supported on Linux only yet) +IPC API requires the `UMF_MEM_MAP_SHARED` memory `visibility` mode +(`UMF_RESULT_ERROR_INVALID_ARGUMENT` is returned otherwise). + There are available two mechanisms for the shared memory mapping: 1) a named shared memory object (used if the `shm_name` parameter is not NULL) or 2) an anonymous file descriptor (used if the `shm_name` parameter is NULL) diff --git a/src/provider/provider_os_memory.c b/src/provider/provider_os_memory.c index 8c18e98cc..3b8bbbe91 100644 --- a/src/provider/provider_os_memory.c +++ b/src/provider/provider_os_memory.c @@ -402,6 +402,9 @@ static umf_result_t translate_params(umf_os_memory_provider_params_t *in_params, return result; } + // IPC API requires in_params->visibility == UMF_MEM_MAP_SHARED + provider->IPC_enabled = (in_params->visibility == UMF_MEM_MAP_SHARED); + // NUMA config int emptyNodeset = in_params->numa_list_len == 0; result = validate_numa_mode(in_params->numa_mode, emptyNodeset); @@ -1089,7 +1092,7 @@ static umf_result_t os_allocation_split(void *provider, void *ptr, (void)totalSize; os_memory_provider_t *os_provider = (os_memory_provider_t *)provider; - if (os_provider->fd <= 0) { + if (os_provider->fd < 0) { return UMF_RESULT_SUCCESS; } @@ -1122,7 +1125,7 @@ static umf_result_t os_allocation_merge(void *provider, void *lowPtr, (void)totalSize; os_memory_provider_t *os_provider = (os_memory_provider_t *)provider; - if (os_provider->fd <= 0) { + if (os_provider->fd < 0) { return UMF_RESULT_SUCCESS; } @@ -1152,6 +1155,10 @@ static umf_result_t os_get_ipc_handle_size(void *provider, size_t *size) { } os_memory_provider_t *os_provider = (os_memory_provider_t *)provider; + if (!os_provider->IPC_enabled) { + LOG_ERR("memory visibility mode is not UMF_MEM_MAP_SHARED") + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } if (os_provider->shm_name[0]) { // os_ipc_data_t->shm_name will be used @@ -1171,7 +1178,8 @@ static umf_result_t os_get_ipc_handle(void *provider, const void *ptr, } os_memory_provider_t *os_provider = (os_memory_provider_t *)provider; - if (os_provider->fd <= 0) { + if (!os_provider->IPC_enabled) { + LOG_ERR("memory visibility mode is not UMF_MEM_MAP_SHARED") return UMF_RESULT_ERROR_INVALID_ARGUMENT; } @@ -1203,6 +1211,11 @@ static umf_result_t os_put_ipc_handle(void *provider, void *providerIpcData) { } os_memory_provider_t *os_provider = (os_memory_provider_t *)provider; + if (!os_provider->IPC_enabled) { + LOG_ERR("memory visibility mode is not UMF_MEM_MAP_SHARED") + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + os_ipc_data_t *os_ipc_data = (os_ipc_data_t *)providerIpcData; if (os_ipc_data->pid != utils_getpid()) { @@ -1229,6 +1242,11 @@ static umf_result_t os_open_ipc_handle(void *provider, void *providerIpcData, } os_memory_provider_t *os_provider = (os_memory_provider_t *)provider; + if (!os_provider->IPC_enabled) { + LOG_ERR("memory visibility mode is not UMF_MEM_MAP_SHARED") + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + os_ipc_data_t *os_ipc_data = (os_ipc_data_t *)providerIpcData; umf_result_t ret = UMF_RESULT_SUCCESS; int fd; @@ -1269,6 +1287,12 @@ static umf_result_t os_close_ipc_handle(void *provider, void *ptr, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } + os_memory_provider_t *os_provider = (os_memory_provider_t *)provider; + if (!os_provider->IPC_enabled) { + LOG_ERR("memory visibility mode is not UMF_MEM_MAP_SHARED") + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + errno = 0; int ret = utils_munmap(ptr, size); // ignore error when size == 0 diff --git a/src/provider/provider_os_memory_internal.h b/src/provider/provider_os_memory_internal.h index 41b4ea11a..faf0de247 100644 --- a/src/provider/provider_os_memory_internal.h +++ b/src/provider/provider_os_memory_internal.h @@ -9,6 +9,7 @@ #define UMF_OS_MEMORY_PROVIDER_INTERNAL_H #include +#include #if defined(_WIN32) && !defined(NAME_MAX) #include @@ -29,8 +30,13 @@ extern "C" { typedef struct os_memory_provider_t { unsigned protection; // combination of OS-specific protection flags unsigned visibility; // memory visibility mode + + // IPC is enabled only if (in_params->visibility == UMF_MEM_MAP_SHARED) + bool IPC_enabled; + // a name of a shared memory file (valid only in case of the shared memory visibility) char shm_name[NAME_MAX]; + int fd; // file descriptor for memory mapping size_t size_fd; // size of file used for memory mapping size_t max_size_fd; // maximum size of file used for memory mapping diff --git a/test/provider_os_memory.cpp b/test/provider_os_memory.cpp index fca494af8..a14f50f57 100644 --- a/test/provider_os_memory.cpp +++ b/test/provider_os_memory.cpp @@ -328,6 +328,41 @@ TEST_P(umfProviderTest, purge_force_INVALID_POINTER) { UMF_OS_RESULT_ERROR_PURGE_FORCE_FAILED); } +TEST_P(umfProviderTest, get_ipc_handle_size_wrong_visibility) { + size_t size; + umf_result_t umf_result = + umfMemoryProviderGetIPCHandleSize(provider.get(), &size); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} + +TEST_P(umfProviderTest, get_ipc_handle_wrong_visibility) { + char providerIpcData; + umf_result_t umf_result = umfMemoryProviderGetIPCHandle( + provider.get(), INVALID_PTR, 1, &providerIpcData); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} + +TEST_P(umfProviderTest, put_ipc_handle_wrong_visibility) { + char providerIpcData; + umf_result_t umf_result = + umfMemoryProviderPutIPCHandle(provider.get(), &providerIpcData); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} + +TEST_P(umfProviderTest, open_ipc_handle_wrong_visibility) { + char providerIpcData; + void *ptr; + umf_result_t umf_result = + umfMemoryProviderOpenIPCHandle(provider.get(), &providerIpcData, &ptr); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} + +TEST_P(umfProviderTest, close_ipc_handle_wrong_visibility) { + umf_result_t umf_result = + umfMemoryProviderCloseIPCHandle(provider.get(), INVALID_PTR, 1); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} + GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(umfIpcTest); umf_os_memory_provider_params_t osMemoryProviderParamsShared() { From b726d3e945966a17ffa8df52ec5b34ca1ea233ce Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Thu, 26 Sep 2024 18:14:02 +0200 Subject: [PATCH 132/352] File provider IPC API requires UMF_MEM_MAP_SHARED or UMF_MEM_MAP_SYNC IPC API of file memory provider requires the `UMF_MEM_MAP_SHARED` or `UMF_MEM_MAP_SYNC` memory `visibility` mode (`UMF_RESULT_ERROR_INVALID_ARGUMENT` is returned otherwise). Signed-off-by: Lukasz Dorau --- README.md | 3 + src/provider/provider_file_memory.c | 39 ++++++++++++ test/provider_file_memory.cpp | 95 ++++++++++++++++++++++------- 3 files changed, 114 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 605174bdc..9c73ecbf1 100644 --- a/README.md +++ b/README.md @@ -203,6 +203,9 @@ so it should be used with a pool manager that will take over the managing of the provided memory - for example the jemalloc pool with the `disable_provider_free` parameter set to true. +IPC API requires the `UMF_MEM_MAP_SHARED` or `UMF_MEM_MAP_SYNC` memory `visibility` mode +(`UMF_RESULT_ERROR_INVALID_ARGUMENT` is returned otherwise). + The memory visibility mode parameter must be set to `UMF_MEM_MAP_SYNC` in case of FSDAX. ##### Requirements diff --git a/src/provider/provider_file_memory.c b/src/provider/provider_file_memory.c index ed9b23164..ec967f3df 100644 --- a/src/provider/provider_file_memory.c +++ b/src/provider/provider_file_memory.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -41,6 +42,9 @@ typedef struct file_memory_provider_t { unsigned visibility; // memory visibility mode size_t page_size; // minimum page size + // IPC is enabled only for UMF_MEM_MAP_SHARED or UMF_MEM_MAP_SYNC visibility + bool IPC_enabled; + critnib *mmaps; // a critnib map storing mmap mappings (addr, size) // A critnib map storing (ptr, fd_offset + 1) pairs. We add 1 to fd_offset @@ -101,6 +105,10 @@ file_translate_params(umf_file_memory_provider_params_t *in_params, return result; } + // IPC is enabled only for UMF_MEM_MAP_SHARED or UMF_MEM_MAP_SYNC visibility + provider->IPC_enabled = (in_params->visibility == UMF_MEM_MAP_SHARED || + in_params->visibility == UMF_MEM_MAP_SYNC); + return UMF_RESULT_SUCCESS; } @@ -545,6 +553,13 @@ static umf_result_t file_get_ipc_handle_size(void *provider, size_t *size) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; } + file_memory_provider_t *file_provider = (file_memory_provider_t *)provider; + if (!file_provider->IPC_enabled) { + LOG_ERR("memory visibility mode is not UMF_MEM_MAP_SHARED nor " + "UMF_MEM_MAP_SYNC") + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + *size = sizeof(file_ipc_data_t); return UMF_RESULT_SUCCESS; @@ -557,6 +572,11 @@ static umf_result_t file_get_ipc_handle(void *provider, const void *ptr, } file_memory_provider_t *file_provider = (file_memory_provider_t *)provider; + if (!file_provider->IPC_enabled) { + LOG_ERR("memory visibility mode is not UMF_MEM_MAP_SHARED nor " + "UMF_MEM_MAP_SYNC") + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } void *value = critnib_get(file_provider->fd_offset_map, (uintptr_t)ptr); if (value == NULL) { @@ -581,6 +601,12 @@ static umf_result_t file_put_ipc_handle(void *provider, void *providerIpcData) { } file_memory_provider_t *file_provider = (file_memory_provider_t *)provider; + if (!file_provider->IPC_enabled) { + LOG_ERR("memory visibility mode is not UMF_MEM_MAP_SHARED nor " + "UMF_MEM_MAP_SYNC") + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + file_ipc_data_t *file_ipc_data = (file_ipc_data_t *)providerIpcData; if (strncmp(file_ipc_data->path, file_provider->path, PATH_MAX)) { @@ -597,6 +623,12 @@ static umf_result_t file_open_ipc_handle(void *provider, void *providerIpcData, } file_memory_provider_t *file_provider = (file_memory_provider_t *)provider; + if (!file_provider->IPC_enabled) { + LOG_ERR("memory visibility mode is not UMF_MEM_MAP_SHARED nor " + "UMF_MEM_MAP_SYNC") + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + file_ipc_data_t *file_ipc_data = (file_ipc_data_t *)providerIpcData; umf_result_t ret = UMF_RESULT_SUCCESS; int fd; @@ -631,6 +663,13 @@ static umf_result_t file_close_ipc_handle(void *provider, void *ptr, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } + file_memory_provider_t *file_provider = (file_memory_provider_t *)provider; + if (!file_provider->IPC_enabled) { + LOG_ERR("memory visibility mode is not UMF_MEM_MAP_SHARED nor " + "UMF_MEM_MAP_SYNC") + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + errno = 0; int ret = utils_munmap(ptr, size); // ignore error when size == 0 diff --git a/test/provider_file_memory.cpp b/test/provider_file_memory.cpp index 3ec7b849e..a00f31adc 100644 --- a/test/provider_file_memory.cpp +++ b/test/provider_file_memory.cpp @@ -55,7 +55,7 @@ static void providerCreateExt(providerCreateExtParams params, umf::provider_unique_handle_t(hProvider, &umfMemoryProviderDestroy); } -struct umfProviderTest +struct FileProviderParamsDefault : umf_test::test, ::testing::WithParamInterface { void SetUp() override { @@ -75,6 +75,8 @@ struct umfProviderTest size_t page_plus_64; }; +struct FileProviderParamsShared : FileProviderParamsDefault {}; + static void test_alloc_free_success(umf_memory_provider_handle_t provider, size_t size, size_t alignment, purge_t purge) { @@ -161,6 +163,9 @@ TEST_F(test, test_if_mapped_with_MAP_SYNC) { // positive tests using test_alloc_free_success +umf_file_memory_provider_params_t file_params_default = + umfFileMemoryProviderParamsDefault(FILE_PATH); + umf_file_memory_provider_params_t get_file_params_shared(char *path) { umf_file_memory_provider_params_t file_params = umfFileMemoryProviderParamsDefault(path); @@ -171,60 +176,100 @@ umf_file_memory_provider_params_t get_file_params_shared(char *path) { umf_file_memory_provider_params_t file_params_shared = get_file_params_shared(FILE_PATH); -INSTANTIATE_TEST_SUITE_P(fileProviderTest, umfProviderTest, +INSTANTIATE_TEST_SUITE_P(fileProviderTest, FileProviderParamsDefault, ::testing::Values(providerCreateExtParams{ - umfFileMemoryProviderOps(), &file_params_shared})); + umfFileMemoryProviderOps(), + &file_params_default})); -TEST_P(umfProviderTest, create_destroy) {} +TEST_P(FileProviderParamsDefault, create_destroy) {} -TEST_P(umfProviderTest, alloc_page64_align_0) { +TEST_P(FileProviderParamsDefault, alloc_page64_align_0) { test_alloc_free_success(provider.get(), page_plus_64, 0, PURGE_NONE); } -TEST_P(umfProviderTest, alloc_page64_align_page_div_2) { +TEST_P(FileProviderParamsDefault, alloc_page64_align_page_div_2) { test_alloc_free_success(provider.get(), page_plus_64, page_size / 2, PURGE_NONE); } -TEST_P(umfProviderTest, purge_lazy) { +TEST_P(FileProviderParamsDefault, purge_lazy) { test_alloc_free_success(provider.get(), page_plus_64, 0, PURGE_LAZY); } -TEST_P(umfProviderTest, purge_force) { +TEST_P(FileProviderParamsDefault, purge_force) { test_alloc_free_success(provider.get(), page_plus_64, 0, PURGE_FORCE); } // negative tests using test_alloc_failure -TEST_P(umfProviderTest, alloc_WRONG_SIZE) { +TEST_P(FileProviderParamsDefault, alloc_WRONG_SIZE) { test_alloc_failure(provider.get(), -1, 0, UMF_RESULT_ERROR_INVALID_ARGUMENT, 0); } -TEST_P(umfProviderTest, alloc_page64_WRONG_ALIGNMENT_3_pages) { +TEST_P(FileProviderParamsDefault, alloc_page64_WRONG_ALIGNMENT_3_pages) { test_alloc_failure(provider.get(), page_plus_64, 3 * page_size, UMF_RESULT_ERROR_INVALID_ALIGNMENT, 0); } -TEST_P(umfProviderTest, alloc_3pages_WRONG_ALIGNMENT_3pages) { +TEST_P(FileProviderParamsDefault, alloc_3pages_WRONG_ALIGNMENT_3pages) { test_alloc_failure(provider.get(), 3 * page_size, 3 * page_size, UMF_RESULT_ERROR_INVALID_ALIGNMENT, 0); } -TEST_P(umfProviderTest, alloc_page64_align_page_minus_1_WRONG_ALIGNMENT_1) { +TEST_P(FileProviderParamsDefault, + alloc_page64_align_page_minus_1_WRONG_ALIGNMENT_1) { test_alloc_failure(provider.get(), page_plus_64, page_size - 1, UMF_RESULT_ERROR_INVALID_ALIGNMENT, 0); } -TEST_P(umfProviderTest, alloc_page64_align_one_half_pages_WRONG_ALIGNMENT_2) { +TEST_P(FileProviderParamsDefault, + alloc_page64_align_one_half_pages_WRONG_ALIGNMENT_2) { test_alloc_failure(provider.get(), page_plus_64, page_size + (page_size / 2), UMF_RESULT_ERROR_INVALID_ALIGNMENT, 0); } +// negative IPC tests + +TEST_P(FileProviderParamsDefault, get_ipc_handle_size_wrong_visibility) { + size_t size; + umf_result_t umf_result = + umfMemoryProviderGetIPCHandleSize(provider.get(), &size); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} + +TEST_P(FileProviderParamsDefault, get_ipc_handle_wrong_visibility) { + char providerIpcData; + umf_result_t umf_result = umfMemoryProviderGetIPCHandle( + provider.get(), INVALID_PTR, 1, &providerIpcData); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} + +TEST_P(FileProviderParamsDefault, put_ipc_handle_wrong_visibility) { + char providerIpcData; + umf_result_t umf_result = + umfMemoryProviderPutIPCHandle(provider.get(), &providerIpcData); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} + +TEST_P(FileProviderParamsDefault, open_ipc_handle_wrong_visibility) { + char providerIpcData; + void *ptr; + umf_result_t umf_result = + umfMemoryProviderOpenIPCHandle(provider.get(), &providerIpcData, &ptr); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} + +TEST_P(FileProviderParamsDefault, close_ipc_handle_wrong_visibility) { + umf_result_t umf_result = + umfMemoryProviderCloseIPCHandle(provider.get(), INVALID_PTR, 1); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} + // other positive tests -TEST_P(umfProviderTest, get_min_page_size) { +TEST_P(FileProviderParamsDefault, get_min_page_size) { size_t min_page_size; umf_result_t umf_result = umfMemoryProviderGetMinPageSize( provider.get(), nullptr, &min_page_size); @@ -232,7 +277,7 @@ TEST_P(umfProviderTest, get_min_page_size) { ASSERT_LE(min_page_size, page_size); } -TEST_P(umfProviderTest, get_recommended_page_size) { +TEST_P(FileProviderParamsDefault, get_recommended_page_size) { size_t min_page_size; umf_result_t umf_result = umfMemoryProviderGetMinPageSize( provider.get(), nullptr, &min_page_size); @@ -246,18 +291,18 @@ TEST_P(umfProviderTest, get_recommended_page_size) { ASSERT_GE(recommended_page_size, min_page_size); } -TEST_P(umfProviderTest, get_name) { +TEST_P(FileProviderParamsDefault, get_name) { const char *name = umfMemoryProviderGetName(provider.get()); ASSERT_STREQ(name, "FILE"); } -TEST_P(umfProviderTest, free_size_0_ptr_not_null) { +TEST_P(FileProviderParamsDefault, free_size_0_ptr_not_null) { umf_result_t umf_result = umfMemoryProviderFree(provider.get(), INVALID_PTR, 0); ASSERT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); } -TEST_P(umfProviderTest, free_NULL) { +TEST_P(FileProviderParamsDefault, free_NULL) { umf_result_t umf_result = umfMemoryProviderFree(provider.get(), nullptr, 0); ASSERT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); } @@ -274,19 +319,19 @@ TEST_F(test, create_empty_path) { EXPECT_EQ(hProvider, nullptr); } -TEST_P(umfProviderTest, free_INVALID_POINTER_SIZE_GT_0) { +TEST_P(FileProviderParamsDefault, free_INVALID_POINTER_SIZE_GT_0) { umf_result_t umf_result = umfMemoryProviderFree(provider.get(), INVALID_PTR, page_plus_64); ASSERT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); } -TEST_P(umfProviderTest, purge_lazy_INVALID_POINTER) { +TEST_P(FileProviderParamsDefault, purge_lazy_INVALID_POINTER) { umf_result_t umf_result = umfMemoryProviderPurgeLazy(provider.get(), INVALID_PTR, 1); ASSERT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); } -TEST_P(umfProviderTest, purge_force_INVALID_POINTER) { +TEST_P(FileProviderParamsDefault, purge_force_INVALID_POINTER) { umf_result_t umf_result = umfMemoryProviderPurgeForce(provider.get(), INVALID_PTR, 1); ASSERT_EQ(umf_result, UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC); @@ -297,7 +342,11 @@ TEST_P(umfProviderTest, purge_force_INVALID_POINTER) { // IPC tests -TEST_P(umfProviderTest, IPC_base_success_test) { +INSTANTIATE_TEST_SUITE_P(fileProviderTest, FileProviderParamsShared, + ::testing::Values(providerCreateExtParams{ + umfFileMemoryProviderOps(), &file_params_shared})); + +TEST_P(FileProviderParamsShared, IPC_base_success_test) { umf_result_t umf_result; void *ptr = nullptr; size_t size = page_size; @@ -338,7 +387,7 @@ TEST_P(umfProviderTest, IPC_base_success_test) { ASSERT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); } -TEST_P(umfProviderTest, IPC_file_not_exist) { +TEST_P(FileProviderParamsShared, IPC_file_not_exist) { umf_result_t umf_result; void *ptr = nullptr; size_t size = page_size; From 7698d75e600303981ae3774fd883de467879908c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Plewa?= Date: Thu, 26 Sep 2024 16:03:49 +0200 Subject: [PATCH 133/352] add example how to use filterById --- examples/memspace_numa/memspace_numa.c | 133 +++++++++++++++++++------ 1 file changed, 105 insertions(+), 28 deletions(-) diff --git a/examples/memspace_numa/memspace_numa.c b/examples/memspace_numa/memspace_numa.c index 8116825ed..e2c460f70 100644 --- a/examples/memspace_numa/memspace_numa.c +++ b/examples/memspace_numa/memspace_numa.c @@ -18,8 +18,9 @@ #include "utils_examples.h" // Function to create a memory provider which allocates memory from the specified NUMA node -int createMemoryProvider(umf_memory_provider_handle_t *hProvider, - unsigned numa) { +// by using umfMemspaceCreateFromNumaArray +int createMemoryProviderFromArray(umf_memory_provider_handle_t *hProvider, + unsigned numa) { int ret = 0; umf_result_t result; umf_memspace_handle_t hMemspace = NULL; @@ -29,9 +30,8 @@ int createMemoryProvider(umf_memory_provider_handle_t *hProvider, // In this example, we create a memspace that contains single numa node; result = umfMemspaceCreateFromNumaArray(&numa, 1, &hMemspace); if (result != UMF_RESULT_SUCCESS) { - ret = -1; - fprintf(stderr, "umfMemspaceCreateFromNumaArray failed.\n"); - goto error_memspace; + fprintf(stderr, "umfMemspaceCreateFromNumaArray() failed.\n"); + return -1; } // Create a mempolicy - mempolicy defines how we want to use memory from memspace. @@ -39,53 +39,90 @@ int createMemoryProvider(umf_memory_provider_handle_t *hProvider, result = umfMempolicyCreate(UMF_MEMPOLICY_BIND, &hPolicy); if (result != UMF_RESULT_SUCCESS) { ret = -1; - fprintf(stderr, "umfMempolicyCreate failed.\n"); - goto error_mempolicy; + fprintf(stderr, "umfMempolicyCreate failed().\n"); + goto error_memspace; } // Create a memory provider using the memory space and memory policy result = umfMemoryProviderCreateFromMemspace(hMemspace, hPolicy, hProvider); if (result != UMF_RESULT_SUCCESS) { ret = -1; - fprintf(stderr, "umfMemoryProviderCreateFromMemspace failed.\n"); - goto error_provider; + fprintf(stderr, "umfMemoryProviderCreateFromMemspace failed().\n"); + goto error_mempolicy; } // After creating the memory provider, we can destroy the memspace and mempolicy -error_provider: - umfMempolicyDestroy(hPolicy); error_mempolicy: - umfMemspaceDestroy(hMemspace); + umfMempolicyDestroy(hPolicy); error_memspace: + umfMemspaceDestroy(hMemspace); return ret; } -int main(void) { - umf_memory_provider_handle_t hProvider = NULL; - umf_result_t ret; +// Function to create a memory provider which allocates memory from the specified NUMA node +// by using filter function. +int createMemoryProviderByFilter(umf_memory_provider_handle_t *hProvider, + unsigned numa) { + int ret = 0; + umf_result_t result; + umf_memspace_handle_t hMemspace = NULL; + umf_mempolicy_handle_t hPolicy = NULL; - // Check if NUMA is available - if (numa_available() < 0) { - fprintf(stderr, "NUMA is not available on this system.\n"); - return TEST_SKIP_ERROR_CODE; + umf_const_memspace_handle_t hostAll = umfMemspaceHostAllGet(); + if (!hostAll) { + fprintf(stderr, "umfMemspaceHostAllGet() failed\n"); + return -1; } - // Create the memory provider that allocates memory from the specified NUMA node - // In this example, we allocate memory from the NUMA node 0 - ret = createMemoryProvider(&hProvider, 0); - if (ret != UMF_RESULT_SUCCESS) { + // umfMemspaceHostAllGet() return immutable memspace, so we need to create a mutable copy + result = umfMemspaceClone(hostAll, &hMemspace); + if (result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "umfMempolicyClone() failed.\n"); return -1; } + // Filter the memspace to contain only the specified numa node + result = umfMemspaceFilterById(hMemspace, &numa, 1); + if (result != UMF_RESULT_SUCCESS) { + ret = -1; + fprintf(stderr, "umfMemspaceFilterById() failed.\n"); + goto error_memspace; + } + + // Create a mempolicy - mempolicy defines how we want to use memory from memspace. + // In this example, we want to bind memory to the specified numa node. + result = umfMempolicyCreate(UMF_MEMPOLICY_BIND, &hPolicy); + if (result != UMF_RESULT_SUCCESS) { + ret = -1; + fprintf(stderr, "umfMempolicyCreate() failed.\n"); + goto error_memspace; + } + // Create a memory provider using the memory space and memory policy + result = umfMemoryProviderCreateFromMemspace(hMemspace, hPolicy, hProvider); + if (result != UMF_RESULT_SUCCESS) { + ret = -1; + fprintf(stderr, "umfMemoryProviderCreateFromMemspace() failed.\n"); + goto error_mempolicy; + } + + // After creating the memory provider, we can destroy the memspace and mempolicy +error_mempolicy: + umfMempolicyDestroy(hPolicy); +error_memspace: + umfMemspaceDestroy(hMemspace); + return ret; +} + +int use_memory_provider(umf_memory_provider_handle_t hProvider) { // Allocate memory from the memory provider void *ptr = NULL; size_t size = 1024; size_t alignment = 64; - ret = umfMemoryProviderAlloc(hProvider, size, alignment, &ptr); + umf_result_t ret = umfMemoryProviderAlloc(hProvider, size, alignment, &ptr); if (ret != UMF_RESULT_SUCCESS) { fprintf(stderr, "umfMemoryProviderAlloc failed.\n"); - goto error_alloc; + return 1; } // Use the allocated memory (ptr) here @@ -95,14 +132,54 @@ int main(void) { int nodeId; int retm = get_mempolicy(&nodeId, NULL, 0, ptr, MPOL_F_ADDR | MPOL_F_NODE); if (retm != 0) { + umfMemoryProviderFree(hProvider, ptr, size); fprintf(stderr, "get_mempolicy failed.\n"); - goto error_alloc; + return 1; } printf("Allocated memory at %p from numa_node %d\n", ptr, nodeId); // Free the allocated memory umfMemoryProviderFree(hProvider, ptr, size); -error_alloc: + + return 0; +} + +int main(void) { + umf_memory_provider_handle_t hProvider = NULL; + umf_result_t ret; + + // Check if NUMA is available + if (numa_available() < 0) { + fprintf(stderr, "NUMA is not available on this system.\n"); + return TEST_SKIP_ERROR_CODE; + } + + // Create the memory provider that allocates memory from the specified NUMA node + // In this example, we allocate memory from the NUMA node 0 + ret = createMemoryProviderFromArray(&hProvider, 0); + if (ret != UMF_RESULT_SUCCESS) { + return -1; + } + + if (use_memory_provider(hProvider)) { + goto error; + } + + umfMemoryProviderDestroy(hProvider); + + // We can achieve the same result by using filter functions + ret = createMemoryProviderByFilter(&hProvider, 0); + if (ret != UMF_RESULT_SUCCESS) { + return -1; + } + + if (use_memory_provider(hProvider)) { + goto error; + } + + umfMemoryProviderDestroy(hProvider); + return 0; +error: umfMemoryProviderDestroy(hProvider); - return ret == UMF_RESULT_SUCCESS ? 0 : 1; + return 1; } From 2b53b9b3691cf86dbdb0064a3db7b3d2cdae57a4 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Fri, 27 Sep 2024 13:36:23 +0200 Subject: [PATCH 134/352] Fix setting size of DEVDAX from environment Fix setting size of DEVDAX from environment. It fixes the Coverity issue no. 469373 and 469374. Signed-off-by: Lukasz Dorau --- test/ipc_devdax_prov_consumer.c | 4 +--- test/ipc_devdax_prov_producer.c | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/test/ipc_devdax_prov_consumer.c b/test/ipc_devdax_prov_consumer.c index 05478e436..f1d576500 100644 --- a/test/ipc_devdax_prov_consumer.c +++ b/test/ipc_devdax_prov_consumer.c @@ -34,9 +34,7 @@ int main(int argc, char *argv[]) { } umf_devdax_memory_provider_params_t devdax_params = - umfDevDaxMemoryProviderParamsDefault( - getenv("UMF_TESTS_DEVDAX_PATH"), - atol(getenv("UMF_TESTS_DEVDAX_SIZE"))); + umfDevDaxMemoryProviderParamsDefault(path, atol(size)); return run_consumer(port, umfDevDaxMemoryProviderOps(), &devdax_params, memcopy, NULL); diff --git a/test/ipc_devdax_prov_producer.c b/test/ipc_devdax_prov_producer.c index 820d0fba9..c462706db 100644 --- a/test/ipc_devdax_prov_producer.c +++ b/test/ipc_devdax_prov_producer.c @@ -34,9 +34,7 @@ int main(int argc, char *argv[]) { } umf_devdax_memory_provider_params_t devdax_params = - umfDevDaxMemoryProviderParamsDefault( - getenv("UMF_TESTS_DEVDAX_PATH"), - atol(getenv("UMF_TESTS_DEVDAX_SIZE"))); + umfDevDaxMemoryProviderParamsDefault(path, atol(size)); return run_producer(port, umfDevDaxMemoryProviderOps(), &devdax_params, memcopy, NULL); From e3b3e9ed17cea6c1d5adbe28ffe86620138a811b Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Fri, 27 Sep 2024 20:30:43 +0200 Subject: [PATCH 135/352] Use UMF_MEM_MAP_SYNC for FSDAX in the FSDAX IPC example Signed-off-by: Lukasz Dorau --- test/ipc_file_prov_consumer.c | 20 ++++++++++++++++++-- test/ipc_file_prov_fsdax.sh | 4 ++-- test/ipc_file_prov_producer.c | 20 ++++++++++++++++++-- 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/test/ipc_file_prov_consumer.c b/test/ipc_file_prov_consumer.c index 834fe1054..d1e622efe 100644 --- a/test/ipc_file_prov_consumer.c +++ b/test/ipc_file_prov_consumer.c @@ -5,8 +5,11 @@ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ +#include #include #include +#include +#include #include @@ -15,17 +18,30 @@ int main(int argc, char *argv[]) { if (argc < 3) { - fprintf(stderr, "usage: %s \n", argv[0]); + fprintf(stderr, "usage: %s \n", argv[0]); + fprintf(stderr, " should be \"FSDAX\" or \"fsdax\" if " + " is located on FSDAX \n"); return -1; } int port = atoi(argv[1]); char *file_name = argv[2]; + bool is_fsdax = false; + + if (argc >= 4) { + if (strncasecmp(argv[3], "FSDAX", strlen("FSDAX")) == 0) { + is_fsdax = true; + } + } umf_file_memory_provider_params_t file_params; file_params = umfFileMemoryProviderParamsDefault(file_name); - file_params.visibility = UMF_MEM_MAP_SHARED; + if (is_fsdax) { + file_params.visibility = UMF_MEM_MAP_SYNC; + } else { + file_params.visibility = UMF_MEM_MAP_SHARED; + } return run_consumer(port, umfFileMemoryProviderOps(), &file_params, memcopy, NULL); diff --git a/test/ipc_file_prov_fsdax.sh b/test/ipc_file_prov_fsdax.sh index f2c799f11..56c540a65 100755 --- a/test/ipc_file_prov_fsdax.sh +++ b/test/ipc_file_prov_fsdax.sh @@ -25,13 +25,13 @@ UMF_LOG_VAL="level:debug;flush:debug;output:stderr;pid:yes" rm -f ${FILE_NAME} echo "Starting ipc_file_prov_fsdax CONSUMER on port $PORT ..." -UMF_LOG=$UMF_LOG_VAL ./umf_test-ipc_file_prov_consumer $PORT $FILE_NAME & +UMF_LOG=$UMF_LOG_VAL ./umf_test-ipc_file_prov_consumer $PORT $FILE_NAME "FSDAX" & echo "Waiting 1 sec ..." sleep 1 echo "Starting ipc_file_prov_fsdax PRODUCER on port $PORT ..." -UMF_LOG=$UMF_LOG_VAL ./umf_test-ipc_file_prov_producer $PORT $FILE_NAME +UMF_LOG=$UMF_LOG_VAL ./umf_test-ipc_file_prov_producer $PORT $FILE_NAME "FSDAX" # remove the SHM file rm -f ${FILE_NAME} diff --git a/test/ipc_file_prov_producer.c b/test/ipc_file_prov_producer.c index 783cff31d..1e7052efb 100644 --- a/test/ipc_file_prov_producer.c +++ b/test/ipc_file_prov_producer.c @@ -5,8 +5,11 @@ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ +#include #include #include +#include +#include #include @@ -15,17 +18,30 @@ int main(int argc, char *argv[]) { if (argc < 3) { - fprintf(stderr, "usage: %s \n", argv[0]); + fprintf(stderr, "usage: %s \n", argv[0]); + fprintf(stderr, " should be \"FSDAX\" or \"fsdax\" if " + " is located on FSDAX \n"); return -1; } int port = atoi(argv[1]); char *file_name = argv[2]; + bool is_fsdax = false; + + if (argc >= 4) { + if (strncasecmp(argv[3], "FSDAX", strlen("FSDAX")) == 0) { + is_fsdax = true; + } + } umf_file_memory_provider_params_t file_params; file_params = umfFileMemoryProviderParamsDefault(file_name); - file_params.visibility = UMF_MEM_MAP_SHARED; + if (is_fsdax) { + file_params.visibility = UMF_MEM_MAP_SYNC; + } else { + file_params.visibility = UMF_MEM_MAP_SHARED; + } return run_producer(port, umfFileMemoryProviderOps(), &file_params, memcopy, NULL); From 7e549a6f07a7b6164eec93f4e6e845edc6b753b2 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 30 Sep 2024 09:48:35 +0200 Subject: [PATCH 136/352] Use the UMF base allocator in RAVL instead of the glibc's one Signed-off-by: Lukasz Dorau --- src/ravl/ravl.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/ravl/ravl.c b/src/ravl/ravl.c index 0bd4d59bc..dd6c17b03 100644 --- a/src/ravl/ravl.c +++ b/src/ravl/ravl.c @@ -16,6 +16,7 @@ #include "../src/utils/utils_common.h" #include "../src/utils/utils_concurrency.h" #include "assert.h" +#include "base_alloc_global.h" #include #include @@ -51,7 +52,7 @@ struct ravl { * ravl_new -- creates a new ravl tree instance */ struct ravl *ravl_new_sized(ravl_compare *compare, size_t data_size) { - struct ravl *r = malloc(sizeof(*r)); + struct ravl *r = umf_ba_global_alloc(sizeof(*r)); if (r == NULL) { return NULL; } @@ -87,7 +88,7 @@ static void ravl_foreach_node(struct ravl_node *n, ravl_cb cb, void *arg, ravl_foreach_node(n->slots[RAVL_RIGHT], cb, arg, free_node); if (free_node) { - free(n); + umf_ba_global_free(n); } } @@ -104,7 +105,7 @@ void ravl_clear(struct ravl *ravl) { */ void ravl_delete_cb(struct ravl *ravl, ravl_cb cb, void *arg) { ravl_foreach_node(ravl->root, cb, arg, 1); - free(ravl); + umf_ba_global_free(ravl); } /* @@ -149,7 +150,7 @@ static void ravl_node_copy_constructor(void *data, size_t data_size, */ static struct ravl_node *ravl_new_node(struct ravl *ravl, ravl_constr constr, const void *arg) { - struct ravl_node *n = malloc(sizeof(*n) + ravl->data_size); + struct ravl_node *n = umf_ba_global_alloc(sizeof(*n) + ravl->data_size); if (n == NULL) { return NULL; } @@ -383,7 +384,7 @@ int ravl_emplace(struct ravl *ravl, ravl_constr constr, const void *arg) { error_duplicate: errno = EEXIST; - free(n); + umf_ba_global_free(n); return -1; } @@ -516,7 +517,7 @@ void ravl_remove(struct ravl *ravl, struct ravl_node *n) { } *ravl_node_ref(ravl, n) = r; - free(n); + umf_ba_global_free(n); } } From 960d708cf4ce87d49530b1c02b3b47f7a7e856ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Thu, 12 Sep 2024 18:17:12 +0200 Subject: [PATCH 137/352] [CI] Add initial workflow for measuring performance --- .github/workflows/performance.yml | 115 ++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 .github/workflows/performance.yml diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml new file mode 100644 index 000000000..6057df5f0 --- /dev/null +++ b/.github/workflows/performance.yml @@ -0,0 +1,115 @@ +name: Performance + +on: + # Can be triggered via manual "dispatch" (from workflow view in GitHub Actions tab) + workflow_dispatch: + inputs: + pr_no: + description: PR number (if 0, it'll run on the main) + type: number + required: true + +permissions: + contents: read + pull-requests: write + +env: + BUILD_DIR : "${{github.workspace}}/build" + +jobs: + perf-l0: + name: Build UMF and run performance tests + runs-on: "L0_PERF" + + steps: + # Workspace on self-hosted runners is not cleaned automatically. + # We have to delete the files created outside of using actions. + - name: Cleanup self-hosted workspace + if: always() + run: | + ls -la ./ + rm -rf ./* || true + + - name: Add comment to PR + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + if: ${{ always() && inputs.pr_no != 0 }} + with: + script: | + const pr_no = '${{ inputs.pr_no }}'; + const provider = 'LEVEL_ZERO'; + const url = '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'; + const body = `Performance workflow for ${provider}_PROVIDER run:\n${url}`; + + github.rest.issues.createComment({ + issue_number: pr_no, + owner: context.repo.owner, + repo: context.repo.repo, + body: body + }) + + - name: Checkout UMF + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - name: Get information about platform + run: .github/scripts/get_system_info.sh + + # We need to fetch special ref for proper PR's merge commit. Note, this ref may be absent if the PR is already merged. + - name: Fetch PR's merge commit + if: ${{ inputs.pr_no != 0 }} + working-directory: ${{github.workspace}} + env: + PR_NO: ${{ inputs.pr_no }} + run: | + git fetch -- https://github.com/${{github.repository}} +refs/pull/${PR_NO}/*:refs/remotes/origin/pr/${PR_NO}/* + git checkout origin/pr/${PR_NO}/merge + git rev-parse origin/pr/${PR_NO}/merge + + - name: Configure build + run: > + cmake + -B ${{env.BUILD_DIR}} + -DCMAKE_BUILD_TYPE=Release + -DUMF_BUILD_SHARED_LIBRARY=ON + -DUMF_BUILD_BENCHMARKS=ON + -DUMF_BUILD_BENCHMARKS_MT=ON + -DUMF_BUILD_TESTS=OFF + -DUMF_FORMAT_CODE_STYLE=OFF + -DUMF_DEVELOPER_MODE=OFF + -DUMF_BUILD_LEVEL_ZERO_PROVIDER=ON + -DUMF_BUILD_CUDA_PROVIDER=ON + -DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON + -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON + + - name: Build + run: cmake --build ${{env.BUILD_DIR}} -j $(nproc) + + - name: Run benchmarks + working-directory: ${{env.BUILD_DIR}} + id: benchmarks + run: numactl -N 1 ctest -V --test-dir benchmark -C Release + + - name: Add comment to PR + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + if: ${{ always() && inputs.pr_no != 0 }} + with: + script: | + let markdown = "" + try { + const fs = require('fs'); + markdown = fs.readFileSync('umf_perf_results.md', 'utf8'); + } catch(err) { + } + + const pr_no = '${{ inputs.pr_no }}'; + const provider = 'LEVEL_ZERO'; + const url = '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'; + const test_status = '${{ steps.benchmarks.outcome }}'; + const job_status = '${{ job.status }}'; + const body = `Performance workflow for ${provider}_PROVIDER run:\n${url}\nJob status: ${job_status}. Test status: ${test_status}.\n ${markdown}`; + + github.rest.issues.createComment({ + issue_number: pr_no, + owner: context.repo.owner, + repo: context.repo.repo, + body: body + }) From df7650b61155cc446cfda3ec1216ebea85fa850a Mon Sep 17 00:00:00 2001 From: Igor Chorazewicz Date: Tue, 1 Oct 2024 00:40:37 +0200 Subject: [PATCH 138/352] Fix handling resident_device_handles in L0 provider handles were being ignored in the initialize function. --- benchmark/ubench.c | 2 +- examples/ipc_level_zero/ipc_level_zero.c | 2 +- .../level_zero_shared_memory.c | 2 +- src/provider/provider_level_zero.c | 22 +++++++++++++++++++ 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/benchmark/ubench.c b/benchmark/ubench.c index 04695a0f4..15890d4e9 100644 --- a/benchmark/ubench.c +++ b/benchmark/ubench.c @@ -430,7 +430,7 @@ int create_level_zero_params(level_zero_memory_provider_params_t *params) { UBENCH_EX(ipc, disjoint_pool_with_level_zero_provider) { const size_t BUFFER_SIZE = 100; const size_t N_BUFFERS = 1000; - level_zero_memory_provider_params_t level_zero_params; + level_zero_memory_provider_params_t level_zero_params = {0}; int ret = create_level_zero_params(&level_zero_params); if (ret != 0) { diff --git a/examples/ipc_level_zero/ipc_level_zero.c b/examples/ipc_level_zero/ipc_level_zero.c index e7991fce6..9a6b4177b 100644 --- a/examples/ipc_level_zero/ipc_level_zero.c +++ b/examples/ipc_level_zero/ipc_level_zero.c @@ -20,7 +20,7 @@ int create_level_zero_pool(ze_context_handle_t context, ze_device_handle_t device, umf_memory_pool_handle_t *pool) { // setup params - level_zero_memory_provider_params_t params; + level_zero_memory_provider_params_t params = {0}; params.level_zero_context_handle = context; params.level_zero_device_handle = device; params.memory_type = UMF_MEMORY_TYPE_DEVICE; diff --git a/examples/level_zero_shared_memory/level_zero_shared_memory.c b/examples/level_zero_shared_memory/level_zero_shared_memory.c index 8d34e0f59..06413a018 100644 --- a/examples/level_zero_shared_memory/level_zero_shared_memory.c +++ b/examples/level_zero_shared_memory/level_zero_shared_memory.c @@ -49,7 +49,7 @@ int main(void) { // Setup parameters for the Level Zero memory provider. It will be used for // allocating memory from Level Zero devices. - level_zero_memory_provider_params_t ze_memory_provider_params; + level_zero_memory_provider_params_t ze_memory_provider_params = {0}; ze_memory_provider_params.level_zero_context_handle = hContext; ze_memory_provider_params.level_zero_device_handle = hDevice; // Set the memory type to shared to allow the memory to be accessed on both diff --git a/src/provider/provider_level_zero.c b/src/provider/provider_level_zero.c index d9c4afe1f..d940d8ded 100644 --- a/src/provider/provider_level_zero.c +++ b/src/provider/provider_level_zero.c @@ -177,6 +177,25 @@ static umf_result_t ze_memory_provider_initialize(void *params, sizeof(ze_provider->device_properties)); } + if (ze_params->resident_device_count) { + ze_provider->resident_device_handles = umf_ba_global_alloc( + sizeof(ze_device_handle_t) * ze_params->resident_device_count); + if (!ze_provider->resident_device_handles) { + umf_ba_global_free(ze_provider); + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + ze_provider->resident_device_count = ze_params->resident_device_count; + + for (uint32_t i = 0; i < ze_provider->resident_device_count; i++) { + ze_provider->resident_device_handles[i] = + ze_params->resident_device_handles[i]; + } + } else { + ze_provider->resident_device_handles = NULL; + ze_provider->resident_device_count = 0; + } + *provider = ze_provider; return UMF_RESULT_SUCCESS; @@ -188,6 +207,9 @@ static void ze_memory_provider_finalize(void *provider) { return; } + ze_memory_provider_t *ze_provider = (ze_memory_provider_t *)provider; + umf_ba_global_free(ze_provider->resident_device_handles); + umf_ba_global_free(provider); } From 2766a21681c1e395d4bcd4c0f178a2627cf56d23 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 2 Oct 2024 11:02:12 +0200 Subject: [PATCH 139/352] Clear tracker for the current pool on destroy Clear tracker for the current pool on destroy. Do not print error messages if provider does not support the free() operation. Signed-off-by: Lukasz Dorau --- src/memory_pool.c | 8 +++- src/provider/provider_tracking.c | 76 ++++++++++++++++++++------------ src/provider/provider_tracking.h | 3 +- test/memoryPoolAPI.cpp | 6 ++- test/pools/disjoint_pool.cpp | 5 ++- 5 files changed, 64 insertions(+), 34 deletions(-) diff --git a/src/memory_pool.c b/src/memory_pool.c index 7d65acf36..f6ae8841f 100644 --- a/src/memory_pool.c +++ b/src/memory_pool.c @@ -41,8 +41,12 @@ static umf_result_t umfPoolCreateInternal(const umf_memory_pool_ops_t *ops, assert(ops->version == UMF_VERSION_CURRENT); if (!(flags & UMF_POOL_CREATE_FLAG_DISABLE_TRACKING)) { - // wrap provider with memory tracking provider - ret = umfTrackingMemoryProviderCreate(provider, pool, &pool->provider); + // Wrap provider with memory tracking provider. + // Check if the provider supports the free() operation. + bool upstreamDoesNotFree = (umfMemoryProviderFree(provider, NULL, 0) == + UMF_RESULT_ERROR_NOT_SUPPORTED); + ret = umfTrackingMemoryProviderCreate(provider, pool, &pool->provider, + upstreamDoesNotFree); if (ret != UMF_RESULT_SUCCESS) { goto err_provider_create; } diff --git a/src/provider/provider_tracking.c b/src/provider/provider_tracking.c index 5e1db9d14..83aa5c335 100644 --- a/src/provider/provider_tracking.c +++ b/src/provider/provider_tracking.c @@ -141,6 +141,9 @@ typedef struct umf_tracking_memory_provider_t { umf_memory_tracker_handle_t hTracker; umf_memory_pool_handle_t pool; critnib *ipcCache; + + // the upstream provider does not support the free() operation + bool upstreamDoesNotFree; } umf_tracking_memory_provider_t; typedef struct umf_tracking_memory_provider_t umf_tracking_memory_provider_t; @@ -392,9 +395,11 @@ static umf_result_t trackingInitialize(void *params, void **ret) { return UMF_RESULT_SUCCESS; } -#ifndef NDEBUG -static void check_if_tracker_is_empty(umf_memory_tracker_handle_t hTracker, - umf_memory_pool_handle_t pool) { +// TODO clearing the tracker is a temporary solution and should be removed. +// The tracker should be cleared using the provider's free() operation. +static void clear_tracker_for_the_pool(umf_memory_tracker_handle_t hTracker, + umf_memory_pool_handle_t pool, + bool upstreamDoesNotFree) { uintptr_t rkey; void *rvalue; size_t n_items = 0; @@ -403,39 +408,55 @@ static void check_if_tracker_is_empty(umf_memory_tracker_handle_t hTracker, while (1 == critnib_find((critnib *)hTracker->map, last_key, FIND_G, &rkey, &rvalue)) { tracker_value_t *value = (tracker_value_t *)rvalue; - if (value->pool == pool || pool == NULL) { - n_items++; + if (value->pool != pool && pool != NULL) { + last_key = rkey; + continue; } + n_items++; + + void *removed_value = critnib_remove(hTracker->map, rkey); + assert(removed_value == rvalue); + umf_ba_free(hTracker->tracker_allocator, removed_value); + last_key = rkey; } - if (n_items) { - // Do not assert if we are running in the proxy library, - // because it may need those resources till - // the very end of exiting the application. - if (!utils_is_running_in_proxy_lib()) { - if (pool) { - LOG_ERR("tracking provider of pool %p is not empty! " - "(%zu items left)", - (void *)pool, n_items); - } else { - LOG_ERR("tracking provider is not empty! (%zu items " - "left)", - n_items); - } +#ifndef NDEBUG + // print error messages only if provider supports the free() operation + if (n_items && !upstreamDoesNotFree) { + if (pool) { + LOG_ERR( + "tracking provider of pool %p is not empty! (%zu items left)", + (void *)pool, n_items); + } else { + LOG_ERR("tracking provider is not empty! (%zu items left)", + n_items); } } +#else /* DEBUG */ + (void)upstreamDoesNotFree; // unused in DEBUG build + (void)n_items; // unused in DEBUG build +#endif /* DEBUG */ +} + +static void clear_tracker(umf_memory_tracker_handle_t hTracker) { + clear_tracker_for_the_pool(hTracker, NULL, false); } -#endif /* NDEBUG */ static void trackingFinalize(void *provider) { umf_tracking_memory_provider_t *p = (umf_tracking_memory_provider_t *)provider; + critnib_delete(p->ipcCache); -#ifndef NDEBUG - check_if_tracker_is_empty(p->hTracker, p->pool); -#endif /* NDEBUG */ + + // Do not clear the tracker if we are running in the proxy library, + // because it may need those resources till + // the very end of exiting the application. + if (!utils_is_running_in_proxy_lib()) { + clear_tracker_for_the_pool(p->hTracker, p->pool, + p->upstreamDoesNotFree); + } umf_ba_global_free(provider); } @@ -661,10 +682,11 @@ umf_memory_provider_ops_t UMF_TRACKING_MEMORY_PROVIDER_OPS = { umf_result_t umfTrackingMemoryProviderCreate( umf_memory_provider_handle_t hUpstream, umf_memory_pool_handle_t hPool, - umf_memory_provider_handle_t *hTrackingProvider) { + umf_memory_provider_handle_t *hTrackingProvider, bool upstreamDoesNotFree) { umf_tracking_memory_provider_t params; params.hUpstream = hUpstream; + params.upstreamDoesNotFree = upstreamDoesNotFree; params.hTracker = TRACKER; if (!params.hTracker) { LOG_ERR("failed, TRACKER is NULL"); @@ -739,16 +761,14 @@ void umfMemoryTrackerDestroy(umf_memory_tracker_handle_t handle) { return; } - // Do not destroy if we are running in the proxy library, + // Do not destroy the tracket if we are running in the proxy library, // because it may need those resources till // the very end of exiting the application. if (utils_is_running_in_proxy_lib()) { return; } -#ifndef NDEBUG - check_if_tracker_is_empty(handle, NULL); -#endif /* NDEBUG */ + clear_tracker(handle); // We have to zero all inner pointers, // because the tracker handle can be copied diff --git a/src/provider/provider_tracking.h b/src/provider/provider_tracking.h index f020c3da8..9444ee475 100644 --- a/src/provider/provider_tracking.h +++ b/src/provider/provider_tracking.h @@ -11,6 +11,7 @@ #define UMF_MEMORY_TRACKER_INTERNAL_H 1 #include +#include #include #include @@ -53,7 +54,7 @@ umf_result_t umfMemoryTrackerGetAllocInfo(const void *ptr, // forwards all requests to hUpstream memory Provider. hUpstream lifetime should be managed by the user of this function. umf_result_t umfTrackingMemoryProviderCreate( umf_memory_provider_handle_t hUpstream, umf_memory_pool_handle_t hPool, - umf_memory_provider_handle_t *hTrackingProvider); + umf_memory_provider_handle_t *hTrackingProvider, bool upstreamDoesNotFree); void umfTrackingMemoryProviderGetUpstreamProvider( umf_memory_provider_handle_t hTrackingProvider, diff --git a/test/memoryPoolAPI.cpp b/test/memoryPoolAPI.cpp index 0fb2a4422..96fd634c6 100644 --- a/test/memoryPoolAPI.cpp +++ b/test/memoryPoolAPI.cpp @@ -139,7 +139,8 @@ TEST_P(umfPoolWithCreateFlagsTest, memoryPoolWithCustomProvider) { } TEST_F(test, retrieveMemoryProvider) { - umf_memory_provider_handle_t provider = (umf_memory_provider_handle_t)0x1; + auto nullProvider = umf_test::wrapProviderUnique(nullProviderCreate()); + umf_memory_provider_handle_t provider = nullProvider.get(); auto pool = wrapPoolUnique(createPoolChecked(umfProxyPoolOps(), provider, nullptr)); @@ -258,7 +259,8 @@ TEST_P(poolInitializeTest, errorPropagation) { } TEST_F(test, retrieveMemoryProvidersError) { - umf_memory_provider_handle_t provider = (umf_memory_provider_handle_t)0x1; + auto nullProvider = umf_test::wrapProviderUnique(nullProviderCreate()); + umf_memory_provider_handle_t provider = nullProvider.get(); auto pool = wrapPoolUnique(createPoolChecked(umfProxyPoolOps(), provider, nullptr)); diff --git a/test/pools/disjoint_pool.cpp b/test/pools/disjoint_pool.cpp index d7612f4d5..2f5d61142 100644 --- a/test/pools/disjoint_pool.cpp +++ b/test/pools/disjoint_pool.cpp @@ -82,7 +82,10 @@ TEST_F(test, sharedLimits) { } umf_result_t free(void *ptr, [[maybe_unused]] size_t size) noexcept { ::free(ptr); - numFrees++; + // umfMemoryProviderFree(provider, NULL, 0) is called inside umfPoolCreateInternal() + if (ptr != NULL && size != 0) { + numFrees++; + } return UMF_RESULT_SUCCESS; } }; From 7ac8cfb83f6ca8437e472937791c76cd7c87f36b Mon Sep 17 00:00:00 2001 From: Gergely Meszaros Date: Wed, 25 Sep 2024 08:32:38 -0700 Subject: [PATCH 140/352] Wrap linker flags on Windows for IntelLLVM The Intel C++ compiler requires linker flags to be wrapped, because CMake passes them through the compiler driver. Prefix Linker options with `LINKER:`. CMake will transform it to the appropriate flag for the compiler driver: (Nothing for MSVC, clang-cl and /Qoption,link for ICX), so this will work for the other compilers too, and for earlier versions of CMake. Fixes: #757 Signed-off-by: Gergely Meszaros --- cmake/helpers.cmake | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cmake/helpers.cmake b/cmake/helpers.cmake index a09fe283f..75bd531d2 100644 --- a/cmake/helpers.cmake +++ b/cmake/helpers.cmake @@ -295,17 +295,17 @@ function(add_umf_target_link_options name) target_link_options( ${name} PRIVATE - /DYNAMICBASE - /HIGHENTROPYVA + LINKER:/DYNAMICBASE + LINKER:/HIGHENTROPYVA $<$:/DEPENDENTLOADFLAG:0x2000> $<$:/DEPENDENTLOADFLAG:0x2000> - /NXCOMPAT) + LINKER:/NXCOMPAT) endif() endfunction() function(add_umf_target_exec_options name) if(MSVC) - target_link_options(${name} PRIVATE /ALLOWISOLATION) + target_link_options(${name} PRIVATE LINKER:/ALLOWISOLATION) endif() endfunction() @@ -362,7 +362,7 @@ function(add_umf_library) if(WINDOWS) target_link_options(${ARG_NAME} PRIVATE - /DEF:${ARG_WINDOWS_DEF_FILE}) + LINKER:/DEF:${ARG_WINDOWS_DEF_FILE}) elseif(LINUX) target_link_options(${ARG_NAME} PRIVATE "-Wl,--version-script=${ARG_LINUX_MAP_FILE}") From adb3f1b1a2297907fc111d77aad19ae43a212c6c Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 2 Oct 2024 17:19:16 +0200 Subject: [PATCH 141/352] Fix one typo in a comment Signed-off-by: Lukasz Dorau --- src/provider/provider_tracking.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/provider/provider_tracking.c b/src/provider/provider_tracking.c index 83aa5c335..fc91761a4 100644 --- a/src/provider/provider_tracking.c +++ b/src/provider/provider_tracking.c @@ -761,7 +761,7 @@ void umfMemoryTrackerDestroy(umf_memory_tracker_handle_t handle) { return; } - // Do not destroy the tracket if we are running in the proxy library, + // Do not destroy the tracker if we are running in the proxy library, // because it may need those resources till // the very end of exiting the application. if (utils_is_running_in_proxy_lib()) { From bfe5cbd8ada8d99f876514d6acab9c8cd7c5a396 Mon Sep 17 00:00:00 2001 From: "Kenneth Benzie (Benie)" Date: Thu, 3 Oct 2024 14:04:34 +0100 Subject: [PATCH 142/352] clang-cl.exe does not support /analyze flag Disable setting the `/analyze` flag on Windows if the compiler ID does not equal MSVC, this fixes builds using the `clang-cl.exe` frontend which does not support this flag. --- cmake/helpers.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/helpers.cmake b/cmake/helpers.cmake index a09fe283f..6628fcee4 100644 --- a/cmake/helpers.cmake +++ b/cmake/helpers.cmake @@ -258,7 +258,7 @@ function(add_umf_target_compile_options name) ${name} PRIVATE /MD$<$:d> $<$:/sdl> - /analyze + $<$:/analyze> /DYNAMICBASE /W4 /Gy From b0bfbb7e92b76cc56c3bcd91c7ac063467136376 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Thu, 3 Oct 2024 15:28:35 +0200 Subject: [PATCH 143/352] Move free() to optional (ext) provider ops Signed-off-by: Lukasz Dorau --- .../custom_file_provider.c | 2 +- include/umf/memory_provider_ops.h | 18 ++++++++-------- src/cpp_helpers.hpp | 2 +- src/memory_provider.c | 15 +++++++++++-- src/provider/provider_cuda.c | 2 +- src/provider/provider_devdax_memory.c | 10 --------- src/provider/provider_file_memory.c | 10 --------- src/provider/provider_level_zero.c | 2 +- src/provider/provider_os_memory.c | 2 +- src/provider/provider_tracking.c | 2 +- test/common/provider_null.c | 2 +- test/common/provider_trace.c | 2 +- test/memoryProviderAPI.cpp | 21 ++++++++++++------- 13 files changed, 43 insertions(+), 47 deletions(-) diff --git a/examples/custom_file_provider/custom_file_provider.c b/examples/custom_file_provider/custom_file_provider.c index 38247acf0..b0f1bc062 100644 --- a/examples/custom_file_provider/custom_file_provider.c +++ b/examples/custom_file_provider/custom_file_provider.c @@ -251,11 +251,11 @@ static umf_memory_provider_ops_t file_ops = { .initialize = file_init, .finalize = file_deinit, .alloc = file_alloc, - .free = file_free, .get_name = file_get_name, .get_last_native_error = file_get_last_native_error, .get_recommended_page_size = file_get_recommended_page_size, .get_min_page_size = file_get_min_page_size, + .ext.free = file_free, }; // Main function diff --git a/include/umf/memory_provider_ops.h b/include/umf/memory_provider_ops.h index a61e0aad0..0b9c7cfce 100644 --- a/include/umf/memory_provider_ops.h +++ b/include/umf/memory_provider_ops.h @@ -22,6 +22,15 @@ extern "C" { /// can keep them NULL. /// typedef struct umf_memory_provider_ext_ops_t { + /// + /// @brief Frees the memory space pointed by \p ptr from the memory \p provider + /// @param provider pointer to the memory provider + /// @param ptr pointer to the allocated memory to free + /// @param size size of the allocation + /// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure + /// + umf_result_t (*free)(void *provider, void *ptr, size_t size); + /// /// @brief Discard physical pages within the virtual memory mapping associated at the given addr /// and \p size. This call is asynchronous and may delay purging the pages indefinitely. @@ -172,15 +181,6 @@ typedef struct umf_memory_provider_ops_t { umf_result_t (*alloc)(void *provider, size_t size, size_t alignment, void **ptr); - /// - /// @brief Frees the memory space pointed by \p ptr from the memory \p provider - /// @param provider pointer to the memory provider - /// @param ptr pointer to the allocated memory to free - /// @param size size of the allocation - /// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure - /// - umf_result_t (*free)(void *provider, void *ptr, size_t size); - /// /// @brief Retrieve string representation of the underlying provider specific /// result reported by the last API that returned diff --git a/src/cpp_helpers.hpp b/src/cpp_helpers.hpp index 86204a20e..aafc7c4db 100644 --- a/src/cpp_helpers.hpp +++ b/src/cpp_helpers.hpp @@ -84,7 +84,7 @@ template umf_memory_provider_ops_t providerOpsBase() { ops.version = UMF_VERSION_CURRENT; ops.finalize = [](void *obj) { delete reinterpret_cast(obj); }; UMF_ASSIGN_OP(ops, T, alloc, UMF_RESULT_ERROR_UNKNOWN); - UMF_ASSIGN_OP(ops, T, free, UMF_RESULT_ERROR_UNKNOWN); + UMF_ASSIGN_OP(ops.ext, T, free, UMF_RESULT_ERROR_UNKNOWN); UMF_ASSIGN_OP_NORETURN(ops, T, get_last_native_error); UMF_ASSIGN_OP(ops, T, get_recommended_page_size, UMF_RESULT_ERROR_UNKNOWN); UMF_ASSIGN_OP(ops, T, get_min_page_size, UMF_RESULT_ERROR_UNKNOWN); diff --git a/src/memory_provider.c b/src/memory_provider.c index f6e07af62..298a39e74 100644 --- a/src/memory_provider.c +++ b/src/memory_provider.c @@ -25,6 +25,13 @@ typedef struct umf_memory_provider_t { void *provider_priv; } umf_memory_provider_t; +static umf_result_t umfDefaultFree(void *provider, void *ptr, size_t size) { + (void)provider; + (void)ptr; + (void)size; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + static umf_result_t umfDefaultPurgeLazy(void *provider, void *ptr, size_t size) { (void)provider; @@ -99,6 +106,9 @@ static umf_result_t umfDefaultCloseIPCHandle(void *provider, void *ptr, } void assignOpsExtDefaults(umf_memory_provider_ops_t *ops) { + if (!ops->ext.free) { + ops->ext.free = umfDefaultFree; + } if (!ops->ext.purge_lazy) { ops->ext.purge_lazy = umfDefaultPurgeLazy; } @@ -133,7 +143,7 @@ void assignOpsIpcDefaults(umf_memory_provider_ops_t *ops) { static bool validateOpsMandatory(const umf_memory_provider_ops_t *ops) { // Mandatory ops should be non-NULL - return ops->alloc && ops->free && ops->get_recommended_page_size && + return ops->alloc && ops->get_recommended_page_size && ops->get_min_page_size && ops->initialize && ops->finalize && ops->get_last_native_error && ops->get_name; } @@ -219,7 +229,8 @@ umf_result_t umfMemoryProviderAlloc(umf_memory_provider_handle_t hProvider, umf_result_t umfMemoryProviderFree(umf_memory_provider_handle_t hProvider, void *ptr, size_t size) { UMF_CHECK((hProvider != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); - umf_result_t res = hProvider->ops.free(hProvider->provider_priv, ptr, size); + umf_result_t res = + hProvider->ops.ext.free(hProvider->provider_priv, ptr, size); checkErrorAndSetLastProvider(res, hProvider); return res; } diff --git a/src/provider/provider_cuda.c b/src/provider/provider_cuda.c index b7c4a308d..22dfc49f1 100644 --- a/src/provider/provider_cuda.c +++ b/src/provider/provider_cuda.c @@ -348,11 +348,11 @@ static struct umf_memory_provider_ops_t UMF_CUDA_MEMORY_PROVIDER_OPS = { .initialize = cu_memory_provider_initialize, .finalize = cu_memory_provider_finalize, .alloc = cu_memory_provider_alloc, - .free = cu_memory_provider_free, .get_last_native_error = cu_memory_provider_get_last_native_error, .get_recommended_page_size = cu_memory_provider_get_recommended_page_size, .get_min_page_size = cu_memory_provider_get_min_page_size, .get_name = cu_memory_provider_get_name, + .ext.free = cu_memory_provider_free, // TODO /* .ext.purge_lazy = cu_memory_provider_purge_lazy, diff --git a/src/provider/provider_devdax_memory.c b/src/provider/provider_devdax_memory.c index 45fc725cc..0127f75ae 100644 --- a/src/provider/provider_devdax_memory.c +++ b/src/provider/provider_devdax_memory.c @@ -247,15 +247,6 @@ static umf_result_t devdax_alloc(void *provider, size_t size, size_t alignment, return UMF_RESULT_SUCCESS; } -// free() is not supported -static umf_result_t devdax_free(void *provider, void *ptr, size_t size) { - (void)provider; // unused - (void)ptr; // unused - (void)size; // unused - - return UMF_RESULT_ERROR_NOT_SUPPORTED; -} - static void devdax_get_last_native_error(void *provider, const char **ppMessage, int32_t *pError) { (void)provider; // unused @@ -520,7 +511,6 @@ static umf_memory_provider_ops_t UMF_DEVDAX_MEMORY_PROVIDER_OPS = { .initialize = devdax_initialize, .finalize = devdax_finalize, .alloc = devdax_alloc, - .free = devdax_free, .get_last_native_error = devdax_get_last_native_error, .get_recommended_page_size = devdax_get_recommended_page_size, .get_min_page_size = devdax_get_min_page_size, diff --git a/src/provider/provider_file_memory.c b/src/provider/provider_file_memory.c index ec967f3df..b89e6bd86 100644 --- a/src/provider/provider_file_memory.c +++ b/src/provider/provider_file_memory.c @@ -392,15 +392,6 @@ static umf_result_t file_alloc(void *provider, size_t size, size_t alignment, return UMF_RESULT_SUCCESS; } -// free() is not supported -static umf_result_t file_free(void *provider, void *ptr, size_t size) { - (void)provider; // unused - (void)ptr; // unused - (void)size; // unused - - return UMF_RESULT_ERROR_NOT_SUPPORTED; -} - static void file_get_last_native_error(void *provider, const char **ppMessage, int32_t *pError) { (void)provider; // unused @@ -688,7 +679,6 @@ static umf_memory_provider_ops_t UMF_FILE_MEMORY_PROVIDER_OPS = { .initialize = file_initialize, .finalize = file_finalize, .alloc = file_alloc, - .free = file_free, .get_last_native_error = file_get_last_native_error, .get_recommended_page_size = file_get_recommended_page_size, .get_min_page_size = file_get_min_page_size, diff --git a/src/provider/provider_level_zero.c b/src/provider/provider_level_zero.c index d940d8ded..6b6cc2e2c 100644 --- a/src/provider/provider_level_zero.c +++ b/src/provider/provider_level_zero.c @@ -545,11 +545,11 @@ static struct umf_memory_provider_ops_t UMF_LEVEL_ZERO_MEMORY_PROVIDER_OPS = { .initialize = ze_memory_provider_initialize, .finalize = ze_memory_provider_finalize, .alloc = ze_memory_provider_alloc, - .free = ze_memory_provider_free, .get_last_native_error = ze_memory_provider_get_last_native_error, .get_recommended_page_size = ze_memory_provider_get_recommended_page_size, .get_min_page_size = ze_memory_provider_get_min_page_size, .get_name = ze_memory_provider_get_name, + .ext.free = ze_memory_provider_free, .ext.purge_lazy = ze_memory_provider_purge_lazy, .ext.purge_force = ze_memory_provider_purge_force, .ext.allocation_merge = ze_memory_provider_allocation_merge, diff --git a/src/provider/provider_os_memory.c b/src/provider/provider_os_memory.c index 3b8bbbe91..fe4ca0460 100644 --- a/src/provider/provider_os_memory.c +++ b/src/provider/provider_os_memory.c @@ -1311,11 +1311,11 @@ static umf_memory_provider_ops_t UMF_OS_MEMORY_PROVIDER_OPS = { .initialize = os_initialize, .finalize = os_finalize, .alloc = os_alloc, - .free = os_free, .get_last_native_error = os_get_last_native_error, .get_recommended_page_size = os_get_recommended_page_size, .get_min_page_size = os_get_min_page_size, .get_name = os_get_name, + .ext.free = os_free, .ext.purge_lazy = os_purge_lazy, .ext.purge_force = os_purge_force, .ext.allocation_merge = os_allocation_merge, diff --git a/src/provider/provider_tracking.c b/src/provider/provider_tracking.c index 83aa5c335..cbe028e2f 100644 --- a/src/provider/provider_tracking.c +++ b/src/provider/provider_tracking.c @@ -665,11 +665,11 @@ umf_memory_provider_ops_t UMF_TRACKING_MEMORY_PROVIDER_OPS = { .initialize = trackingInitialize, .finalize = trackingFinalize, .alloc = trackingAlloc, - .free = trackingFree, .get_last_native_error = trackingGetLastError, .get_min_page_size = trackingGetMinPageSize, .get_recommended_page_size = trackingGetRecommendedPageSize, .get_name = trackingName, + .ext.free = trackingFree, .ext.purge_force = trackingPurgeForce, .ext.purge_lazy = trackingPurgeLazy, .ext.allocation_split = trackingAllocationSplit, diff --git a/test/common/provider_null.c b/test/common/provider_null.c index e667bfce4..5db389e89 100644 --- a/test/common/provider_null.c +++ b/test/common/provider_null.c @@ -134,11 +134,11 @@ umf_memory_provider_ops_t UMF_NULL_PROVIDER_OPS = { .initialize = nullInitialize, .finalize = nullFinalize, .alloc = nullAlloc, - .free = nullFree, .get_last_native_error = nullGetLastError, .get_recommended_page_size = nullGetRecommendedPageSize, .get_min_page_size = nullGetPageSize, .get_name = nullName, + .ext.free = nullFree, .ext.purge_lazy = nullPurgeLazy, .ext.purge_force = nullPurgeForce, .ext.allocation_merge = nullAllocationMerge, diff --git a/test/common/provider_trace.c b/test/common/provider_trace.c index 9d063b4f5..219dde5cd 100644 --- a/test/common/provider_trace.c +++ b/test/common/provider_trace.c @@ -195,11 +195,11 @@ umf_memory_provider_ops_t UMF_TRACE_PROVIDER_OPS = { .initialize = traceInitialize, .finalize = traceFinalize, .alloc = traceAlloc, - .free = traceFree, .get_last_native_error = traceGetLastError, .get_recommended_page_size = traceGetRecommendedPageSize, .get_min_page_size = traceGetPageSize, .get_name = traceName, + .ext.free = traceFree, .ext.purge_lazy = tracePurgeLazy, .ext.purge_force = tracePurgeForce, .ext.allocation_merge = traceAllocationMerge, diff --git a/test/memoryProviderAPI.cpp b/test/memoryProviderAPI.cpp index 144aa4d55..41196de34 100644 --- a/test/memoryProviderAPI.cpp +++ b/test/memoryProviderAPI.cpp @@ -86,6 +86,19 @@ TEST_F(test, memoryProviderTrace) { ASSERT_EQ(calls.size(), ++call_count); } +TEST_F(test, memoryProviderOpsNullFreeField) { + umf_memory_provider_ops_t provider_ops = UMF_NULL_PROVIDER_OPS; + provider_ops.ext.free = nullptr; + umf_memory_provider_handle_t hProvider; + auto ret = umfMemoryProviderCreate(&provider_ops, nullptr, &hProvider); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + ret = umfMemoryProviderFree(hProvider, nullptr, 0); + ASSERT_EQ(ret, UMF_RESULT_ERROR_NOT_SUPPORTED); + + umfMemoryProviderDestroy(hProvider); +} + TEST_F(test, memoryProviderOpsNullPurgeLazyField) { umf_memory_provider_ops_t provider_ops = UMF_NULL_PROVIDER_OPS; provider_ops.ext.purge_lazy = nullptr; @@ -155,14 +168,6 @@ TEST_F(test, memoryProviderOpsNullAllocField) { ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); } -TEST_F(test, memoryProviderOpsNullFreeField) { - umf_memory_provider_ops_t provider_ops = UMF_NULL_PROVIDER_OPS; - provider_ops.free = nullptr; - umf_memory_provider_handle_t hProvider; - auto ret = umfMemoryProviderCreate(&provider_ops, nullptr, &hProvider); - ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); -} - TEST_F(test, memoryProviderOpsNullGetLastNativeErrorField) { umf_memory_provider_ops_t provider_ops = UMF_NULL_PROVIDER_OPS; provider_ops.get_last_native_error = nullptr; From fa006eea503a58e79fa197891f1391c9dcda73e1 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Thu, 3 Oct 2024 15:29:29 +0200 Subject: [PATCH 144/352] Add umfIsFreeOpDefault(hProvider) Add umfIsFreeOpDefault(hProvider) to check if op.ext.free is set to the default function pointer. Signed-off-by: Lukasz Dorau --- src/memory_pool.c | 3 +-- src/memory_provider.c | 4 ++++ src/memory_provider_internal.h | 3 +++ test/pools/disjoint_pool.cpp | 5 +---- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/memory_pool.c b/src/memory_pool.c index f6ae8841f..c45ddafe7 100644 --- a/src/memory_pool.c +++ b/src/memory_pool.c @@ -43,8 +43,7 @@ static umf_result_t umfPoolCreateInternal(const umf_memory_pool_ops_t *ops, if (!(flags & UMF_POOL_CREATE_FLAG_DISABLE_TRACKING)) { // Wrap provider with memory tracking provider. // Check if the provider supports the free() operation. - bool upstreamDoesNotFree = (umfMemoryProviderFree(provider, NULL, 0) == - UMF_RESULT_ERROR_NOT_SUPPORTED); + bool upstreamDoesNotFree = umfIsFreeOpDefault(provider); ret = umfTrackingMemoryProviderCreate(provider, pool, &pool->provider, upstreamDoesNotFree); if (ret != UMF_RESULT_SUCCESS) { diff --git a/src/memory_provider.c b/src/memory_provider.c index 298a39e74..1e47a248a 100644 --- a/src/memory_provider.c +++ b/src/memory_provider.c @@ -169,6 +169,10 @@ static bool validateOps(const umf_memory_provider_ops_t *ops) { validateOpsIpc(&(ops->ipc)); } +bool umfIsFreeOpDefault(umf_memory_provider_handle_t hProvider) { + return (hProvider->ops.ext.free == umfDefaultFree); +} + umf_result_t umfMemoryProviderCreate(const umf_memory_provider_ops_t *ops, void *params, umf_memory_provider_handle_t *hProvider) { diff --git a/src/memory_provider_internal.h b/src/memory_provider_internal.h index 4e858992d..49b2f2e53 100644 --- a/src/memory_provider_internal.h +++ b/src/memory_provider_internal.h @@ -10,6 +10,8 @@ #ifndef UMF_MEMORY_PROVIDER_INTERNAL_H #define UMF_MEMORY_PROVIDER_INTERNAL_H 1 +#include + #include #ifdef __cplusplus @@ -18,6 +20,7 @@ extern "C" { void *umfMemoryProviderGetPriv(umf_memory_provider_handle_t hProvider); umf_memory_provider_handle_t *umfGetLastFailedMemoryProviderPtr(void); +bool umfIsFreeOpDefault(umf_memory_provider_handle_t hProvider); #ifdef __cplusplus } diff --git a/test/pools/disjoint_pool.cpp b/test/pools/disjoint_pool.cpp index 2f5d61142..d7612f4d5 100644 --- a/test/pools/disjoint_pool.cpp +++ b/test/pools/disjoint_pool.cpp @@ -82,10 +82,7 @@ TEST_F(test, sharedLimits) { } umf_result_t free(void *ptr, [[maybe_unused]] size_t size) noexcept { ::free(ptr); - // umfMemoryProviderFree(provider, NULL, 0) is called inside umfPoolCreateInternal() - if (ptr != NULL && size != 0) { - numFrees++; - } + numFrees++; return UMF_RESULT_SUCCESS; } }; From 39cdf856b788d0ec84a86e18ea8d037011c75762 Mon Sep 17 00:00:00 2001 From: Agata Momot Date: Fri, 30 Aug 2024 14:32:51 +0000 Subject: [PATCH 145/352] fix: replace UT_ASSERTs with GTEST asserts canQuery*(...) are changed to void, since EXPECT_* and ADD_FAILURE() interefere with GTEST_SKIP() when used in a non-void helper function - tests are run in spite of labelling as skipped by the fixture. The success, failure or the need to skip the tests are determined in the function body using GTEST asserts, which set the appropriate flags for the current test. Then the flags are checked in the fixture. Ref. #569 --- test/common/base.hpp | 2 ++ test/memspaces/memspace_fixtures.hpp | 21 ++++++++++++++----- test/memspaces/memspace_highest_bandwidth.cpp | 16 +++++++++----- test/memspaces/memspace_lowest_latency.cpp | 16 +++++++++----- 4 files changed, 40 insertions(+), 15 deletions(-) diff --git a/test/common/base.hpp b/test/common/base.hpp index 8f2d5f6be..ea8f04a37 100644 --- a/test/common/base.hpp +++ b/test/common/base.hpp @@ -14,6 +14,8 @@ namespace umf_test { +#define IS_SKIPPED_OR_FAILED() (HasFatalFailure() || IsSkipped()) + #define NOEXCEPT_COND(cond, val, expected_val) \ try { \ cond(val, expected_val); \ diff --git a/test/memspaces/memspace_fixtures.hpp b/test/memspaces/memspace_fixtures.hpp index d2886ee7e..9bcfc5fbe 100644 --- a/test/memspaces/memspace_fixtures.hpp +++ b/test/memspaces/memspace_fixtures.hpp @@ -51,7 +51,7 @@ struct numaNodesTest : ::umf_test::test { unsigned long maxNodeId = 0; }; -using isQuerySupportedFunc = bool (*)(size_t); +using isQuerySupportedFunc = void (*)(size_t); using memspaceGetFunc = umf_const_memspace_handle_t (*)(); using memspaceGetParams = std::tuple; @@ -65,9 +65,10 @@ struct memspaceGetTest : ::numaNodesTest, } auto [isQuerySupported, memspaceGet] = this->GetParam(); + isQuerySupported(nodeIds.front()); - if (!isQuerySupported(nodeIds.front())) { - GTEST_SKIP(); + if (IS_SKIPPED_OR_FAILED()) { + return; } hMemspace = memspaceGet(); @@ -81,8 +82,18 @@ struct memspaceProviderTest : ::memspaceGetTest { void SetUp() override { ::memspaceGetTest::SetUp(); - if (::memspaceGetTest::IsSkipped()) { - GTEST_SKIP(); + if (numa_available() == -1 || numa_all_nodes_ptr == nullptr) { + GTEST_SKIP() << "No available NUMA support; skipped"; + } + + auto [isQuerySupported, memspaceGet] = ::memspaceGetTest::GetParam(); + isQuerySupported(nodeIds.front()); + + // The test has been marked as skipped in isQuerySupported, + // repeating GTEST_SKIP in fixture would only duplicate + // the output message + if (IS_SKIPPED_OR_FAILED()) { + return; } umf_result_t ret = diff --git a/test/memspaces/memspace_highest_bandwidth.cpp b/test/memspaces/memspace_highest_bandwidth.cpp index a5bffb41d..5c30696a8 100644 --- a/test/memspaces/memspace_highest_bandwidth.cpp +++ b/test/memspaces/memspace_highest_bandwidth.cpp @@ -9,16 +9,17 @@ #include "memspace_internal.h" #include "test_helpers.h" -static bool canQueryBandwidth(size_t nodeId) { +static void canQueryBandwidth(size_t nodeId) { hwloc_topology_t topology = nullptr; int ret = hwloc_topology_init(&topology); - UT_ASSERTeq(ret, 0); + ASSERT_EQ(ret, 0); + ret = hwloc_topology_load(topology); - UT_ASSERTeq(ret, 0); + ASSERT_EQ(ret, 0); hwloc_obj_t numaNode = hwloc_get_obj_by_type(topology, HWLOC_OBJ_NUMANODE, nodeId); - UT_ASSERTne(numaNode, nullptr); + ASSERT_NE(numaNode, nullptr); // Setup initiator structure. struct hwloc_location initiator; @@ -30,7 +31,12 @@ static bool canQueryBandwidth(size_t nodeId) { numaNode, &initiator, 0, &value); hwloc_topology_destroy(topology); - return (ret == 0); + + if (ret != 0) { + GTEST_SKIP() + << "Error: hwloc_memattr_get_value return value is equal to " << ret + << ", should be " << 0; + } } INSTANTIATE_TEST_SUITE_P(memspaceLowestLatencyTest, memspaceGetTest, diff --git a/test/memspaces/memspace_lowest_latency.cpp b/test/memspaces/memspace_lowest_latency.cpp index cf921612c..fc35f465a 100644 --- a/test/memspaces/memspace_lowest_latency.cpp +++ b/test/memspaces/memspace_lowest_latency.cpp @@ -9,16 +9,17 @@ #include "memspace_internal.h" #include "test_helpers.h" -static bool canQueryLatency(size_t nodeId) { +static void canQueryLatency(size_t nodeId) { hwloc_topology_t topology = nullptr; int ret = hwloc_topology_init(&topology); - UT_ASSERTeq(ret, 0); + ASSERT_EQ(ret, 0); + ret = hwloc_topology_load(topology); - UT_ASSERTeq(ret, 0); + ASSERT_EQ(ret, 0); hwloc_obj_t numaNode = hwloc_get_obj_by_type(topology, HWLOC_OBJ_NUMANODE, nodeId); - UT_ASSERTne(numaNode, nullptr); + ASSERT_NE(numaNode, nullptr); // Setup initiator structure. struct hwloc_location initiator; @@ -30,7 +31,12 @@ static bool canQueryLatency(size_t nodeId) { &initiator, 0, &value); hwloc_topology_destroy(topology); - return (ret == 0); + + if (ret != 0) { + GTEST_SKIP() + << "Error: hwloc_memattr_get_value return value is equal to " << ret + << ", should be " << 0; + } } INSTANTIATE_TEST_SUITE_P(memspaceLowestLatencyTest, memspaceGetTest, From 84e7b71bdcc46d83bcdc9e149ce12fb1a382fbc2 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Sat, 5 Oct 2024 11:44:29 +0200 Subject: [PATCH 146/352] Add Coarse provider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add Coarse provider - a memory provider that can manage a memory (i.e. handle the alloc() and free() ops) of a given pre-allocated buffer or of an additional upstream provider (e.g. OS Memory Provider or providers that do not support the free() operation, like the file memory provider and the DevDax memory provider). Co-developed-by: Rafał Rudnicki Co-developed-by: Lukasz Dorau Signed-off-by: Lukasz Dorau --- README.md | 7 + include/umf/providers/provider_coarse.h | 102 ++ scripts/docs_config/api.rst | 11 + src/CMakeLists.txt | 2 + src/libumf.def.in | 2 + src/libumf.map.in | 2 + src/provider/provider_coarse.c | 1572 +++++++++++++++++ src/utils/utils_common.h | 6 +- test/CMakeLists.txt | 4 + test/common/base.hpp | 3 + test/disjointCoarseMallocPool.cpp | 761 ++++++++ ...ind-umf_test-disjointCoarseMallocPool.supp | 24 + 12 files changed, 2495 insertions(+), 1 deletion(-) create mode 100644 include/umf/providers/provider_coarse.h create mode 100644 src/provider/provider_coarse.c create mode 100644 test/disjointCoarseMallocPool.cpp create mode 100644 test/supp/helgrind-umf_test-disjointCoarseMallocPool.supp diff --git a/README.md b/README.md index 9c73ecbf1..0d2587f4e 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,13 @@ More detailed documentation is available here: https://oneapi-src.github.io/unif ### Memory providers +#### Coarse Provider + +A memory provider that can provide memory from: +1) a given pre-allocated buffer (the fixed-size memory provider option) or +2) from an additional upstream provider (e.g. provider that does not support the free() operation + like the File memory provider or the DevDax memory provider - see below). + #### OS memory provider A memory provider that provides memory from an operating system. diff --git a/include/umf/providers/provider_coarse.h b/include/umf/providers/provider_coarse.h new file mode 100644 index 000000000..16d11fd77 --- /dev/null +++ b/include/umf/providers/provider_coarse.h @@ -0,0 +1,102 @@ +/* + * 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 + +#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; +} 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); + +#ifdef __cplusplus +} +#endif + +#endif // UMF_COARSE_PROVIDER_H diff --git a/scripts/docs_config/api.rst b/scripts/docs_config/api.rst index 625116dd2..bc9b83056 100644 --- a/scripts/docs_config/api.rst +++ b/scripts/docs_config/api.rst @@ -80,6 +80,17 @@ and operate on the provider. .. doxygenfile:: memory_provider.h :sections: define enum typedef func var +Coarse Provider +------------------------------------------ + +A memory provider that can provide memory from: +1) a given pre-allocated buffer (the fixed-size memory provider option) or +2) from an additional upstream provider (e.g. provider that does not support the free() operation + like the File memory provider or the DevDax memory provider - see below). + +.. doxygenfile:: provider_coarse.h + :sections: define enum typedef func var + OS Memory Provider ------------------------------------------ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9eb883cfa..fdba77858 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -110,6 +110,7 @@ set(UMF_SOURCES memtarget.c mempolicy.c memspace.c + provider/provider_coarse.c provider/provider_tracking.c critnib/critnib.c ravl/ravl.c @@ -266,6 +267,7 @@ target_include_directories( umf PUBLIC $ $ + $ $ $ $ diff --git a/src/libumf.def.in b/src/libumf.def.in index e0a43042e..01aaa7e68 100644 --- a/src/libumf.def.in +++ b/src/libumf.def.in @@ -14,6 +14,8 @@ EXPORTS umfTearDown umfGetCurrentVersion umfCloseIPCHandle + umfCoarseMemoryProviderGetStats + umfCoarseMemoryProviderOps umfFree umfGetIPCHandle umfGetLastFailedMemoryProvider diff --git a/src/libumf.map.in b/src/libumf.map.in index 59fbe3cf3..99e45298a 100644 --- a/src/libumf.map.in +++ b/src/libumf.map.in @@ -8,6 +8,8 @@ UMF_1.0 { umfTearDown; umfGetCurrentVersion; umfCloseIPCHandle; + umfCoarseMemoryProviderGetStats; + umfCoarseMemoryProviderOps; umfFree; umfGetIPCHandle; umfGetLastFailedMemoryProvider; diff --git a/src/provider/provider_coarse.c b/src/provider/provider_coarse.c new file mode 100644 index 000000000..b404014d8 --- /dev/null +++ b/src/provider/provider_coarse.c @@ -0,0 +1,1572 @@ +/* + * 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; + + // 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; + + // Set to true if the free() operation of the upstream memory provider is not supported + // (i.e. if (umfMemoryProviderFree(upstream_memory_provider, NULL, 0) == UMF_RESULT_ERROR_NOT_SUPPORTED) + bool disable_upstream_provider_free; +} 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 ravl_node_t *get_block_node(struct ravl *rtree, block_t *block) { + ravl_data_t rdata = {(uintptr_t)block->data, NULL}; + return ravl_find(rtree, &rdata, RAVL_PREDICATE_EQUAL); +} + +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); +} + +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); +} + +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; + default: + LOG_DEBUG("wrong value of check_blocks"); + block = NULL; + assert(0); + break; + } + + 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) { + umf_result_t umf_result = UMF_RESULT_ERROR_UNKNOWN; + + if (provider == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + 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; + } + + 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->allocation_strategy = coarse_params->allocation_strategy; + coarse_provider->init_buffer = coarse_params->init_buffer; + + if (coarse_provider->upstream_memory_provider) { + coarse_provider->disable_upstream_provider_free = + umfIsFreeOpDefault(coarse_provider->upstream_memory_provider); + } else { + coarse_provider->disable_upstream_provider_free = false; + } + + 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; + } + + 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"); + umf_result = UMF_RESULT_ERROR_OUT_OF_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"); + umf_result = UMF_RESULT_ERROR_OUT_OF_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"); + umf_result = UMF_RESULT_ERROR_OUT_OF_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"); + 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) { + umf_result = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + 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 && + !coarse_provider->disable_upstream_provider_free) { + // 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) { + if (provider == NULL) { + assert(0); + return; + } + + 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); + + 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); + + default: + LOG_ERR("unknown memory allocation strategy"); + assert(0); + return NULL; + } +} + +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_SUCCESS; + + if (provider == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + 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("lockng 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) { + if (utils_mutex_unlock(&coarse_provider->lock) != 0) { + LOG_ERR("unlocking the lock failed"); + } + 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) { + if (utils_mutex_unlock(&coarse_provider->lock) != 0) { + LOG_ERR("unlocking the lock failed"); + } + 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)); + + if (utils_mutex_unlock(&coarse_provider->lock) != 0) { + LOG_ERR("unlocking the lock failed"); + return UMF_RESULT_ERROR_UNKNOWN; + } + + return UMF_RESULT_SUCCESS; + } + + // no suitable block found - try to get more memory from the upstream provider + + if (coarse_provider->upstream_memory_provider == NULL) { + LOG_ERR("out of memory - no upstream memory provider given"); + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + umfMemoryProviderAlloc(coarse_provider->upstream_memory_provider, size, + alignment, resultPtr); + if (*resultPtr == NULL) { + LOG_ERR("out of memory - upstream memory provider allocation failed"); + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + ASSERT_IS_ALIGNED(((uintptr_t)(*resultPtr)), alignment); + + umf_result = coarse_add_upstream_block(coarse_provider, *resultPtr, size); + if (umf_result != UMF_RESULT_SUCCESS) { + return umf_result; + } + + LOG_DEBUG("coarse_ALLOC (upstream) %zu used %zu alloc %zu", size, + coarse_provider->used_size, coarse_provider->alloc_size); + + assert(debug_check(coarse_provider)); + + if (utils_mutex_unlock(&coarse_provider->lock) != 0) { + LOG_ERR("unlocking the lock failed"); + umf_result = UMF_RESULT_ERROR_UNKNOWN; + goto unlock_error; + } + + return UMF_RESULT_SUCCESS; + +unlock_error: + coarse_ravl_rm(coarse_provider->all_blocks, *resultPtr); + coarse_ravl_rm(coarse_provider->upstream_blocks, *resultPtr); + + if (!coarse_provider->disable_upstream_provider_free) { + umfMemoryProviderFree(coarse_provider->upstream_memory_provider, + *resultPtr, size); + } + + return umf_result; +} + +static umf_result_t coarse_memory_provider_free(void *provider, void *ptr, + size_t bytes) { + if (provider == 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("lockng 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; + } + + assert(bytes == 0 || bytes == block->size); + + 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)); + + if (utils_mutex_unlock(&coarse_provider->lock) != 0) { + LOG_ERR("unlocking the lock failed"); + return UMF_RESULT_ERROR_UNKNOWN; + } + + 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) { + if (provider == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + 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) { + if (provider == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + 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) { + if (provider == NULL) { + return COARSE_BASE_NAME; + } + + 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) { + if (provider == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + if (stats == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + 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; +} + +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, + .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.free = coarse_memory_provider_free, + // TODO + /* + .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, + .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("lockng the lock failed"); + return stats; + } + + coarse_memory_provider_get_stats(priv, &stats); + + utils_mutex_unlock(&coarse_provider->lock); + + return stats; +} diff --git a/src/utils/utils_common.h b/src/utils/utils_common.h index 999fc5745..e5fea27e7 100644 --- a/src/utils/utils_common.h +++ b/src/utils/utils_common.h @@ -35,10 +35,14 @@ typedef enum umf_purge_advise_t { expression; \ } while (0) +#define IS_ALIGNED(value, align) \ + ((align == 0 || (((value) & ((align)-1)) == 0))) +#define IS_NOT_ALIGNED(value, align) \ + ((align != 0 && (((value) & ((align)-1)) != 0))) #define ALIGN_UP(value, align) (((value) + (align)-1) & ~((align)-1)) #define ALIGN_DOWN(value, align) ((value) & ~((align)-1)) #define ASSERT_IS_ALIGNED(value, align) \ - DO_WHILE_EXPRS(assert(((value) & ((align)-1)) == 0)) + DO_WHILE_EXPRS(assert(IS_ALIGNED(value, align))) #define VALGRIND_ANNOTATE_NEW_MEMORY(p, s) DO_WHILE_EMPTY #define VALGRIND_HG_DRD_DISABLE_CHECKING(p, s) DO_WHILE_EMPTY diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a10562038..3020094b9 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -161,6 +161,10 @@ 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) endif() if(UMF_BUILD_LIBUMF_POOL_DISJOINT diff --git a/test/common/base.hpp b/test/common/base.hpp index 8f2d5f6be..9fcf718ca 100644 --- a/test/common/base.hpp +++ b/test/common/base.hpp @@ -48,6 +48,9 @@ std::function withGeneratedArgs(Ret (*f)(Args...)) { }; } +const size_t KB = 1024; +const size_t MB = 1024 * KB; + } // namespace umf_test #endif /* UMF_TEST_BASE_HPP */ diff --git a/test/disjointCoarseMallocPool.cpp b/test/disjointCoarseMallocPool.cpp new file mode 100644 index 000000000..254479a46 --- /dev/null +++ b/test/disjointCoarseMallocPool.cpp @@ -0,0 +1,761 @@ +/* + * 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 +#include + +using umf_test::KB; +using umf_test::MB; +using umf_test::test; + +#define GetStats umfCoarseMemoryProviderGetStats + +#define UPSTREAM_NAME "malloc" +#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, disjointCoarseMallocPool_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.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); + + ASSERT_EQ( + strcmp(umfMemoryProviderGetName(coarse_memory_provider), COARSE_NAME), + 0); + + umfMemoryProviderDestroy(coarse_memory_provider); + umfMemoryProviderDestroy(malloc_memory_provider); +} + +TEST_F(test, disjointCoarseMallocPool_name_no_upstream) { + umf_result_t umf_result; + + const size_t init_buffer_size = 20 * MB; + + // Preallocate some memory + std::unique_ptr buffer(new char[init_buffer_size]); + void *buf = buffer.get(); + ASSERT_NE(buf, nullptr); + memset(buf, 0, init_buffer_size); + + 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); + + ASSERT_EQ( + strcmp(umfMemoryProviderGetName(coarse_memory_provider), BASE_NAME), 0); + + umfMemoryProviderDestroy(coarse_memory_provider); +} + +TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_basic) { + 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.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 = 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_t disjoint_memory_pool_params = {}; + disjoint_memory_pool_params.SlabMinSize = 4096; + disjoint_memory_pool_params.MaxPoolableSize = 4096; + disjoint_memory_pool_params.Capacity = 4; + disjoint_memory_pool_params.MinBucketSize = 64; + disjoint_memory_pool_params.PoolTrace = 1; + + umf_memory_pool_handle_t pool; + umf_result = umfPoolCreate(umfDisjointPoolOps(), coarse_memory_provider, + &disjoint_memory_pool_params, + UMF_POOL_CREATE_FLAG_NONE, &pool); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(pool, nullptr); + + // test + + umf_memory_provider_handle_t prov = NULL; + umf_result = umfPoolGetMemoryProvider(pool, &prov); + 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); + umfMemoryProviderDestroy(coarse_memory_provider); + umfMemoryProviderDestroy(malloc_memory_provider); +} + +TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_simple1) { + 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.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); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(coarse_memory_provider, nullptr); + + umf_disjoint_pool_params_t disjoint_memory_pool_params = {}; + disjoint_memory_pool_params.SlabMinSize = 4096; + disjoint_memory_pool_params.MaxPoolableSize = 4096; + disjoint_memory_pool_params.Capacity = 4; + disjoint_memory_pool_params.MinBucketSize = 64; + disjoint_memory_pool_params.PoolTrace = 1; + + umf_memory_pool_handle_t pool; + umf_result = umfPoolCreate(umfDisjointPoolOps(), coarse_memory_provider, + &disjoint_memory_pool_params, + UMF_POOL_CREATE_FLAG_NONE, &pool); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(pool, nullptr); + + umf_memory_provider_handle_t prov = NULL; + umfPoolGetMemoryProvider(pool, &prov); + ASSERT_NE(prov, nullptr); + + // test 1 + + size_t s1 = 74659 * KB; + size_t s2 = 8206 * KB; + + size_t max_alloc_size = 0; + + const int nreps = 2; + const int nptrs = 6; + + // s1 + for (int j = 0; j < nreps; j++) { + void *t[nptrs] = {0}; + for (int i = 0; i < nptrs; i++) { + t[i] = umfPoolMalloc(pool, s1); + 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); + } + } + + // s2 + for (int j = 0; j < nreps; j++) { + void *t[nptrs] = {0}; + for (int i = 0; i < nptrs; i++) { + t[i] = umfPoolMalloc(pool, s2); + 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); + } + } + + umfPoolDestroy(pool); + umfMemoryProviderDestroy(coarse_memory_provider); + umfMemoryProviderDestroy(malloc_memory_provider); +} + +TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_simple2) { + 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.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); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(coarse_memory_provider, nullptr); + + umf_disjoint_pool_params_t disjoint_memory_pool_params = {}; + disjoint_memory_pool_params.SlabMinSize = 4096; + disjoint_memory_pool_params.MaxPoolableSize = 4096; + disjoint_memory_pool_params.Capacity = 4; + disjoint_memory_pool_params.MinBucketSize = 64; + disjoint_memory_pool_params.PoolTrace = 1; + + umf_memory_pool_handle_t pool; + umf_result = umfPoolCreate(umfDisjointPoolOps(), coarse_memory_provider, + &disjoint_memory_pool_params, + UMF_POOL_CREATE_FLAG_NONE, &pool); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(pool, nullptr); + + // test + double sizes[] = {2, 4, 0.5, 1, 8, 0.25}; + size_t alignment[] = {0, 4, 0, 16, 32, 128}; + for (int i = 0; i < 6; i++) { + size_t s = (size_t)(sizes[i] * MB); + void *t[8] = {0}; + for (int j = 0; j < 8; j++) { + t[j] = umfPoolAlignedMalloc(pool, s, alignment[i]); + ASSERT_NE(t[j], nullptr); + } + + for (int j = 0; j < 8; j++) { + umf_result = umfPoolFree(pool, t[j]); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + } + } + + umfPoolDestroy(pool); + umfMemoryProviderDestroy(coarse_memory_provider); + umfMemoryProviderDestroy(malloc_memory_provider); +} + +struct alloc_ptr_size { + void *ptr; + size_t size; + + bool operator<(const alloc_ptr_size &other) const { + if (ptr == other.ptr) { + return size < other.size; + } + return ptr < other.ptr; + } +}; + +TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMMapPool_random) { + umf_result_t umf_result; + + const size_t init_buffer_size = 200 * MB; + + // Preallocate some memory + std::unique_ptr buffer(new char[init_buffer_size]); + void *buf = buffer.get(); + ASSERT_NE(buf, nullptr); + memset(buf, 0, init_buffer_size); + + 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_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_t disjoint_memory_pool_params = {}; + disjoint_memory_pool_params.SlabMinSize = 1024; + disjoint_memory_pool_params.MaxPoolableSize = 1024; + disjoint_memory_pool_params.Capacity = 2; + disjoint_memory_pool_params.MinBucketSize = 16; + disjoint_memory_pool_params.PoolTrace = 1; + + umf_memory_pool_handle_t pool; + umf_result = umfPoolCreate(umfDisjointPoolOps(), coarse_memory_provider, + &disjoint_memory_pool_params, + UMF_POOL_CREATE_FLAG_NONE, &pool); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(pool, nullptr); + + // set constant seed so each test run will have the same scenario + uint32_t seed = 1234; + std::mt19937 mt(seed); + + // different sizes to alloc + std::vector sizes = {15, 49, 588, 1025, + 2 * KB, 5 * KB, 160 * KB, 511 * KB, + 1000 * KB, MB, 3 * MB, 7 * MB}; + std::uniform_int_distribution sizes_dist(0, (int)(sizes.size() - 1)); + + // each alloc would be done few times + std::vector counts = {1, 3, 4, 8, 9, 11}; + std::uniform_int_distribution counts_dist(0, (int)(counts.size() - 1)); + + // action to take will be random + // alloc = <0, .5), free = <.5, 1) + std::uniform_real_distribution actions_dist(0, 1); + + std::set allocs; + const int nreps = 100; + + for (size_t i = 0; i < nreps; i++) { + size_t count = counts[counts_dist(mt)]; + float action = actions_dist(mt); + + if (action < 0.5) { + size_t size = sizes[sizes_dist(mt)]; + std::cout << "size: " << size << " count: " << count + << " action: alloc" << std::endl; + + // alloc + for (size_t j = 0; j < count; j++) { + void *ptr = umfPoolMalloc(pool, size); + ASSERT_NE(ptr, nullptr); + + if (ptr == nullptr) { + break; + } + + // check if first and last bytes are empty and fill them with control data + ASSERT_EQ(((unsigned char *)ptr)[0], 0); + ASSERT_EQ(((unsigned char *)ptr)[size - 1], 0); + ((unsigned char *)ptr)[0] = alloc_check_val; + ((unsigned char *)ptr)[size - 1] = alloc_check_val; + + allocs.insert({ptr, size}); + } + } else { + std::cout << "count: " << count << " action: free" << std::endl; + + // free random allocs + for (size_t j = 0; j < count; j++) { + if (allocs.size() == 0) { + continue; + } + + std::uniform_int_distribution free_dist( + 0, (int)(allocs.size() - 1)); + size_t free_id = free_dist(mt); + auto it = allocs.begin(); + std::advance(it, free_id); + auto [ptr, size] = (*it); + ASSERT_NE(ptr, nullptr); + + // check if control bytes are set and clean them + + ASSERT_EQ(((unsigned char *)ptr)[0], alloc_check_val); + ASSERT_EQ(((unsigned char *)ptr)[size - 1], alloc_check_val); + ((unsigned char *)ptr)[0] = 0; + ((unsigned char *)ptr)[size - 1] = 0; + + umf_result_t ret = umfPoolFree(pool, ptr); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + allocs.erase(it); + } + } + } + + std::cout << "cleanup" << std::endl; + + while (allocs.size()) { + umf_result_t ret = umfPoolFree(pool, (*allocs.begin()).ptr); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + allocs.erase(allocs.begin()); + } + + umfPoolDestroy(pool); + umfMemoryProviderDestroy(coarse_memory_provider); +} + +// negative tests + +TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_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 parameters: given no upstream_memory_provider +// nor init_buffer while exactly one of them must be set +TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_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, disjointCoarseMallocPool_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 + std::unique_ptr buffer(new char[init_buffer_size]); + void *buf = buffer.get(); + ASSERT_NE(buf, nullptr); + memset(buf, 0, init_buffer_size); + + 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, disjointCoarseMallocPool_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, disjointCoarseMallocPool_wrong_params_3) { + umf_result_t umf_result; + + const size_t init_buffer_size = 20 * MB; + + // Preallocate some memory + std::unique_ptr buffer(new char[init_buffer_size]); + void *buf = buffer.get(); + ASSERT_NE(buf, nullptr); + memset(buf, 0, init_buffer_size); + + 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, disjointCoarseMallocPool_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); +} diff --git a/test/supp/helgrind-umf_test-disjointCoarseMallocPool.supp b/test/supp/helgrind-umf_test-disjointCoarseMallocPool.supp new file mode 100644 index 000000000..2f669eb31 --- /dev/null +++ b/test/supp/helgrind-umf_test-disjointCoarseMallocPool.supp @@ -0,0 +1,24 @@ +{ + Incompatibility with helgrind's implementation (pthread_mutex_lock with a pthread_rwlock_t* argument) + Helgrind:Misc + obj:*vgpreload_helgrind-amd64-linux.so + fun:_ZL20__gthread_mutex_lockP15pthread_mutex_t + ... +} + +{ + Incompatibility with helgrind's implementation (pthread_mutex_unlock with a pthread_rwlock_t* argument) + Helgrind:Misc + obj:*vgpreload_helgrind-amd64-linux.so + fun:_ZL22__gthread_mutex_unlockP15pthread_mutex_t + ... +} + +{ + Incompatibility with helgrind's implementation (lock order "0xA before 0xB" violated) + Helgrind:LockOrder + obj:*vgpreload_helgrind-amd64-linux.so + fun:_ZStL23__glibcxx_rwlock_wrlockP16pthread_rwlock_t + fun:_ZNSt22__shared_mutex_pthread4lockEv + ... +} From 2355b9869312cbae8640f94557ae500f3c1125fc Mon Sep 17 00:00:00 2001 From: Nicolas Miller Date: Mon, 7 Oct 2024 16:58:40 +0100 Subject: [PATCH 147/352] Fix build with hwloc support disabled `umfMemspaceCreateFromNumaArray` is defined in `memspaces/memspace_numa.c` which is only added to the build if hwloc is enabled. When hwloc is enabled this is added as an optional symbol to the linker script through `UMF_OPTIONAL_SYMBOLS_LINUX`. When hwloc is disabled this symbol isn't available so this linker script would fail, I believe the correct fix is just to remove the symbol from the linker script. --- src/libumf.map.in | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libumf.map.in b/src/libumf.map.in index 99e45298a..9999d882c 100644 --- a/src/libumf.map.in +++ b/src/libumf.map.in @@ -37,7 +37,6 @@ UMF_1.0 { umfMempolicySetCustomSplitPartitions; umfMempolicySetInterleavePartSize; umfMemspaceClone; - umfMemspaceCreateFromNumaArray; umfMemspaceDestroy; umfMemspaceFilterByCapacity; umfMemspaceFilterById; From 4016c8d85dc814ea4dd33729cf5b6a54dd874f40 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Tue, 8 Oct 2024 11:50:09 +0200 Subject: [PATCH 148/352] Fix missing unlock() in Coarse Provider Signed-off-by: Lukasz Dorau --- src/provider/provider_coarse.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/provider/provider_coarse.c b/src/provider/provider_coarse.c index b404014d8..ce9c54dac 100644 --- a/src/provider/provider_coarse.c +++ b/src/provider/provider_coarse.c @@ -1283,43 +1283,42 @@ static umf_result_t coarse_memory_provider_alloc(void *provider, size_t size, if (coarse_provider->upstream_memory_provider == NULL) { LOG_ERR("out of memory - no upstream memory provider given"); - return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + umf_result = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + 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"); - return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + umf_result = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + 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) { - return umf_result; + if (!coarse_provider->disable_upstream_provider_free) { + 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)); if (utils_mutex_unlock(&coarse_provider->lock) != 0) { LOG_ERR("unlocking the lock failed"); - umf_result = UMF_RESULT_ERROR_UNKNOWN; - goto unlock_error; - } - - return UMF_RESULT_SUCCESS; - -unlock_error: - coarse_ravl_rm(coarse_provider->all_blocks, *resultPtr); - coarse_ravl_rm(coarse_provider->upstream_blocks, *resultPtr); - - if (!coarse_provider->disable_upstream_provider_free) { - umfMemoryProviderFree(coarse_provider->upstream_memory_provider, - *resultPtr, size); + if (umf_result == UMF_RESULT_SUCCESS) { + umf_result = UMF_RESULT_ERROR_UNKNOWN; + } } return umf_result; From 6ce0ee724aae76931d137db0cbc87adc6cf91166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Thu, 3 Oct 2024 12:02:13 +0200 Subject: [PATCH 149/352] [CI] Add Windows icx build in nightly workflow Ref. #772 --- .github/workflows/nightly.yml | 87 +++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 89317cc63..bfb544ada 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -88,3 +88,90 @@ jobs: - name: Run tests under valgrind run: ${{github.workspace}}/test/test_valgrind.sh ${{github.workspace}} ${{github.workspace}}/build ${{matrix.tool}} + + icx: + name: ICX + env: + VCPKG_PATH: "${{github.workspace}}/build/vcpkg/packages/hwloc_x64-windows;${{github.workspace}}/build/vcpkg/packages/tbb_x64-windows;${{github.workspace}}/build/vcpkg/packages/jemalloc_x64-windows" + BUILD_DIR : "${{github.workspace}}/build" + strategy: + matrix: + os: ['windows-2019', 'windows-2022'] + build_type: [Debug] + compiler: [{c: icx, cxx: icx}] + shared_library: ['ON', 'OFF'] + include: + - os: windows-2022 + build_type: Release + compiler: {c: icx, cxx: icx} + shared_library: 'ON' + + runs-on: ${{matrix.os}} + + steps: + - name: Checkout + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + + - name: Initialize vcpkg + uses: lukka/run-vcpkg@5e0cab206a5ea620130caf672fce3e4a6b5666a1 # v11.5 + with: + vcpkgGitCommitId: 3dd44b931481d7a8e9ba412621fa810232b66289 + vcpkgDirectory: ${{env.BUILD_DIR}}/vcpkg + vcpkgJsonGlob: '**/vcpkg.json' + + - name: Install dependencies + run: vcpkg install + + - name: Install Ninja + uses: seanmiddleditch/gha-setup-ninja@96bed6edff20d1dd61ecff9b75cc519d516e6401 # v5 + + - name: Download icx compiler + env: + # Link source: https://www.intel.com/content/www/us/en/developer/tools/oneapi/dpc-compiler-download.html + CMPLR_LINK: "https://registrationcenter-download.intel.com/akdlm/IRC_NAS/15a35578-2f9a-4f39-804b-3906e0a5f8fc/w_dpcpp-cpp-compiler_p_2024.2.1.83_offline.exe" + run: | + Invoke-WebRequest -Uri "${{ env.CMPLR_LINK }}" -OutFile compiler_install.exe + + - name: Install icx compiler + shell: cmd + run: | + start /b /wait .\compiler_install.exe -s -x -f extracted --log extract.log + extracted\bootstrapper.exe -s --action install --eula=accept -p=NEED_VS2017_INTEGRATION=0 ^ + -p=NEED_VS2019_INTEGRATION=0 -p=NEED_VS2022_INTEGRATION=0 --log-dir=. + + - name: Configure build + shell: cmd + run: | + call "C:\Program Files (x86)\Intel\oneAPI\setvars.bat" + call "C:\Program Files (x86)\Intel\oneAPI\setvars-vcvarsall.bat" + cmake ^ + -B ${{env.BUILD_DIR}} ^ + -DCMAKE_PREFIX_PATH="${{env.VCPKG_PATH}}" ^ + -DCMAKE_C_COMPILER=${{matrix.compiler.c}} ^ + -DCMAKE_CXX_COMPILER=${{matrix.compiler.cxx}} ^ + -G Ninja ^ + -DUMF_BUILD_SHARED_LIBRARY=${{matrix.shared_library}} ^ + -DUMF_FORMAT_CODE_STYLE=OFF ^ + -DUMF_DEVELOPER_MODE=ON ^ + -DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON ^ + -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON ^ + -DUMF_BUILD_LEVEL_ZERO_PROVIDER=ON ^ + -DUMF_BUILD_CUDA_PROVIDER=ON ^ + -DUMF_TESTS_FAIL_ON_SKIP=ON + + - name: Build UMF + shell: cmd + run: | + call "C:\Program Files (x86)\Intel\oneAPI\setvars.bat" + call "C:\Program Files (x86)\Intel\oneAPI\setvars-vcvarsall.bat" + cmake --build ${{env.BUILD_DIR}} --config ${{matrix.build_type}} -j %NUMBER_OF_PROCESSORS% + + - name: Run tests + shell: cmd + working-directory: ${{env.BUILD_DIR}} + run: | + call "C:\Program Files (x86)\Intel\oneAPI\setvars.bat" + call "C:\Program Files (x86)\Intel\oneAPI\setvars-vcvarsall.bat" + ctest -C ${{matrix.build_type}} --output-on-failure --test-dir test From b7f5f7869e009f639c2cc4cf345cda20c908346a Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Tue, 8 Oct 2024 15:34:17 +0200 Subject: [PATCH 150/352] Remove unused function get_block_node() Signed-off-by: Lukasz Dorau --- src/provider/provider_coarse.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/provider/provider_coarse.c b/src/provider/provider_coarse.c index b404014d8..8659b8f6f 100644 --- a/src/provider/provider_coarse.c +++ b/src/provider/provider_coarse.c @@ -120,11 +120,6 @@ static int coarse_ravl_comp(const void *lhs, const void *rhs) { return 0; } -static inline ravl_node_t *get_block_node(struct ravl *rtree, block_t *block) { - ravl_data_t rdata = {(uintptr_t)block->data, NULL}; - return ravl_find(rtree, &rdata, RAVL_PREDICATE_EQUAL); -} - static inline block_t *get_node_block(ravl_node_t *node) { ravl_data_t *node_data = ravl_data(node); assert(node_data); From 7e81e7ee1e58a359c86e2d835432f874ebf4f63a Mon Sep 17 00:00:00 2001 From: Rafal Rudnicki Date: Tue, 8 Oct 2024 09:27:11 +0200 Subject: [PATCH 151/352] open_ipc_handle should use shm from handle --- examples/ipc_ipcapi/ipc_ipcapi_shm.sh | 2 +- src/provider/provider_os_memory.c | 37 +++++++------ test/common/ipc_common.c | 75 ++++++++++++++++++++++----- test/ipc_os_prov_shm.sh | 2 +- 4 files changed, 84 insertions(+), 32 deletions(-) diff --git a/examples/ipc_ipcapi/ipc_ipcapi_shm.sh b/examples/ipc_ipcapi/ipc_ipcapi_shm.sh index db310d08d..57a344c1e 100755 --- a/examples/ipc_ipcapi/ipc_ipcapi_shm.sh +++ b/examples/ipc_ipcapi/ipc_ipcapi_shm.sh @@ -20,7 +20,7 @@ UMF_LOG_VAL="level:debug;flush:debug;output:stderr;pid:yes" rm -f /dev/shm/${SHM_NAME} echo "Starting ipc_ipcapi_shm CONSUMER on port $PORT ..." -UMF_LOG=$UMF_LOG_VAL ./umf_example_ipc_ipcapi_consumer $PORT $SHM_NAME & +UMF_LOG=$UMF_LOG_VAL ./umf_example_ipc_ipcapi_consumer $PORT & echo "Waiting 1 sec ..." sleep 1 diff --git a/src/provider/provider_os_memory.c b/src/provider/provider_os_memory.c index fe4ca0460..2279678b6 100644 --- a/src/provider/provider_os_memory.c +++ b/src/provider/provider_os_memory.c @@ -1146,7 +1146,10 @@ typedef struct os_ipc_data_t { int fd; size_t fd_offset; size_t size; - char shm_name[NAME_MAX]; // optional - can be used or not (see below) + // shm_name is a Flexible Array Member because it is optional and its size + // varies on the Shared Memory object name + size_t shm_name_len; + char shm_name[]; } os_ipc_data_t; static umf_result_t os_get_ipc_handle_size(void *provider, size_t *size) { @@ -1160,13 +1163,8 @@ static umf_result_t os_get_ipc_handle_size(void *provider, size_t *size) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - if (os_provider->shm_name[0]) { - // os_ipc_data_t->shm_name will be used - *size = sizeof(os_ipc_data_t); - } else { - // os_ipc_data_t->shm_name will NOT be used - *size = sizeof(os_ipc_data_t) - NAME_MAX; - } + // NOTE: +1 for '\0' at the end of the string + *size = sizeof(os_ipc_data_t) + strlen(os_provider->shm_name) + 1; return UMF_RESULT_SUCCESS; } @@ -1195,9 +1193,10 @@ static umf_result_t os_get_ipc_handle(void *provider, const void *ptr, os_ipc_data->pid = utils_getpid(); os_ipc_data->fd_offset = (size_t)value - 1; os_ipc_data->size = size; - if (os_provider->shm_name[0]) { - strncpy(os_ipc_data->shm_name, os_provider->shm_name, NAME_MAX - 1); - os_ipc_data->shm_name[NAME_MAX - 1] = '\0'; + os_ipc_data->shm_name_len = strlen(os_provider->shm_name); + if (os_ipc_data->shm_name_len > 0) { + strncpy(os_ipc_data->shm_name, os_provider->shm_name, + os_ipc_data->shm_name_len); } else { os_ipc_data->fd = os_provider->fd; } @@ -1222,8 +1221,12 @@ static umf_result_t os_put_ipc_handle(void *provider, void *providerIpcData) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - if (os_provider->shm_name[0]) { - if (strncmp(os_ipc_data->shm_name, os_provider->shm_name, NAME_MAX)) { + size_t shm_name_len = strlen(os_provider->shm_name); + if (shm_name_len > 0) { + if (os_ipc_data->shm_name_len != shm_name_len) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } else if (strncmp(os_ipc_data->shm_name, os_provider->shm_name, + shm_name_len)) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; } } else { @@ -1251,14 +1254,14 @@ static umf_result_t os_open_ipc_handle(void *provider, void *providerIpcData, umf_result_t ret = UMF_RESULT_SUCCESS; int fd; - if (os_provider->shm_name[0]) { - fd = utils_shm_open(os_provider->shm_name); + if (os_ipc_data->shm_name_len) { + fd = utils_shm_open(os_ipc_data->shm_name); if (fd <= 0) { LOG_PERR("opening a shared memory file (%s) failed", - os_provider->shm_name); + os_ipc_data->shm_name); return UMF_RESULT_ERROR_UNKNOWN; } - (void)utils_shm_unlink(os_provider->shm_name); + (void)utils_shm_unlink(os_ipc_data->shm_name); } else { umf_result_t umf_result = utils_duplicate_fd(os_ipc_data->pid, os_ipc_data->fd, &fd); diff --git a/test/common/ipc_common.c b/test/common/ipc_common.c index 18ce263d8..910bb187c 100644 --- a/test/common/ipc_common.c +++ b/test/common/ipc_common.c @@ -15,7 +15,7 @@ #include "ipc_common.h" #define INET_ADDR "127.0.0.1" -#define MSG_SIZE 1024 +#define MSG_SIZE 1024 * 8 // consumer's response message #define CONSUMER_MSG \ @@ -33,6 +33,10 @@ Generally communication between the producer and the consumer looks like: - Producer creates a socket - Producer connects to the consumer - Consumer connects at IP 127.0.0.1 and a port to the producer +- Producer sends the IPC handle size to the consumer +- Consumer receives the IPC handle size from the producer +- Consumer sends the confirmation (IPC handle size) to the producer +- Producer receives the confirmation (IPC handle size) from the consumer - Producer sends the IPC handle to the consumer - Consumer receives the IPC handle from the producer - Consumer opens the IPC handle received from the producer @@ -127,29 +131,36 @@ int run_consumer(int port, umf_memory_provider_ops_t *provider_ops, return -1; } - // get the size of the IPC handle - size_t IPC_handle_size; - umf_result = umfMemoryProviderGetIPCHandleSize(provider, &IPC_handle_size); - if (umf_result != UMF_RESULT_SUCCESS) { - fprintf(stderr, - "[consumer] ERROR: getting size of the IPC handle failed\n"); + producer_socket = consumer_connect(port); + if (producer_socket < 0) { goto err_umfMemoryProviderDestroy; } // allocate the zeroed receive buffer - char *recv_buffer = calloc(1, IPC_handle_size); + char *recv_buffer = calloc(1, MSG_SIZE); if (!recv_buffer) { fprintf(stderr, "[consumer] ERROR: out of memory\n"); goto err_umfMemoryProviderDestroy; } - producer_socket = consumer_connect(port); - if (producer_socket < 0) { - goto err_umfMemoryProviderDestroy; + // get the size of the IPC handle from the producer + size_t IPC_handle_size; + ssize_t recv_len = recv(producer_socket, recv_buffer, MSG_SIZE, 0); + if (recv_len < 0) { + fprintf(stderr, "[consumer] ERROR: recv() failed\n"); + goto err_close_producer_socket; } + IPC_handle_size = *(size_t *)recv_buffer; + fprintf(stderr, "[consumer] Got the size of the IPC handle: %zu\n", + IPC_handle_size); + + // send confirmation to the producer (IPC handle size) + send(producer_socket, &IPC_handle_size, sizeof(IPC_handle_size), 0); + fprintf(stderr, + "[consumer] Send the confirmation (IPC handle size) to producer\n"); - // receive a producer's message - ssize_t recv_len = recv(producer_socket, recv_buffer, IPC_handle_size, 0); + // receive IPC handle from the producer + recv_len = recv(producer_socket, recv_buffer, MSG_SIZE, 0); if (recv_len < 0) { fprintf(stderr, "[consumer] ERROR: recv() failed\n"); goto err_close_producer_socket; @@ -388,6 +399,44 @@ int run_producer(int port, umf_memory_provider_ops_t *provider_ops, goto err_PutIPCHandle; } + // send the IPC_handle_size to the consumer + ssize_t len = + send(producer_socket, &IPC_handle_size, sizeof(IPC_handle_size), 0); + if (len < 0) { + fprintf(stderr, "[producer] ERROR: unable to send the message\n"); + goto err_close_producer_socket; + } + + fprintf(stderr, + "[producer] Sent the size of the IPC handle (%zu) to the consumer " + "(sent %zu bytes)\n", + IPC_handle_size, len); + + // zero the consumer_message buffer + memset(consumer_message, 0, sizeof(consumer_message)); + + // receive the consumer's confirmation - IPC handle size + len = recv(producer_socket, consumer_message, sizeof(consumer_message), 0); + if (len < 0) { + fprintf(stderr, "[producer] ERROR: error while receiving the " + "confirmation from the consumer\n"); + goto err_close_producer_socket; + } + + size_t conf_IPC_handle_size = *(size_t *)consumer_message; + if (conf_IPC_handle_size == IPC_handle_size) { + fprintf(stderr, + "[producer] Received the correct confirmation (%zu) from the " + "consumer (%zu bytes)\n", + conf_IPC_handle_size, len); + } else { + fprintf(stderr, + "[producer] Received an INCORRECT confirmation (%zu) from the " + "consumer (%zu bytes)\n", + conf_IPC_handle_size, len); + goto err_close_producer_socket; + } + // send the IPC_handle of IPC_handle_size to the consumer if (send(producer_socket, IPC_handle, IPC_handle_size, 0) < 0) { fprintf(stderr, "[producer] ERROR: unable to send the message\n"); diff --git a/test/ipc_os_prov_shm.sh b/test/ipc_os_prov_shm.sh index 088d77169..efa2de35a 100755 --- a/test/ipc_os_prov_shm.sh +++ b/test/ipc_os_prov_shm.sh @@ -20,7 +20,7 @@ UMF_LOG_VAL="level:debug;flush:debug;output:stderr;pid:yes" rm -f /dev/shm/${SHM_NAME} echo "Starting ipc_os_prov_shm CONSUMER on port $PORT ..." -UMF_LOG=$UMF_LOG_VAL ./umf_test-ipc_os_prov_consumer $PORT $SHM_NAME & +UMF_LOG=$UMF_LOG_VAL ./umf_test-ipc_os_prov_consumer $PORT & echo "Waiting 1 sec ..." sleep 1 From 7fb8bccb0ca3c0a4518d66dfe5d39d5020e2fb0f Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 9 Oct 2024 10:03:35 +0200 Subject: [PATCH 152/352] Fix: add some missing *_LIBRARY_DIRS to target_link_directories() The following examples: - umf_example_ipc_ipcapi_anon_fd - umf_example_ipc_ipcapi_shm - umf_example_custom_file_provider require TBB and they have to know TBB_LIBRARY_DIRS. The umf_example_dram_and_fsdax example requires HWLOC and it has to know LIBHWLOC_LIBRARY_DIRS. Signed-off-by: Lukasz Dorau --- examples/CMakeLists.txt | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index e681c7ba8..201231676 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -171,7 +171,8 @@ function(build_umf_ipc_example name) ${EX_NAME} PRIVATE ${UMF_CMAKE_SOURCE_DIR}/src/utils ${UMF_CMAKE_SOURCE_DIR}/include) - target_link_directories(${EX_NAME} PRIVATE ${LIBHWLOC_LIBRARY_DIRS}) + target_link_directories(${EX_NAME} PRIVATE ${LIBHWLOC_LIBRARY_DIRS} + ${TBB_LIBRARY_DIRS}) endforeach(loop_var) endfunction() @@ -192,7 +193,7 @@ function(add_umf_ipc_example script) endif() endfunction() -if(LINUX) +if(LINUX AND UMF_POOL_SCALABLE_ENABLED) build_umf_ipc_example(ipc_ipcapi) add_umf_ipc_example(ipc_ipcapi_anon_fd) add_umf_ipc_example(ipc_ipcapi_shm) @@ -252,23 +253,26 @@ if(LINUX) set_tests_properties(${EXAMPLE_NAME} PROPERTIES SKIP_RETURN_CODE ${UMF_TEST_SKIP_RETURN_CODE}) - set(EXAMPLE_NAME umf_example_custom_file_provider) + if(UMF_POOL_SCALABLE_ENABLED) + set(EXAMPLE_NAME umf_example_custom_file_provider) - add_umf_executable( - NAME ${EXAMPLE_NAME} - SRCS custom_file_provider/custom_file_provider.c - LIBS umf ${LIBHWLOC_LIBRARIES}) + add_umf_executable( + NAME ${EXAMPLE_NAME} + SRCS custom_file_provider/custom_file_provider.c + LIBS umf ${LIBHWLOC_LIBRARIES}) - target_include_directories( - ${EXAMPLE_NAME} PRIVATE ${UMF_CMAKE_SOURCE_DIR}/src/utils - ${UMF_CMAKE_SOURCE_DIR}/include) + target_include_directories( + ${EXAMPLE_NAME} PRIVATE ${UMF_CMAKE_SOURCE_DIR}/src/utils + ${UMF_CMAKE_SOURCE_DIR}/include) - target_link_directories(${EXAMPLE_NAME} PRIVATE ${LIBHWLOC_LIBRARY_DIRS}) + target_link_directories(${EXAMPLE_NAME} PRIVATE + ${LIBHWLOC_LIBRARY_DIRS} ${TBB_LIBRARY_DIRS}) - add_test( - NAME ${EXAMPLE_NAME} - COMMAND ${EXAMPLE_NAME} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + add_test( + NAME ${EXAMPLE_NAME} + COMMAND ${EXAMPLE_NAME} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + endif() if(UMF_POOL_JEMALLOC_ENABLED) set(EXAMPLE_NAME umf_example_dram_and_fsdax) @@ -278,6 +282,9 @@ if(LINUX) SRCS dram_and_fsdax/dram_and_fsdax.c LIBS umf jemalloc_pool) + target_link_directories(${EXAMPLE_NAME} PRIVATE + ${LIBHWLOC_LIBRARY_DIRS}) + add_test( NAME ${EXAMPLE_NAME} COMMAND ${EXAMPLE_NAME} From 3a5b33cae24309c82d78e39a2ed1302e9e64d061 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 9 Oct 2024 15:27:31 +0200 Subject: [PATCH 153/352] Implement split()/merge() API of the Coarse provider Signed-off-by: Lukasz Dorau --- src/provider/provider_coarse.c | 190 ++++++++++++++++++++++++++- test/disjointCoarseMallocPool.cpp | 208 ++++++++++++++++++++++++++++++ 2 files changed, 392 insertions(+), 6 deletions(-) diff --git a/src/provider/provider_coarse.c b/src/provider/provider_coarse.c index b404014d8..022c35d76 100644 --- a/src/provider/provider_coarse.c +++ b/src/provider/provider_coarse.c @@ -1209,7 +1209,7 @@ static umf_result_t coarse_memory_provider_alloc(void *provider, size_t size, (struct coarse_memory_provider_t *)provider; if (utils_mutex_lock(&coarse_provider->lock) != 0) { - LOG_ERR("lockng the lock failed"); + LOG_ERR("locking the lock failed"); return UMF_RESULT_ERROR_UNKNOWN; } @@ -1335,7 +1335,7 @@ static umf_result_t coarse_memory_provider_free(void *provider, void *ptr, (struct coarse_memory_provider_t *)provider; if (utils_mutex_lock(&coarse_provider->lock) != 0) { - LOG_ERR("lockng the lock failed"); + LOG_ERR("locking the lock failed"); return UMF_RESULT_ERROR_UNKNOWN; } @@ -1357,7 +1357,12 @@ static umf_result_t coarse_memory_provider_free(void *provider, void *ptr, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - assert(bytes == 0 || bytes == block->size); + 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, @@ -1517,6 +1522,179 @@ coarse_memory_provider_get_stats(void *provider, return UMF_RESULT_SUCCESS; } +static umf_result_t coarse_memory_provider_allocation_split(void *provider, + void *ptr, + size_t totalSize, + size_t firstSize) { + if (provider == NULL || ptr == NULL || (firstSize >= totalSize) || + firstSize == 0) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + 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)); + + if (utils_mutex_unlock(&coarse_provider->lock) != 0) { + LOG_ERR("unlocking the lock failed"); + if (umf_result == UMF_RESULT_SUCCESS) { + umf_result = UMF_RESULT_ERROR_UNKNOWN; + } + } + + return umf_result; +} + +static umf_result_t coarse_memory_provider_allocation_merge(void *provider, + void *lowPtr, + void *highPtr, + size_t totalSize) { + if (provider == NULL || lowPtr == NULL || highPtr == NULL || + ((uintptr_t)highPtr <= (uintptr_t)lowPtr) || + ((uintptr_t)highPtr - (uintptr_t)lowPtr >= totalSize)) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + 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)); + + if (utils_mutex_unlock(&coarse_provider->lock) != 0) { + LOG_ERR("unlocking the lock failed"); + if (umf_result == UMF_RESULT_SUCCESS) { + umf_result = UMF_RESULT_ERROR_UNKNOWN; + } + } + + return umf_result; +} + umf_memory_provider_ops_t UMF_COARSE_MEMORY_PROVIDER_OPS = { .version = UMF_VERSION_CURRENT, .initialize = coarse_memory_provider_initialize, @@ -1528,12 +1706,12 @@ umf_memory_provider_ops_t UMF_COARSE_MEMORY_PROVIDER_OPS = { .get_min_page_size = coarse_memory_provider_get_min_page_size, .get_name = coarse_memory_provider_get_name, .ext.free = coarse_memory_provider_free, + .ext.allocation_merge = coarse_memory_provider_allocation_merge, + .ext.allocation_split = coarse_memory_provider_allocation_split, // TODO /* .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, .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, @@ -1560,7 +1738,7 @@ umfCoarseMemoryProviderGetStats(umf_memory_provider_handle_t provider) { (struct coarse_memory_provider_t *)priv; if (utils_mutex_lock(&coarse_provider->lock) != 0) { - LOG_ERR("lockng the lock failed"); + LOG_ERR("locking the lock failed"); return stats; } diff --git a/test/disjointCoarseMallocPool.cpp b/test/disjointCoarseMallocPool.cpp index 254479a46..b3eb3f91b 100644 --- a/test/disjointCoarseMallocPool.cpp +++ b/test/disjointCoarseMallocPool.cpp @@ -759,3 +759,211 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_wrong_params_4) { umfMemoryProviderDestroy(malloc_memory_provider); } + +TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_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, + disjointCoarseMallocPool_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); +} From 1e1566f941be63dd406428ff5ce9107008284741 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Wed, 9 Oct 2024 13:08:09 +0200 Subject: [PATCH 154/352] Bump pip deps --- .github/workflows/codeql.yml | 5 +++++ third_party/requirements.txt | 18 +++++++++--------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index a44423420..4a8f3ceb5 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -46,6 +46,11 @@ jobs: with: fetch-depth: 0 + - name: Setup newer Python + uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0 + with: + python-version: "3.10" + - name: Initialize CodeQL uses: github/codeql-action/init@b7bf0a3ed3ecfa44160715d7c442788f65f0f923 # v3.23.2 with: diff --git a/third_party/requirements.txt b/third_party/requirements.txt index 8a5f6c4cf..ac316e2ad 100644 --- a/third_party/requirements.txt +++ b/third_party/requirements.txt @@ -4,14 +4,14 @@ clang-format==15.0.7 cmake-format==0.6.13 black==24.3.0 # Tests -packaging==24.0 +packaging==24.1 # Generating HTML documentation -pygments==2.15.1 -sphinxcontrib_applehelp==1.0.4 -sphinxcontrib_devhelp==1.0.2 -sphinxcontrib_htmlhelp==2.0.1 -sphinxcontrib_serializinghtml==1.1.5 -sphinxcontrib_qthelp==1.0.3 +pygments==2.18.0 +sphinxcontrib_applehelp==2.0.0 +sphinxcontrib_devhelp==2.0.0 +sphinxcontrib_htmlhelp==2.1.0 +sphinxcontrib_serializinghtml==2.0.0 +sphinxcontrib_qthelp==2.0.0 breathe==4.35.0 -sphinx==4.5.0 -sphinx_book_theme==0.3.3 +sphinx==8.0.2 +sphinx_book_theme==1.1.3 From aec66c83e098f6d5e6514cfe792fe5ca7a19b228 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Thu, 10 Oct 2024 13:50:02 +0200 Subject: [PATCH 155/352] ifndef NDEBUG get_block_prev() and get_block_next() ifndef NDEBUG get_block_prev() and get_block_next() since get_block_prev() and get_block_next() are used only in Debug build. Signed-off-by: Lukasz Dorau --- src/provider/provider_coarse.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/provider/provider_coarse.c b/src/provider/provider_coarse.c index c8dde0850..0dc674fbb 100644 --- a/src/provider/provider_coarse.c +++ b/src/provider/provider_coarse.c @@ -135,6 +135,7 @@ 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) { @@ -152,6 +153,7 @@ static block_t *get_block_next(ravl_node_t *node) { return get_node_block(ravl_next); } +#endif /* NDEBUG */ static bool is_same_origin(struct ravl *upstream_blocks, block_t *block1, block_t *block2) { From 104dd607a33ac522955077e7df8d04bb6eddc997 Mon Sep 17 00:00:00 2001 From: Rafal Rudnicki Date: Thu, 10 Oct 2024 09:49:08 +0200 Subject: [PATCH 156/352] remove optional symbols --- CMakeLists.txt | 23 ------ cmake/helpers.cmake | 9 --- src/CMakeLists.txt | 91 ++++++++-------------- src/{libumf.def.in => libumf.def} | 15 +++- src/{libumf.map.in => libumf.map} | 13 +++- src/memspaces/memspace_highest_bandwidth.c | 16 ++++ src/memspaces/memspace_highest_capacity.c | 16 ++++ src/memspaces/memspace_host_all.c | 16 ++++ src/memspaces/memspace_lowest_latency.c | 16 ++++ src/memspaces/memspace_numa.c | 20 +++++ src/provider/provider_cuda.c | 11 +++ src/provider/provider_devdax_memory.c | 19 ++++- src/provider/provider_file_memory.c | 19 ++++- src/provider/provider_level_zero.c | 11 +++ src/provider/provider_os_memory.c | 17 +++- 15 files changed, 205 insertions(+), 107 deletions(-) rename src/{libumf.def.in => libumf.def} (85%) rename src/{libumf.map.in => libumf.map} (86%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ce5028c4..280bfd218 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -423,29 +423,6 @@ if((UMF_BUILD_GPU_TESTS OR UMF_BUILD_GPU_EXAMPLES) AND UMF_BUILD_CUDA_PROVIDER) # TODO do the same for ze_loader endif() -# set optional symbols for map/def files -# -# TODO: ref. #649 -set(UMF_OPTIONAL_SYMBOLS_LINUX "") -set(UMF_OPTIONAL_SYMBOLS_WINDOWS "") - -if(UMF_BUILD_LEVEL_ZERO_PROVIDER) - add_optional_symbol(umfLevelZeroMemoryProviderOps) -endif() - -# Conditional configuration for CUDA provider -if(UMF_BUILD_CUDA_PROVIDER) - add_optional_symbol(umfCUDAMemoryProviderOps) -endif() - -if(NOT UMF_DISABLE_HWLOC) - add_optional_symbol(umfOsMemoryProviderOps) - if(LINUX) - add_optional_symbol(umfDevDaxMemoryProviderOps) - add_optional_symbol(umfFileMemoryProviderOps) - endif() -endif() - add_subdirectory(src) if(UMF_BUILD_TESTS) diff --git a/cmake/helpers.cmake b/cmake/helpers.cmake index 8545f285b..a101c8615 100644 --- a/cmake/helpers.cmake +++ b/cmake/helpers.cmake @@ -446,12 +446,3 @@ macro(add_sanitizer_flag flag) set(CMAKE_REQUIRED_FLAGS ${SAVED_CMAKE_REQUIRED_FLAGS}) endmacro() - -function(add_optional_symbol symbol) - set(UMF_OPTIONAL_SYMBOLS_WINDOWS - "${UMF_OPTIONAL_SYMBOLS_WINDOWS} \n ${symbol}" - PARENT_SCOPE) - set(UMF_OPTIONAL_SYMBOLS_LINUX - "${UMF_OPTIONAL_SYMBOLS_LINUX} \n ${symbol};" - PARENT_SCOPE) -endfunction() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fdba77858..873dc6d92 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -110,7 +110,17 @@ set(UMF_SOURCES memtarget.c mempolicy.c memspace.c + memspaces/memspace_host_all.c + memspaces/memspace_highest_capacity.c + 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 + provider/provider_level_zero.c + provider/provider_os_memory.c provider/provider_tracking.c critnib/critnib.c ravl/ravl.c @@ -118,62 +128,35 @@ set(UMF_SOURCES pool/pool_scalable.c) if(NOT UMF_DISABLE_HWLOC) - set(UMF_SOURCES ${UMF_SOURCES} ${HWLOC_DEPENDENT_SOURCES}) + set(UMF_SOURCES ${UMF_SOURCES} ${HWLOC_DEPENDENT_SOURCES} + memtargets/memtarget_numa.c) + set(UMF_LIBS ${UMF_LIBS} ${LIBHWLOC_LIBRARIES}) + set(UMF_PRIVATE_LIBRARY_DIRS ${UMF_PRIVATE_LIBRARY_DIRS} + ${LIBHWLOC_LIBRARY_DIRS}) +else() + set(UMF_COMMON_COMPILE_DEFINITIONS ${UMF_COMMON_COMPILE_DEFINITIONS} + "UMF_NO_HWLOC=1") endif() set(UMF_SOURCES_LINUX libumf_linux.c) - set(UMF_SOURCES_MACOSX libumf_linux.c) - set(UMF_SOURCES_WINDOWS libumf_windows.c) -set(UMF_SOURCES_COMMON_LINUX_MACOSX - provider/provider_devdax_memory.c - provider/provider_file_memory.c - provider/provider_os_memory.c - memtargets/memtarget_numa.c - memspaces/memspace_numa.c - memspaces/memspace_host_all.c - memspaces/memspace_highest_capacity.c - memspaces/memspace_highest_bandwidth.c - memspaces/memspace_lowest_latency.c) - -if(NOT UMF_DISABLE_HWLOC) - set(UMF_SOURCES_LINUX ${UMF_SOURCES_LINUX} - ${UMF_SOURCES_COMMON_LINUX_MACOSX}) - - set(UMF_SOURCES_MACOSX ${UMF_SOURCES_MACOSX} - ${UMF_SOURCES_COMMON_LINUX_MACOSX}) - - set(UMF_SOURCES_WINDOWS ${UMF_SOURCES_WINDOWS} - provider/provider_os_memory.c) - - set(UMF_LIBS ${UMF_LIBS} ${LIBHWLOC_LIBRARIES}) - - if(NOT WINDOWS) - add_optional_symbol(umfMemspaceCreateFromNumaArray) - add_optional_symbol(umfMemspaceHighestBandwidthGet) - add_optional_symbol(umfMemspaceHighestCapacityGet) - add_optional_symbol(umfMemspaceHostAllGet) - add_optional_symbol(umfMemspaceLowestLatencyGet) - endif() +# Add compile definitions to handle unsupported functions +if(NOT UMF_BUILD_CUDA_PROVIDER) + set(UMF_COMMON_COMPILE_DEFINITIONS ${UMF_COMMON_COMPILE_DEFINITIONS} + "UMF_NO_CUDA_PROVIDER=1") endif() - -if(WINDOWS) - message(STATUS "UMF_OPTIONAL_SYMBOLS: ${UMF_OPTIONAL_SYMBOLS_WINDOWS}") -else() - message(STATUS "UMF_OPTIONAL_SYMBOLS: ${UMF_OPTIONAL_SYMBOLS_LINUX}") +if(NOT UMF_BUILD_LEVEL_ZERO_PROVIDER) + set(UMF_COMMON_COMPILE_DEFINITIONS ${UMF_COMMON_COMPILE_DEFINITIONS} + "UMF_NO_LEVEL_ZERO_PROVIDER=1") +endif() +if(UMF_DISABLE_HWLOC OR WINDOWS) + set(UMF_COMMON_COMPILE_DEFINITIONS ${UMF_COMMON_COMPILE_DEFINITIONS} + "UMF_NO_DEVDAX_PROVIDER=1") + set(UMF_COMMON_COMPILE_DEFINITIONS ${UMF_COMMON_COMPILE_DEFINITIONS} + "UMF_NO_FILE_PROVIDER=1") endif() - -# Configure map/def files with optional symbols -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/libumf.def.in" - "${CMAKE_CURRENT_BINARY_DIR}/libumf.def" @ONLY) - -configure_file("${CMAKE_CURRENT_SOURCE_DIR}/libumf.map.in" - "${CMAKE_CURRENT_BINARY_DIR}/libumf.map" @ONLY) - -set(UMF_PRIVATE_LIBRARY_DIRS ${UMF_PRIVATE_LIBRARY_DIRS} - ${LIBHWLOC_LIBRARY_DIRS}) if(LINUX) set(UMF_SOURCES ${UMF_SOURCES} ${UMF_SOURCES_LINUX}) @@ -198,8 +181,8 @@ if(UMF_BUILD_SHARED_LIBRARY) TYPE SHARED SRCS ${UMF_SOURCES} LIBS ${UMF_LIBS} ${HWLOC_LIB} - LINUX_MAP_FILE ${CMAKE_CURRENT_BINARY_DIR}/libumf.map - WINDOWS_DEF_FILE ${CMAKE_CURRENT_BINARY_DIR}/libumf.def) + LINUX_MAP_FILE ${CMAKE_CURRENT_SOURCE_DIR}/libumf.map + WINDOWS_DEF_FILE ${CMAKE_CURRENT_SOURCE_DIR}/libumf.def) set(UMF_COMMON_COMPILE_DEFINITIONS ${UMF_COMMON_COMPILE_DEFINITIONS} "UMF_SHARED_LIBRARY") set_target_properties( @@ -215,11 +198,6 @@ else() LIBS ${UMF_LIBS}) endif() -if(UMF_DISABLE_HWLOC) - set(UMF_COMMON_COMPILE_DEFINITIONS ${UMF_COMMON_COMPILE_DEFINITIONS} - UMF_NO_HWLOC=1) -endif() - if(UMF_LINK_HWLOC_STATICALLY) add_dependencies(umf ${UMF_HWLOC_NAME}) endif() @@ -229,8 +207,6 @@ target_link_directories(umf PRIVATE ${UMF_PRIVATE_LIBRARY_DIRS}) target_compile_definitions(umf PRIVATE ${UMF_COMMON_COMPILE_DEFINITIONS}) if(UMF_BUILD_LEVEL_ZERO_PROVIDER) - target_sources(umf PRIVATE provider/provider_level_zero.c) - if(LINUX) # WA for error ze_api.h:14234:20: no newline at end of file # [-Werror,-Wnewline-eof] @@ -244,7 +220,6 @@ if(UMF_BUILD_LEVEL_ZERO_PROVIDER) endif() if(UMF_BUILD_CUDA_PROVIDER) - target_sources(umf PRIVATE provider/provider_cuda.c) set(UMF_COMPILE_DEFINITIONS ${UMF_COMPILE_DEFINITIONS} "UMF_BUILD_CUDA_PROVIDER=1") endif() diff --git a/src/libumf.def.in b/src/libumf.def similarity index 85% rename from src/libumf.def.in rename to src/libumf.def index 01aaa7e68..979187d96 100644 --- a/src/libumf.def.in +++ b/src/libumf.def @@ -16,10 +16,13 @@ EXPORTS umfCloseIPCHandle umfCoarseMemoryProviderGetStats umfCoarseMemoryProviderOps + umfCUDAMemoryProviderOps + umfDevDaxMemoryProviderOps umfFree + umfFileMemoryProviderOps umfGetIPCHandle umfGetLastFailedMemoryProvider - umfMemoryTrackerGetAllocInfo + umfLevelZeroMemoryProviderOps umfMemoryProviderAlloc umfMemoryProviderAllocationMerge umfMemoryProviderAllocationSplit @@ -38,14 +41,20 @@ EXPORTS umfMemoryProviderPurgeForce umfMemoryProviderPurgeLazy umfMemoryProviderPutIPCHandle + umfMemoryTrackerGetAllocInfo umfMempolicyCreate umfMempolicyDestroy umfMempolicySetCustomSplitPartitions umfMempolicySetInterleavePartSize umfMemspaceClone + umfMemspaceCreateFromNumaArray umfMemspaceDestroy umfMemspaceFilterByCapacity umfMemspaceFilterById + umfMemspaceHighestBandwidthGet + umfMemspaceHighestCapacityGet + umfMemspaceHostAllGet + umfMemspaceLowestLatencyGet umfMemspaceMemtargetAdd umfMemspaceMemtargetGet umfMemspaceMemtargetNum @@ -55,7 +64,8 @@ EXPORTS umfMemtargetGetCapacity umfMemtargetGetId umfMemtargetGetType - umfOpenIPCHandle + umfOpenIPCHandle + umfOsMemoryProviderOps umfPoolAlignedMalloc umfPoolByPtr umfPoolCalloc @@ -72,4 +82,3 @@ EXPORTS umfProxyPoolOps umfPutIPCHandle umfScalablePoolOps - @UMF_OPTIONAL_SYMBOLS_WINDOWS@ diff --git a/src/libumf.map.in b/src/libumf.map similarity index 86% rename from src/libumf.map.in rename to src/libumf.map index 9999d882c..bfca09a27 100644 --- a/src/libumf.map.in +++ b/src/libumf.map @@ -10,10 +10,13 @@ UMF_1.0 { umfCloseIPCHandle; umfCoarseMemoryProviderGetStats; umfCoarseMemoryProviderOps; + umfCUDAMemoryProviderOps; + umfDevDaxMemoryProviderOps; umfFree; + umfFileMemoryProviderOps; umfGetIPCHandle; umfGetLastFailedMemoryProvider; - umfMemoryTrackerGetAllocInfo; + umfLevelZeroMemoryProviderOps; umfMemoryProviderAlloc; umfMemoryProviderAllocationMerge; umfMemoryProviderAllocationSplit; @@ -32,14 +35,20 @@ UMF_1.0 { umfMemoryProviderPurgeForce; umfMemoryProviderPurgeLazy; umfMemoryProviderPutIPCHandle; + umfMemoryTrackerGetAllocInfo; umfMempolicyCreate; umfMempolicyDestroy; umfMempolicySetCustomSplitPartitions; umfMempolicySetInterleavePartSize; umfMemspaceClone; + umfMemspaceCreateFromNumaArray; umfMemspaceDestroy; umfMemspaceFilterByCapacity; umfMemspaceFilterById; + umfMemspaceHighestBandwidthGet; + umfMemspaceHighestCapacityGet; + umfMemspaceHostAllGet; + umfMemspaceLowestLatencyGet; umfMemspaceMemtargetAdd; umfMemspaceMemtargetGet; umfMemspaceMemtargetNum; @@ -50,6 +59,7 @@ UMF_1.0 { umfMemtargetGetId; umfMemtargetGetType; umfOpenIPCHandle; + umfOsMemoryProviderOps; umfPoolAlignedMalloc; umfPoolByPtr; umfPoolCalloc; @@ -66,7 +76,6 @@ UMF_1.0 { umfProxyPoolOps; umfPutIPCHandle; umfScalablePoolOps; - @UMF_OPTIONAL_SYMBOLS_LINUX@ local: *; }; diff --git a/src/memspaces/memspace_highest_bandwidth.c b/src/memspaces/memspace_highest_bandwidth.c index a6ea558d7..93fede2cd 100644 --- a/src/memspaces/memspace_highest_bandwidth.c +++ b/src/memspaces/memspace_highest_bandwidth.c @@ -11,6 +11,20 @@ #include #include +#include +#include + +// UMF_MEMSPACE_HIGHEST_BANDWIDTH requires HWLOC +// Additionally, it is currently unsupported on Win +#if defined(_WIN32) || defined(UMF_NO_HWLOC) + +umf_const_memspace_handle_t umfMemspaceHighestBandwidthGet(void) { + // not supported + return NULL; +} + +#else // !defined(_WIN32) && !defined(UMF_NO_HWLOC) + #include "base_alloc_global.h" #include "memspace_internal.h" #include "memtarget_numa.h" @@ -100,3 +114,5 @@ umf_const_memspace_handle_t umfMemspaceHighestBandwidthGet(void) { umfMemspaceHighestBandwidthInit); return UMF_MEMSPACE_HIGHEST_BANDWIDTH; } + +#endif // !defined(_WIN32) && !defined(UMF_NO_HWLOC) diff --git a/src/memspaces/memspace_highest_capacity.c b/src/memspaces/memspace_highest_capacity.c index 8a4e19148..4a195316a 100644 --- a/src/memspaces/memspace_highest_capacity.c +++ b/src/memspaces/memspace_highest_capacity.c @@ -10,6 +10,20 @@ #include #include +#include +#include + +// UMF_MEMSPACE_HIGHEST_CAPACITY requires HWLOC +// Additionally, it is currently unsupported on Win +#if defined(_WIN32) || defined(UMF_NO_HWLOC) + +umf_const_memspace_handle_t umfMemspaceHighestCapacityGet(void) { + // not supported + return NULL; +} + +#else // !defined(_WIN32) && !defined(UMF_NO_HWLOC) + #include "base_alloc_global.h" #include "memspace_internal.h" #include "memtarget_numa.h" @@ -72,3 +86,5 @@ umf_const_memspace_handle_t umfMemspaceHighestCapacityGet(void) { umfMemspaceHighestCapacityInit); return UMF_MEMSPACE_HIGHEST_CAPACITY; } + +#endif // !defined(_WIN32) && !defined(UMF_NO_HWLOC) diff --git a/src/memspaces/memspace_host_all.c b/src/memspaces/memspace_host_all.c index 09d5877c3..4b7db69d4 100644 --- a/src/memspaces/memspace_host_all.c +++ b/src/memspaces/memspace_host_all.c @@ -10,6 +10,20 @@ #include #include +#include +#include + +// UMF_MEMSPACE_HOST_ALL requires HWLOC +// Additionally, it is currently unsupported on Win + +#if defined(_WIN32) || defined(UMF_NO_HWLOC) +umf_const_memspace_handle_t umfMemspaceHostAllGet(void) { + // not supported + return NULL; +} + +#else // !defined(_WIN32) && !defined(UMF_NO_HWLOC) + #include "base_alloc_global.h" #include "memspace_internal.h" #include "memtarget_numa.h" @@ -93,3 +107,5 @@ umf_const_memspace_handle_t umfMemspaceHostAllGet(void) { utils_init_once(&UMF_MEMSPACE_HOST_ALL_INITIALIZED, umfMemspaceHostAllInit); return UMF_MEMSPACE_HOST_ALL; } + +#endif // !defined(_WIN32) && !defined(UMF_NO_HWLOC) diff --git a/src/memspaces/memspace_lowest_latency.c b/src/memspaces/memspace_lowest_latency.c index 52f8e7f36..5ca369fee 100644 --- a/src/memspaces/memspace_lowest_latency.c +++ b/src/memspaces/memspace_lowest_latency.c @@ -11,6 +11,20 @@ #include #include +#include +#include + +// UMF_MEMSPACE_LOWEST_LATENCY requires HWLOC +// Additionally, it is currently unsupported on Win +#if defined(_WIN32) || defined(UMF_NO_HWLOC) + +umf_const_memspace_handle_t umfMemspaceLowestLatencyGet(void) { + // not supported + return NULL; +} + +#else // !defined(_WIN32) && !defined(UMF_NO_HWLOC) + #include "base_alloc_global.h" #include "memspace_internal.h" #include "memtarget_numa.h" @@ -100,3 +114,5 @@ umf_const_memspace_handle_t umfMemspaceLowestLatencyGet(void) { umfMemspaceLowestLatencyInit); return UMF_MEMSPACE_LOWEST_LATENCY; } + +#endif // !defined(_WIN32) && !defined(UMF_NO_HWLOC) diff --git a/src/memspaces/memspace_numa.c b/src/memspaces/memspace_numa.c index 306851d7c..0028e394d 100644 --- a/src/memspaces/memspace_numa.c +++ b/src/memspaces/memspace_numa.c @@ -9,6 +9,24 @@ #include +#include +#include + +// umfMemspaceCreateFromNumaArray requires HWLOC +// Additionally, it is currently unsupported on Win +#if defined(_WIN32) || defined(UMF_NO_HWLOC) +umf_result_t umfMemspaceCreateFromNumaArray(unsigned *nodeIds, size_t numIds, + umf_memspace_handle_t *hMemspace) { + (void)nodeIds; + (void)numIds; + (void)hMemspace; + + // not supported + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + +#else // !defined(_WIN32) && !defined(UMF_NO_HWLOC) + #include "../memspace_internal.h" #include "../memtargets/memtarget_numa.h" #include "base_alloc_global.h" @@ -57,3 +75,5 @@ umf_result_t umfMemspaceCreateFromNumaArray(unsigned *nodeIds, size_t numIds, umf_ba_global_free(memspace); return ret; } + +#endif // !defined(_WIN32) && !defined(UMF_NO_HWLOC) diff --git a/src/provider/provider_cuda.c b/src/provider/provider_cuda.c index 22dfc49f1..85d6d9b79 100644 --- a/src/provider/provider_cuda.c +++ b/src/provider/provider_cuda.c @@ -12,6 +12,15 @@ #include #include +#if defined(UMF_NO_CUDA_PROVIDER) + +umf_memory_provider_ops_t *umfCUDAMemoryProviderOps(void) { + // not supported + return NULL; +} + +#else // !defined(UMF_NO_CUDA_PROVIDER) + #include "cuda.h" #include "base_alloc_global.h" @@ -370,3 +379,5 @@ static struct umf_memory_provider_ops_t UMF_CUDA_MEMORY_PROVIDER_OPS = { umf_memory_provider_ops_t *umfCUDAMemoryProviderOps(void) { return &UMF_CUDA_MEMORY_PROVIDER_OPS; } + +#endif // !defined(UMF_NO_CUDA_PROVIDER) diff --git a/src/provider/provider_devdax_memory.c b/src/provider/provider_devdax_memory.c index 0127f75ae..544960995 100644 --- a/src/provider/provider_devdax_memory.c +++ b/src/provider/provider_devdax_memory.c @@ -13,15 +13,24 @@ #include #include +#include +#include +#include + +#if defined(_WIN32) || defined(UMF_NO_HWLOC) + +umf_memory_provider_ops_t *umfDevDaxMemoryProviderOps(void) { + // not supported + return NULL; +} + +#else // !defined(_WIN32) && !defined(UMF_NO_HWLOC) + #include "base_alloc_global.h" #include "utils_common.h" #include "utils_concurrency.h" #include "utils_log.h" -#include -#include -#include - #define NODESET_STR_BUF_LEN 1024 #define TLS_MSG_BUF_LEN 1024 @@ -528,3 +537,5 @@ static umf_memory_provider_ops_t UMF_DEVDAX_MEMORY_PROVIDER_OPS = { umf_memory_provider_ops_t *umfDevDaxMemoryProviderOps(void) { return &UMF_DEVDAX_MEMORY_PROVIDER_OPS; } + +#endif // !defined(_WIN32) && !defined(UMF_NO_HWLOC) diff --git a/src/provider/provider_file_memory.c b/src/provider/provider_file_memory.c index b89e6bd86..bb8cad2e3 100644 --- a/src/provider/provider_file_memory.c +++ b/src/provider/provider_file_memory.c @@ -14,16 +14,25 @@ #include #include +#include +#include +#include + +#if defined(_WIN32) || defined(UMF_NO_HWLOC) + +umf_memory_provider_ops_t *umfFileMemoryProviderOps(void) { + // not supported + return NULL; +} + +#else // !defined(_WIN32) && !defined(UMF_NO_HWLOC) + #include "base_alloc_global.h" #include "critnib.h" #include "utils_common.h" #include "utils_concurrency.h" #include "utils_log.h" -#include -#include -#include - #define TLS_MSG_BUF_LEN 1024 typedef struct file_memory_provider_t { @@ -696,3 +705,5 @@ static umf_memory_provider_ops_t UMF_FILE_MEMORY_PROVIDER_OPS = { umf_memory_provider_ops_t *umfFileMemoryProviderOps(void) { return &UMF_FILE_MEMORY_PROVIDER_OPS; } + +#endif // !defined(_WIN32) && !defined(UMF_NO_HWLOC) diff --git a/src/provider/provider_level_zero.c b/src/provider/provider_level_zero.c index 6b6cc2e2c..3f122cd6a 100644 --- a/src/provider/provider_level_zero.c +++ b/src/provider/provider_level_zero.c @@ -14,6 +14,15 @@ #include #include +#if defined(UMF_NO_LEVEL_ZERO_PROVIDER) + +umf_memory_provider_ops_t *umfLevelZeroMemoryProviderOps(void) { + // not supported + return NULL; +} + +#else // !defined(UMF_NO_LEVEL_ZERO_PROVIDER) + #include "base_alloc_global.h" #include "utils_assert.h" #include "utils_common.h" @@ -564,3 +573,5 @@ static struct umf_memory_provider_ops_t UMF_LEVEL_ZERO_MEMORY_PROVIDER_OPS = { umf_memory_provider_ops_t *umfLevelZeroMemoryProviderOps(void) { return &UMF_LEVEL_ZERO_MEMORY_PROVIDER_OPS; } + +#endif // !defined(UMF_NO_LEVEL_ZERO_PROVIDER) diff --git a/src/provider/provider_os_memory.c b/src/provider/provider_os_memory.c index 2279678b6..3318beef0 100644 --- a/src/provider/provider_os_memory.c +++ b/src/provider/provider_os_memory.c @@ -13,6 +13,17 @@ #include #include +#include +#include +#include + +// OS Memory Provider requires HWLOC +#if defined(UMF_NO_HWLOC) + +umf_memory_provider_ops_t *umfOsMemoryProviderOps(void) { return NULL; } + +#else // !defined(UMF_NO_HWLOC) + #include "base_alloc_global.h" #include "critnib.h" #include "provider_os_memory_internal.h" @@ -20,10 +31,6 @@ #include "utils_concurrency.h" #include "utils_log.h" -#include -#include -#include - #define NODESET_STR_BUF_LEN 1024 #define TLS_MSG_BUF_LEN 1024 @@ -1332,3 +1339,5 @@ static umf_memory_provider_ops_t UMF_OS_MEMORY_PROVIDER_OPS = { umf_memory_provider_ops_t *umfOsMemoryProviderOps(void) { return &UMF_OS_MEMORY_PROVIDER_OPS; } + +#endif // !defined(UMF_NO_HWLOC) From 439ea94a971be6e4adbd8e976c552b9ee541b135 Mon Sep 17 00:00:00 2001 From: Sergei Vinogradov Date: Sun, 13 Oct 2024 01:47:27 +0200 Subject: [PATCH 157/352] Fix umfPoolDestroy to destroy providers in the right order --- src/memory_pool.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/memory_pool.c b/src/memory_pool.c index c45ddafe7..4a85955ef 100644 --- a/src/memory_pool.c +++ b/src/memory_pool.c @@ -76,18 +76,20 @@ static umf_result_t umfPoolCreateInternal(const umf_memory_pool_ops_t *ops, void umfPoolDestroy(umf_memory_pool_handle_t hPool) { hPool->ops.finalize(hPool->pool_priv); - if (hPool->flags & UMF_POOL_CREATE_FLAG_OWN_PROVIDER) { - // Destroy associated memory provider. - umf_memory_provider_handle_t hProvider = NULL; - umfPoolGetMemoryProvider(hPool, &hProvider); - umfMemoryProviderDestroy(hProvider); - } + + umf_memory_provider_handle_t hUpstreamProvider = NULL; + umfPoolGetMemoryProvider(hPool, &hUpstreamProvider); if (!(hPool->flags & UMF_POOL_CREATE_FLAG_DISABLE_TRACKING)) { // Destroy tracking provider. umfMemoryProviderDestroy(hPool->provider); } + if (hPool->flags & UMF_POOL_CREATE_FLAG_OWN_PROVIDER) { + // Destroy associated memory provider. + umfMemoryProviderDestroy(hUpstreamProvider); + } + LOG_INFO("Memory pool destroyed: %p", (void *)hPool); // TODO: this free keeps memory in base allocator, so it can lead to OOM in some scenarios (it should be optimized) From 4ff667bdd4daecef5e4c371df6112dac8de2ce95 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 14 Oct 2024 10:25:34 +0200 Subject: [PATCH 158/352] Fix: add missing header stdexcept in benchmark/multithread.hpp Signed-off-by: Lukasz Dorau --- benchmark/multithread.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/benchmark/multithread.hpp b/benchmark/multithread.hpp index e642d2987..a3ba37541 100644 --- a/benchmark/multithread.hpp +++ b/benchmark/multithread.hpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include From 50f7d22602566fe2a66037237256b1083d961af9 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 14 Oct 2024 12:02:20 +0200 Subject: [PATCH 159/352] Add missing tests for the proxy library Signed-off-by: Lukasz Dorau --- .github/workflows/proxy_lib.yml | 4 +-- test/test_proxy_lib.cpp | 55 +++++++++++++++++++++++++++++++-- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/.github/workflows/proxy_lib.yml b/.github/workflows/proxy_lib.yml index 678b40eff..581819c49 100644 --- a/.github/workflows/proxy_lib.yml +++ b/.github/workflows/proxy_lib.yml @@ -66,8 +66,8 @@ jobs: - name: Run "/usr/bin/ls" with proxy library working-directory: ${{env.BUILD_DIR}} - run: LD_PRELOAD=./lib/libumf_proxy.so /usr/bin/ls + run: UMF_PROXY="page.disposition=shared-fd" LD_PRELOAD=./lib/libumf_proxy.so /usr/bin/ls - name: Run "/usr/bin/date" with proxy library working-directory: ${{env.BUILD_DIR}} - run: LD_PRELOAD=./lib/libumf_proxy.so /usr/bin/date + run: UMF_PROXY="page.disposition=shared-shm" LD_PRELOAD=./lib/libumf_proxy.so /usr/bin/date diff --git a/test/test_proxy_lib.cpp b/test/test_proxy_lib.cpp index 557698117..85afc65be 100644 --- a/test/test_proxy_lib.cpp +++ b/test/test_proxy_lib.cpp @@ -15,15 +15,20 @@ #include "base.hpp" #include "test_helpers.h" +#include "utils_common.h" using umf_test::test; -TEST_F(test, proxyLibBasic) { +#define SIZE_64 64 +#define ALIGN_1024 1024 - ::free(::malloc(64)); +TEST_F(test, proxyLib_basic) { + + ::free(::malloc(SIZE_64)); // a check to verify we are running the proxy library void *ptr = (void *)0x01; + #ifdef _WIN32 size_t size = _msize(ptr); #elif __APPLE__ @@ -31,5 +36,51 @@ TEST_F(test, proxyLibBasic) { #else size_t size = ::malloc_usable_size(ptr); #endif + ASSERT_EQ(size, 0xDEADBEEF); } + +TEST_F(test, proxyLib_realloc_size0) { + // realloc(ptr, 0) == free (ptr) + // realloc(ptr, 0) returns NULL + ASSERT_EQ(::realloc(::malloc(SIZE_64), 0), nullptr); +} + +TEST_F(test, proxyLib_malloc_usable_size) { + + void *ptr = ::malloc(SIZE_64); + ASSERT_NE(ptr, nullptr); + if (ptr == nullptr) { + // Fix for the following CodeQL's warning on Windows: + // 'ptr' could be '0': this does not adhere to the specification for the function '_msize'. + return; + } + +#ifdef _WIN32 + size_t size = _msize(ptr); +#elif __APPLE__ + size_t size = ::malloc_size(ptr); +#else + size_t size = ::malloc_usable_size(ptr); +#endif + + ASSERT_EQ((int)(size == 0 || size >= SIZE_64), 1); + + ::free(ptr); +} + +TEST_F(test, proxyLib_aligned_alloc) { +#ifdef _WIN32 + void *ptr = _aligned_malloc(SIZE_64, ALIGN_1024); +#else + void *ptr = ::aligned_alloc(ALIGN_1024, SIZE_64); +#endif + + ASSERT_EQ((int)(IS_ALIGNED((uintptr_t)ptr, ALIGN_1024)), 1); + +#ifdef _WIN32 + _aligned_free(ptr); +#else + ::free(ptr); +#endif +} From ded84af1d5a7cec53fec61af16d78e94f06b8830 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Mon, 14 Oct 2024 12:46:01 +0200 Subject: [PATCH 160/352] Add new IPC test: openInTwoPools --- test/ipcFixtures.hpp | 53 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/test/ipcFixtures.hpp b/test/ipcFixtures.hpp index cd8905008..22d687eac 100644 --- a/test/ipcFixtures.hpp +++ b/test/ipcFixtures.hpp @@ -335,6 +335,59 @@ TEST_P(umfIpcTest, AllocFreeAllocTest) { EXPECT_EQ(stat.openCount, stat.closeCount); } +TEST_P(umfIpcTest, openInTwoPools) { + constexpr size_t SIZE = 100; + std::vector expected_data(SIZE); + umf::pool_unique_handle_t pool1 = makePool(); + umf::pool_unique_handle_t pool2 = makePool(); + void *ptr = umfPoolMalloc(pool1.get(), sizeof(expected_data[0]) * SIZE); + EXPECT_NE(ptr, nullptr); + + std::iota(expected_data.begin(), expected_data.end(), 0); + memAccessor->copy(ptr, expected_data.data(), SIZE * sizeof(int)); + + umf_ipc_handle_t ipcHandle = nullptr; + size_t handleSize = 0; + umf_result_t ret = umfGetIPCHandle(ptr, &ipcHandle, &handleSize); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + void *openedPtr1 = nullptr; + ret = umfOpenIPCHandle(pool1.get(), ipcHandle, &openedPtr1); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + void *openedPtr2 = nullptr; + ret = umfOpenIPCHandle(pool2.get(), ipcHandle, &openedPtr2); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + ret = umfPutIPCHandle(ipcHandle); + EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + + std::vector actual_data(SIZE); + memAccessor->copy(actual_data.data(), openedPtr1, SIZE * sizeof(int)); + ASSERT_TRUE(std::equal(expected_data.begin(), expected_data.end(), + actual_data.begin())); + + ret = umfCloseIPCHandle(openedPtr1); + EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + + memAccessor->copy(actual_data.data(), openedPtr2, SIZE * sizeof(int)); + ASSERT_TRUE(std::equal(expected_data.begin(), expected_data.end(), + actual_data.begin())); + + ret = umfCloseIPCHandle(openedPtr2); + EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + + ret = umfPoolFree(pool1.get(), ptr); + EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + + pool1.reset(nullptr); + pool2.reset(nullptr); + EXPECT_EQ(stat.getCount, 1); + EXPECT_EQ(stat.putCount, stat.getCount); + EXPECT_EQ(stat.openCount, 2); + EXPECT_EQ(stat.closeCount, stat.openCount); +} + TEST_P(umfIpcTest, ConcurrentGetPutHandles) { std::vector ptrs; constexpr size_t ALLOC_SIZE = 100; From 12a2b86ebeab57424013d7a099af20639204eaed Mon Sep 17 00:00:00 2001 From: Agata Momot Date: Thu, 19 Sep 2024 12:36:57 +0000 Subject: [PATCH 161/352] fix: segfault in src/memory_provider.c --- src/memory_provider.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/memory_provider.c b/src/memory_provider.c index 1e47a248a..3d823a4a8 100644 --- a/src/memory_provider.c +++ b/src/memory_provider.c @@ -209,8 +209,10 @@ umf_result_t umfMemoryProviderCreate(const umf_memory_provider_ops_t *ops, } void umfMemoryProviderDestroy(umf_memory_provider_handle_t hProvider) { - hProvider->ops.finalize(hProvider->provider_priv); - umf_ba_global_free(hProvider); + if (hProvider) { + hProvider->ops.finalize(hProvider->provider_priv); + umf_ba_global_free(hProvider); + } } static void From ced30bb874e37982ea738009c4c5bde502f8c710 Mon Sep 17 00:00:00 2001 From: Agata Momot Date: Mon, 14 Oct 2024 15:27:17 +0200 Subject: [PATCH 162/352] fix: replace UT_ASSERTs with GTEST asserts If possible, change non-void functions to void by passing pointers Otherwise, introduce error-indicating return values Ref. #569 --- test/memspaces/memspace_highest_capacity.cpp | 2 +- ...provider_os_memory_multiple_numa_nodes.cpp | 52 ++++++++++++++----- 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/test/memspaces/memspace_highest_capacity.cpp b/test/memspaces/memspace_highest_capacity.cpp index 59ee61649..8452e74a7 100644 --- a/test/memspaces/memspace_highest_capacity.cpp +++ b/test/memspaces/memspace_highest_capacity.cpp @@ -21,7 +21,7 @@ struct memspaceHighestCapacityProviderTest : ::numaNodesTest { ::numaNodesTest::SetUp(); umf_const_memspace_handle_t hMemspace = umfMemspaceHighestCapacityGet(); - UT_ASSERTne(hMemspace, nullptr); + ASSERT_NE(hMemspace, nullptr); umf_result_t ret = umfMemoryProviderCreateFromMemspace(hMemspace, nullptr, &hProvider); diff --git a/test/provider_os_memory_multiple_numa_nodes.cpp b/test/provider_os_memory_multiple_numa_nodes.cpp index 3359b003d..8c771a642 100644 --- a/test/provider_os_memory_multiple_numa_nodes.cpp +++ b/test/provider_os_memory_multiple_numa_nodes.cpp @@ -42,7 +42,14 @@ std::vector get_available_cpus() { CPU_ZERO(mask); int ret = sched_getaffinity(0, sizeof(cpu_set_t), mask); - UT_ASSERTeq(ret, 0); + + if (ret != 0) { + available_cpus.emplace_back(-1); + CPU_FREE(mask); + + return available_cpus; + } + // Get all available cpus. printf("All CPUs: "); for (size_t i = 0; i < CPU_SETSIZE; ++i) { @@ -88,13 +95,16 @@ struct testNuma : testing::Test { ASSERT_NE(os_memory_provider, nullptr); } - struct bitmask *retrieve_nodemask(void *addr) { - struct bitmask *retrieved_nodemask = numa_allocate_nodemask(); - UT_ASSERTne(nodemask, nullptr); - int ret = get_mempolicy(nullptr, retrieved_nodemask->maskp, + void retrieve_nodemask(void *addr, bitmask **retrieved_nodemask) { + *retrieved_nodemask = numa_allocate_nodemask(); + + ASSERT_NE(nodemask, nullptr); + ASSERT_NE(*retrieved_nodemask, nullptr); + + int ret = get_mempolicy(nullptr, (*retrieved_nodemask)->maskp, nodemask->size, addr, MPOL_F_ADDR); - UT_ASSERTeq(ret, 0); - return retrieved_nodemask; + + ASSERT_EQ(ret, 0); } void TearDown() override { @@ -241,7 +251,17 @@ TEST_P(testNumaOnEachNode, checkModeInterleaveSingleNode) { EXPECT_NODE_EQ(ptr, numa_node_number); } -struct testNumaOnEachCpu : testNuma, testing::WithParamInterface {}; +struct testNumaOnEachCpu : testNuma, testing::WithParamInterface { + void SetUp() override { + ::testNuma::SetUp(); + + int cpuNumber = this->GetParam(); + + if (cpuNumber < 0) { + GTEST_FAIL() << "get_available_cpus() error"; + } + } +}; INSTANTIATE_TEST_SUITE_P(testNumaNodesAllocationsAllCpus, testNumaOnEachCpu, ::testing::ValuesIn(get_available_cpus())); @@ -260,7 +280,7 @@ TEST_P(testNumaOnEachCpu, checkModePreferredEmptyNodeset) { int ret = sched_setaffinity(0, sizeof(cpu_set_t), mask); CPU_FREE(mask); - UT_ASSERTeq(ret, 0); + ASSERT_EQ(ret, 0); umf_os_memory_provider_params_t os_memory_provider_params = UMF_OS_MEMORY_PROVIDER_PARAMS_TEST; @@ -275,7 +295,7 @@ TEST_P(testNumaOnEachCpu, checkModePreferredEmptyNodeset) { // Verify we're on the expected CPU int cpu_check = sched_getcpu(); - UT_ASSERTeq(cpu, cpu_check); + ASSERT_EQ(cpu, cpu_check); int numa_node_number = numa_node_of_cpu(cpu); printf("Got CPU: %d, got numa node: %d\n", cpu, numa_node_number); @@ -297,7 +317,7 @@ TEST_P(testNumaOnEachCpu, checkModeLocal) { int ret = sched_setaffinity(0, sizeof(cpu_set_t), mask); CPU_FREE(mask); - UT_ASSERTeq(ret, 0); + ASSERT_EQ(ret, 0); umf_os_memory_provider_params_t os_memory_provider_params = UMF_OS_MEMORY_PROVIDER_PARAMS_TEST; @@ -312,7 +332,7 @@ TEST_P(testNumaOnEachCpu, checkModeLocal) { // Verify we're on the expected CPU int cpu_check = sched_getcpu(); - UT_ASSERTeq(cpu, cpu_check); + ASSERT_EQ(cpu, cpu_check); int numa_node_number = numa_node_of_cpu(cpu); printf("Got CPU: %d, got numa node: %d\n", cpu, numa_node_number); @@ -391,7 +411,13 @@ TEST_F(testNuma, checkModeInterleave) { EXPECT_NODE_EQ((char *)ptr + page_size * i, numa_nodes[index]); } - bitmask *retrieved_nodemask = retrieve_nodemask(ptr); + bitmask *retrieved_nodemask = nullptr; + retrieve_nodemask(ptr, &retrieved_nodemask); + + if (IS_SKIPPED_OR_FAILED()) { + return; + } + int ret = numa_bitmask_equal(retrieved_nodemask, nodemask); numa_bitmask_free(retrieved_nodemask); From 8976dbb20f05f0b00dc7f49daa7015b312b985ce Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Oct 2024 22:10:01 +0000 Subject: [PATCH 163/352] Bump sphinx Bumps the pip-dependencies group with 1 update in the /third_party directory: [sphinx](https://github.com/sphinx-doc/sphinx). Updates `sphinx` from 8.0.2 to 8.1.3 - [Release notes](https://github.com/sphinx-doc/sphinx/releases) - [Changelog](https://github.com/sphinx-doc/sphinx/blob/master/CHANGES.rst) - [Commits](https://github.com/sphinx-doc/sphinx/compare/v8.0.2...v8.1.3) --- updated-dependencies: - dependency-name: sphinx dependency-type: direct:production update-type: version-update:semver-minor dependency-group: pip-dependencies ... Signed-off-by: dependabot[bot] --- third_party/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/requirements.txt b/third_party/requirements.txt index ac316e2ad..17be62608 100644 --- a/third_party/requirements.txt +++ b/third_party/requirements.txt @@ -13,5 +13,5 @@ sphinxcontrib_htmlhelp==2.1.0 sphinxcontrib_serializinghtml==2.0.0 sphinxcontrib_qthelp==2.0.0 breathe==4.35.0 -sphinx==8.0.2 +sphinx==8.1.3 sphinx_book_theme==1.1.3 From 9a796443a4373cb52be01afe4e99b304c023241e Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Tue, 15 Oct 2024 12:55:16 +0200 Subject: [PATCH 164/352] Rename UMF_USE_GCOV to UMF_USE_COVERAGE Signed-off-by: Lukasz Dorau --- CMakeLists.txt | 2 +- CONTRIBUTING.md | 4 ++-- README.md | 2 +- cmake/helpers.cmake | 13 +++++++++---- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 280bfd218..42eeb50eb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,7 +71,7 @@ option(UMF_USE_UBSAN "Enable UndefinedBehaviorSanitizer checks" OFF) option(UMF_USE_TSAN "Enable ThreadSanitizer checks" OFF) option(UMF_USE_MSAN "Enable MemorySanitizer checks" OFF) option(UMF_USE_VALGRIND "Enable Valgrind instrumentation" OFF) -option(UMF_USE_GCOV "Enable gcov support" OFF) +option(UMF_USE_COVERAGE "Build with coverage enabled (Linux only)" OFF) # set UMF_PROXY_LIB_BASED_ON_POOL to one of: SCALABLE or JEMALLOC set(KNOWN_PROXY_LIB_POOLS SCALABLE JEMALLOC) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 48eb62579..cd4a2a790 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -209,12 +209,12 @@ origin: https://dependency_origin.com ## Code coverage After adding a new functionality add tests and check coverage before and after the change. -To do this, enable coverage instrumentation by turning on the UMF_USE_GCOV flag in CMake. +To do this, enable coverage instrumentation by turning on the UMF_USE_COVERAGE flag in CMake. Coverage instrumentation feature is supported only by GCC and Clang. An example flow might look like the following: ```bash -$ cmake -B build -DUMF_USE_GCOV=1 -DCMAKE_BUILD_TYPE=Debug +$ cmake -B build -DUMF_USE_COVERAGE=1 -DCMAKE_BUILD_TYPE=Debug $ cmake --build build -j $ cd build $ ctest diff --git a/README.md b/README.md index 0d2587f4e..2c4146dc6 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,7 @@ List of options provided by CMake: | UMF_USE_TSAN | Enable ThreadSanitizer checks | ON/OFF | OFF | | UMF_USE_MSAN | Enable MemorySanitizer checks | ON/OFF | OFF | | UMF_USE_VALGRIND | Enable Valgrind instrumentation | ON/OFF | OFF | -| UMF_USE_GCOV | Enable gcov support (Linux only) | ON/OFF | OFF | +| UMF_USE_COVERAGE | Build with coverage enabled (Linux only) | ON/OFF | OFF | | UMF_LINK_HWLOC_STATICALLY | Link UMF with HWLOC library statically (Windows+Release only) | ON/OFF | OFF | | UMF_DISABLE_HWLOC | Disable features that requires hwloc (OS provider, memory targets, topology discovery) | ON/OFF | OFF | diff --git a/cmake/helpers.cmake b/cmake/helpers.cmake index a101c8615..4ea8e417e 100644 --- a/cmake/helpers.cmake +++ b/cmake/helpers.cmake @@ -247,9 +247,12 @@ function(add_umf_target_compile_options name) target_compile_options(${name} PRIVATE -fno-omit-frame-pointer -fstack-protector-strong) endif() - if(UMF_USE_GCOV) + if(UMF_USE_COVERAGE) if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") - message(FATAL_ERROR "To use gcov, the build type must be Debug") + message( + FATAL_ERROR + "To use the --coverage flag, the build type must be Debug" + ) endif() target_compile_options(${name} PRIVATE --coverage) endif() @@ -283,10 +286,12 @@ function(add_umf_target_link_options name) if(NOT MSVC) if(NOT APPLE) target_link_options(${name} PRIVATE "LINKER:-z,relro,-z,now") - if(UMF_USE_GCOV) + if(UMF_USE_COVERAGE) if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") message( - FATAL_ERROR "To use gcov, the build type must be Debug") + FATAL_ERROR + "To use the --coverage flag, the build type must be Debug" + ) endif() target_link_options(${name} PRIVATE --coverage) endif() From b25d92c64ae0347f11a0e76bdcf525998eb75022 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 9 Oct 2024 14:22:02 +0200 Subject: [PATCH 165/352] Compute code coverage Signed-off-by: Lukasz Dorau --- .github/workflows/coverage.yml | 49 ++++++++++++++++++++++++ cmake/helpers.cmake | 7 ++++ scripts/coverage/coverage_capture.sh | 49 ++++++++++++++++++++++++ scripts/coverage/merge_coverage_files.sh | 27 +++++++++++++ test/CMakeLists.txt | 3 +- 5 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/coverage.yml create mode 100755 scripts/coverage/coverage_capture.sh create mode 100755 scripts/coverage/merge_coverage_files.sh diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 000000000..08816c37a --- /dev/null +++ b/.github/workflows/coverage.yml @@ -0,0 +1,49 @@ +# Coverage build +name: Coverage + +on: workflow_call + +permissions: + contents: read + +env: + COVERAGE_DIR : "${{github.workspace}}/coverage" + +jobs: + Coverage: + name: Coverage build + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + + - name: Install dependencies (ubuntu-latest) + run: | + sudo apt-get update + sudo apt-get install -y lcov + + - name: Download all coverage artifacts + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + with: + pattern: exports-coverage-* + path: coverage + merge-multiple: true + + - name: Compute coverage + working-directory: ${{env.COVERAGE_DIR}} + run: | + echo "DIR: $(pwd)" && ls -al + ../scripts/coverage/merge_coverage_files.sh exports-coverage total_coverage + genhtml --no-function-coverage -o html_report total_coverage 2>&1 | tee output.txt + mkdir coverage_report + mv html_report ./coverage_report/ + tail -n2 output.txt >> $GITHUB_STEP_SUMMARY + + - name: Upload coverage report + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 + with: + name: coverage_html_report + path: coverage/coverage_report diff --git a/cmake/helpers.cmake b/cmake/helpers.cmake index 4ea8e417e..1372531a0 100644 --- a/cmake/helpers.cmake +++ b/cmake/helpers.cmake @@ -255,6 +255,13 @@ function(add_umf_target_compile_options name) ) endif() target_compile_options(${name} PRIVATE --coverage) + if(${CMAKE_C_COMPILER} MATCHES "gcc") + # Fix for the following error: geninfo: ERROR: Unexpected + # negative count '-1' for provider_os_memory.c:1037. Perhaps you + # need to compile with '-fprofile-update=atomic + target_compile_options(${name} PRIVATE -fprofile-update=atomic + -g -O0) + endif() endif() elseif(MSVC) target_compile_options( diff --git a/scripts/coverage/coverage_capture.sh b/scripts/coverage/coverage_capture.sh new file mode 100755 index 000000000..c77f1b141 --- /dev/null +++ b/scripts/coverage/coverage_capture.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# Copyright (C) 2024 Intel Corporation +# Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +# This script calculates coverage for a single build + +set -e + +[ "$1" != "" ] && OUTPUT_NAME="$1" || OUTPUT_NAME="output_coverage" + +set -x + +lcov --capture --directory . \ +--exclude "/usr/*" \ +--exclude "*/build/*" \ +--exclude "*/benchmark/*" \ +--exclude "*/examples/*" \ +--exclude "*/test/*" \ +--exclude "*/src/critnib/*" \ +--exclude "*/src/ravl/*" \ +--exclude "*proxy_lib_new_delete.h" \ +--output-file $OUTPUT_NAME || \ + ( echo "RETRY after ERROR !!!:" && \ + lcov --capture --directory . \ + --exclude "/usr/*" \ + --exclude "*/build/*" \ + --exclude "*/benchmark/*" \ + --exclude "*/examples/*" \ + --exclude "*/test/*" \ + --exclude "*/src/critnib/*" \ + --exclude "*/src/ravl/*" \ + --exclude "*proxy_lib_new_delete.h" \ + --ignore-errors mismatch,unused,negative,corrupt \ + --output-file $OUTPUT_NAME ) + +# Most common UMF source code directory on most GH CI runners +COMMON_UMF_DIR=/home/runner/work/unified-memory-framework/unified-memory-framework + +# Get the current UMF source code directory +# This is ${CURRENT_UMF_DIR}/scripts/coverage/coverage_capture.sh file, so +CURRENT_UMF_DIR=$(realpath $(dirname $0)/../..) + +# Coverage (lcov) has to be run in the same directory on all runners: +# /home/runner/work/unified-memory-framework/unified-memory-framework/build +# to be able to merge all results, so we have to replace the paths if they are different: +if [ "$CURRENT_UMF_DIR" != "$COMMON_UMF_DIR" ]; then + sed -i "s|$CURRENT_UMF_DIR|$COMMON_UMF_DIR|g" $OUTPUT_NAME +fi diff --git a/scripts/coverage/merge_coverage_files.sh b/scripts/coverage/merge_coverage_files.sh new file mode 100755 index 000000000..193600556 --- /dev/null +++ b/scripts/coverage/merge_coverage_files.sh @@ -0,0 +1,27 @@ +#!/bin/bash +# Copyright (C) 2024 Intel Corporation +# Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +# +# Arguments: +# +# This script looks for "${PREFIX}-*" lcov output files in the current directory, +# merges them and saves the merged output in the $OUTPUT_NAME file. +# + +[ "$1" != "" ] && PREFIX="$1" || PREFIX="exports-coverage" +[ "$2" != "" ] && OUTPUT_NAME="$2" || OUTPUT_NAME="total_coverage" + +OPTS="" +for file in $(ls -1 ${PREFIX}-*); do + OPTS="$OPTS -a $file" +done + +set -x + +lcov $OPTS -o $OUTPUT_NAME || \ + ( echo "RETRY after ERROR !!!:" && \ + lcov $OPTS \ + --ignore-errors mismatch,unused,negative,corrupt \ + --output-file $OUTPUT_NAME ) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3020094b9..8a03fd195 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -498,7 +498,8 @@ if(LINUX (UMF_USE_ASAN OR UMF_USE_UBSAN OR UMF_USE_TSAN - OR UMF_USE_MSAN)) + OR UMF_USE_MSAN + OR UMF_USE_COVERAGE)) set(EXAMPLES "") From f5f3f539b90fc936c225248b80e9edcff942b4cd Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 14 Oct 2024 15:49:23 +0200 Subject: [PATCH 166/352] Add Basic builds to Coverage Signed-off-by: Lukasz Dorau --- .github/workflows/basic.yml | 25 ++++++++++++++++++++++--- .github/workflows/pr_push.yml | 3 +++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/.github/workflows/basic.yml b/.github/workflows/basic.yml index 6a12c025f..bfa21d40f 100644 --- a/.github/workflows/basic.yml +++ b/.github/workflows/basic.yml @@ -11,6 +11,8 @@ env: UMF_VERSION: 0.10.0 BUILD_DIR : "${{github.workspace}}/build" INSTL_DIR : "${{github.workspace}}/../install-dir" + COVERAGE_DIR : "${{github.workspace}}/coverage" + COVERAGE_NAME : "exports-coverage-basic" jobs: ubuntu-build: @@ -122,8 +124,8 @@ jobs: - name: Install apt packages run: | sudo apt-get update - sudo apt-get install -y clang cmake libnuma-dev libjemalloc-dev - + sudo apt-get install -y clang cmake libnuma-dev libjemalloc-dev lcov + - name: Install TBB apt package if: matrix.install_tbb == 'ON' run: | @@ -167,6 +169,7 @@ jobs: -DUMF_TESTS_FAIL_ON_SKIP=ON -DUMF_DISABLE_HWLOC=${{matrix.disable_hwloc}} -DUMF_LINK_HWLOC_STATICALLY=${{matrix.link_hwloc_statically}} + ${{ matrix.build_type == 'Debug' && matrix.compiler.c == 'gcc' && '-DUMF_USE_COVERAGE=ON' || '' }} - name: Build UMF run: | @@ -177,7 +180,23 @@ jobs: working-directory: ${{env.BUILD_DIR}} run: | ${{ matrix.compiler.cxx == 'icpx' && '. /opt/intel/oneapi/setvars.sh' || true }} - ctest --output-on-failure --test-dir test + ctest --output-on-failure # run all tests for better coverage + + - name: Check coverage + if: ${{ matrix.build_type == 'Debug' && matrix.compiler.c == 'gcc' }} + working-directory: ${{env.BUILD_DIR}} + run: | + export COVERAGE_FILE_NAME=${{env.COVERAGE_NAME}}-${{matrix.os}}-shared-${{matrix.shared_library}}-no_hwloc-${{matrix.disable_hwloc}} + echo "COVERAGE_FILE_NAME: $COVERAGE_FILE_NAME" + ../scripts/coverage/coverage_capture.sh $COVERAGE_FILE_NAME + mkdir -p ${{env.COVERAGE_DIR}} + mv ./$COVERAGE_FILE_NAME ${{env.COVERAGE_DIR}} + + - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 + if: ${{ matrix.build_type == 'Debug' && matrix.compiler.c == 'gcc' }} + with: + name: ${{env.COVERAGE_NAME}}-${{matrix.os}}-shared-${{matrix.shared_library}}-no_hwloc-${{matrix.disable_hwloc}} + path: ${{env.COVERAGE_DIR}} - name: Remove the installation directory run: rm -rf ${{env.INSTL_DIR}} diff --git a/.github/workflows/pr_push.yml b/.github/workflows/pr_push.yml index c921eced6..68058514e 100644 --- a/.github/workflows/pr_push.yml +++ b/.github/workflows/pr_push.yml @@ -110,3 +110,6 @@ jobs: MultiNuma: needs: [Build] uses: ./.github/workflows/multi_numa.yml + Coverage: + needs: [Spellcheck, CodeStyle, Build] + uses: ./.github/workflows/coverage.yml From e13bf13b334e35f01a758da5bc213128fc57c642 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Sat, 12 Oct 2024 12:30:59 +0200 Subject: [PATCH 167/352] Add DAX to Coverage Signed-off-by: Lukasz Dorau --- .github/workflows/dax.yml | 19 +++++++++++++++++++ .github/workflows/pr_push.yml | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/.github/workflows/dax.yml b/.github/workflows/dax.yml index 04c36cf80..b776d3eff 100644 --- a/.github/workflows/dax.yml +++ b/.github/workflows/dax.yml @@ -28,6 +28,8 @@ env: UMF_TESTS_FSDAX_PATH: "/mnt/pmem1/file" BUILD_DIR : "${{github.workspace}}/build" INSTL_DIR : "${{github.workspace}}/../install-dir" + COVERAGE_DIR : "${{github.workspace}}/coverage" + COVERAGE_NAME : "exports-coverage-dax" jobs: dax: @@ -83,6 +85,7 @@ jobs: -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON -DUMF_BUILD_LEVEL_ZERO_PROVIDER=OFF -DUMF_TESTS_FAIL_ON_SKIP=ON + ${{ matrix.build_type == 'Debug' && '-DUMF_USE_COVERAGE=ON' || '' }} - name: Build UMF run: cmake --build ${{env.BUILD_DIR}} --config ${{matrix.build_type}} -j $(nproc) @@ -100,3 +103,19 @@ jobs: UMF_TESTS_FSDAX_PATH=${{env.UMF_TESTS_FSDAX_PATH}} ctest -C ${{matrix.build_type}} -R umf-provider_file_memory -V UMF_TESTS_FSDAX_PATH=${{env.UMF_TESTS_FSDAX_PATH}} ctest -C ${{matrix.build_type}} -R umf_example_dram_and_fsdax -V UMF_TESTS_FSDAX_PATH=${{env.UMF_TESTS_FSDAX_PATH}} ctest -C ${{matrix.build_type}} -R umf-ipc_file_prov_fsdax -V + + - name: Check coverage + if: ${{ matrix.build_type == 'Debug' }} + working-directory: ${{env.BUILD_DIR}} + run: | + export COVERAGE_FILE_NAME=${{env.COVERAGE_NAME}}-shared-${{matrix.shared_library}} + echo "COVERAGE_FILE_NAME: $COVERAGE_FILE_NAME" + ../scripts/coverage/coverage_capture.sh $COVERAGE_FILE_NAME + mkdir -p ${{env.COVERAGE_DIR}} + mv ./$COVERAGE_FILE_NAME ${{env.COVERAGE_DIR}} + + - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 + if: ${{ matrix.build_type == 'Debug' }} + with: + name: ${{env.COVERAGE_NAME}}-shared-${{matrix.shared_library}} + path: ${{env.COVERAGE_DIR}} diff --git a/.github/workflows/pr_push.yml b/.github/workflows/pr_push.yml index 68058514e..b5e052b56 100644 --- a/.github/workflows/pr_push.yml +++ b/.github/workflows/pr_push.yml @@ -111,5 +111,5 @@ jobs: needs: [Build] uses: ./.github/workflows/multi_numa.yml Coverage: - needs: [Spellcheck, CodeStyle, Build] + needs: [Build, DevDax] uses: ./.github/workflows/coverage.yml From ba20da2973599aa7bad3a3363cffc7f166edfdd4 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 14 Oct 2024 15:50:29 +0200 Subject: [PATCH 168/352] Add GPU to Coverage Signed-off-by: Lukasz Dorau --- .github/workflows/gpu.yml | 66 ++++++++++++++++++++++++++++------- .github/workflows/pr_push.yml | 2 +- 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/.github/workflows/gpu.yml b/.github/workflows/gpu.yml index 279f977b1..91e13b674 100644 --- a/.github/workflows/gpu.yml +++ b/.github/workflows/gpu.yml @@ -12,19 +12,21 @@ permissions: env: BUILD_DIR : "${{github.workspace}}/build" INSTL_DIR : "${{github.workspace}}/../install-dir" + COVERAGE_DIR : "${{github.workspace}}/coverage" jobs: gpu: name: Build env: - BUILD_TYPE: Release VCPKG_PATH: "${{github.workspace}}/../../../../vcpkg/packages/hwloc_x64-windows;${{github.workspace}}/../../../../vcpkg/packages/tbb_x64-windows;${{github.workspace}}/../../../../vcpkg/packages/jemalloc_x64-windows" + COVERAGE_NAME : "exports-coverage-gpu" # run only on upstream; forks will not have the HW if: github.repository == 'oneapi-src/unified-memory-framework' strategy: matrix: shared_library: ['ON', 'OFF'] os: ['Ubuntu', 'Windows'] + build_type: ['Debug', 'Release'] include: - os: 'Ubuntu' compiler: {c: gcc, cxx: g++} @@ -32,6 +34,9 @@ jobs: - os: 'Windows' compiler: {c: cl, cxx: cl} number_of_processors: '$Env:NUMBER_OF_PROCESSORS' + exclude: + - os: 'Windows' + build_type: 'Debug' runs-on: ["DSS-LEVEL_ZERO", "DSS-${{matrix.os}}"] steps: @@ -51,7 +56,7 @@ jobs: -DCMAKE_PREFIX_PATH="${{env.VCPKG_PATH}}" -B ${{env.BUILD_DIR}} -DCMAKE_INSTALL_PREFIX="${{env.INSTL_DIR}}" - -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} + -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DCMAKE_C_COMPILER=${{matrix.compiler.c}} -DCMAKE_CXX_COMPILER=${{matrix.compiler.cxx}} -DUMF_BUILD_SHARED_LIBRARY=${{matrix.shared_library}} @@ -73,7 +78,7 @@ jobs: cmake -B ${{env.BUILD_DIR}} -DCMAKE_INSTALL_PREFIX="${{env.INSTL_DIR}}" - -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} + -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DCMAKE_C_COMPILER=${{matrix.compiler.c}} -DCMAKE_CXX_COMPILER=${{matrix.compiler.cxx}} -DUMF_BUILD_SHARED_LIBRARY=${{matrix.shared_library}} @@ -88,31 +93,49 @@ jobs: -DUMF_BUILD_LEVEL_ZERO_PROVIDER=ON -DUMF_BUILD_CUDA_PROVIDER=OFF -DUMF_TESTS_FAIL_ON_SKIP=ON + ${{ matrix.build_type == 'Debug' && '-DUMF_USE_COVERAGE=ON' || '' }} - name: Build UMF - run: cmake --build ${{env.BUILD_DIR}} --config ${{env.BUILD_TYPE}} -j ${{matrix.number_of_processors}} + run: cmake --build ${{env.BUILD_DIR}} --config ${{matrix.build_type}} -j ${{matrix.number_of_processors}} - name: Run tests working-directory: ${{env.BUILD_DIR}} - run: ctest -C ${{env.BUILD_TYPE}} --output-on-failure --test-dir test + run: ctest -C ${{matrix.build_type}} --output-on-failure --test-dir test - name: Run examples working-directory: ${{env.BUILD_DIR}} - run: ctest --output-on-failure --test-dir examples -C ${{env.BUILD_TYPE}} + run: ctest --output-on-failure --test-dir examples -C ${{matrix.build_type}} - name: Run benchmarks working-directory: ${{env.BUILD_DIR}} - run: ctest --output-on-failure --test-dir benchmark -C ${{env.BUILD_TYPE}} --exclude-regex umf-bench-multithreaded + run: ctest --output-on-failure --test-dir benchmark -C ${{matrix.build_type}} --exclude-regex umf-bench-multithreaded + + - name: Check coverage + if: ${{ matrix.build_type == 'Debug' && matrix.os == 'Ubuntu' }} + working-directory: ${{env.BUILD_DIR}} + run: | + export COVERAGE_FILE_NAME=${{env.COVERAGE_NAME}}-shared-${{matrix.shared_library}} + echo "COVERAGE_FILE_NAME: $COVERAGE_FILE_NAME" + ../scripts/coverage/coverage_capture.sh $COVERAGE_FILE_NAME + mkdir -p ${{env.COVERAGE_DIR}} + mv ./$COVERAGE_FILE_NAME ${{env.COVERAGE_DIR}} + + - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 + if: ${{ matrix.build_type == 'Debug' && matrix.os == 'Ubuntu' }} + with: + name: ${{env.COVERAGE_NAME}}-shared-${{matrix.shared_library}} + path: ${{env.COVERAGE_DIR}} gpu-CUDA: name: Build env: - BUILD_TYPE: Release + COVERAGE_NAME : "exports-coverage-gpu-CUDA" # run only on upstream; forks will not have the HW if: github.repository == 'oneapi-src/unified-memory-framework' strategy: matrix: shared_library: ['ON', 'OFF'] + build_type: ['Debug', 'Release'] # TODO add windows os: ['Ubuntu'] include: @@ -136,7 +159,7 @@ jobs: run: > cmake -B ${{env.BUILD_DIR}} -DCMAKE_INSTALL_PREFIX="${{env.INSTL_DIR}}" - -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} + -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DCMAKE_C_COMPILER=${{matrix.compiler.c}} -DCMAKE_CXX_COMPILER=${{matrix.compiler.cxx}} -DUMF_BUILD_SHARED_LIBRARY=${{matrix.shared_library}} @@ -151,18 +174,35 @@ jobs: -DUMF_BUILD_LEVEL_ZERO_PROVIDER=OFF -DUMF_BUILD_CUDA_PROVIDER=ON -DUMF_TESTS_FAIL_ON_SKIP=ON + ${{ matrix.build_type == 'Debug' && '-DUMF_USE_COVERAGE=ON' || '' }} - name: Build UMF - run: cmake --build ${{env.BUILD_DIR}} --config ${{env.BUILD_TYPE}} -j ${{matrix.number_of_processors}} + run: cmake --build ${{env.BUILD_DIR}} --config ${{matrix.build_type}} -j ${{matrix.number_of_processors}} - name: Run tests working-directory: ${{env.BUILD_DIR}} - run: ctest -C ${{env.BUILD_TYPE}} --output-on-failure --test-dir test + run: ctest -C ${{matrix.build_type}} --output-on-failure --test-dir test - name: Run examples working-directory: ${{env.BUILD_DIR}} - run: ctest --output-on-failure --test-dir examples -C ${{env.BUILD_TYPE}} + run: ctest --output-on-failure --test-dir examples -C ${{matrix.build_type}} - name: Run benchmarks working-directory: ${{env.BUILD_DIR}} - run: ctest --output-on-failure --test-dir benchmark -C ${{env.BUILD_TYPE}} --exclude-regex umf-bench-multithreaded + run: ctest --output-on-failure --test-dir benchmark -C ${{matrix.build_type}} --exclude-regex umf-bench-multithreaded + + - name: Check coverage + if: ${{ matrix.build_type == 'Debug' && matrix.os == 'Ubuntu' }} + working-directory: ${{env.BUILD_DIR}} + run: | + export COVERAGE_FILE_NAME=${{env.COVERAGE_NAME}}-shared-${{matrix.shared_library}} + echo "COVERAGE_FILE_NAME: $COVERAGE_FILE_NAME" + ../scripts/coverage/coverage_capture.sh $COVERAGE_FILE_NAME + mkdir -p ${{env.COVERAGE_DIR}} + mv ./$COVERAGE_FILE_NAME ${{env.COVERAGE_DIR}} + + - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 + if: ${{ matrix.build_type == 'Debug' && matrix.os == 'Ubuntu' }} + with: + name: ${{env.COVERAGE_NAME}}-shared-${{matrix.shared_library}} + path: ${{env.COVERAGE_DIR}} diff --git a/.github/workflows/pr_push.yml b/.github/workflows/pr_push.yml index b5e052b56..d9b6bebb8 100644 --- a/.github/workflows/pr_push.yml +++ b/.github/workflows/pr_push.yml @@ -111,5 +111,5 @@ jobs: needs: [Build] uses: ./.github/workflows/multi_numa.yml Coverage: - needs: [Build, DevDax] + needs: [Build, DevDax, GPU] uses: ./.github/workflows/coverage.yml From 60294f9df19cfa6d3cf04cd615e5d8fc7f0cd425 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 14 Oct 2024 15:50:45 +0200 Subject: [PATCH 169/352] Add multi_NUMA to Coverage Signed-off-by: Lukasz Dorau --- .github/workflows/multi_numa.yml | 22 ++++++++++++++++++++++ .github/workflows/pr_push.yml | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/.github/workflows/multi_numa.yml b/.github/workflows/multi_numa.yml index a9433018e..df00af181 100644 --- a/.github/workflows/multi_numa.yml +++ b/.github/workflows/multi_numa.yml @@ -6,6 +6,11 @@ on: [workflow_call] permissions: contents: read +env: + BUILD_DIR : "${{github.workspace}}/build" + COVERAGE_DIR : "${{github.workspace}}/coverage" + COVERAGE_NAME : "exports-coverage-multinuma" + jobs: multi_numa: name: ${{matrix.os}} @@ -40,6 +45,7 @@ jobs: -DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON -DUMF_TESTS_FAIL_ON_SKIP=ON + ${{ matrix.os == 'ubuntu-22.04' && '-DUMF_USE_COVERAGE=ON' || '' }} - name: Build UMF run: cmake --build ${{github.workspace}}/build -j $(nproc) @@ -59,3 +65,19 @@ jobs: ctest --output-on-failure --test-dir test -E "umf-provider_os_memory_multiple_numa_nodes" ./test/umf_test-provider_os_memory_multiple_numa_nodes \ --gtest_filter="-*checkModeLocal/*:*checkModePreferredEmptyNodeset/*:testNuma.checkModeInterleave" + + - name: Check coverage + if: matrix.os == 'ubuntu-22.04' + working-directory: ${{env.BUILD_DIR}} + run: | + export COVERAGE_FILE_NAME=${{env.COVERAGE_NAME}}-os-${{matrix.os}} + echo "COVERAGE_FILE_NAME: $COVERAGE_FILE_NAME" + ../scripts/coverage/coverage_capture.sh $COVERAGE_FILE_NAME + mkdir -p ${{env.COVERAGE_DIR}} + mv ./$COVERAGE_FILE_NAME ${{env.COVERAGE_DIR}} + + - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 + if: matrix.os == 'ubuntu-22.04' + with: + name: ${{env.COVERAGE_NAME}}-os-${{matrix.os}} + path: ${{env.COVERAGE_DIR}} diff --git a/.github/workflows/pr_push.yml b/.github/workflows/pr_push.yml index d9b6bebb8..7750eb3c0 100644 --- a/.github/workflows/pr_push.yml +++ b/.github/workflows/pr_push.yml @@ -111,5 +111,5 @@ jobs: needs: [Build] uses: ./.github/workflows/multi_numa.yml Coverage: - needs: [Build, DevDax, GPU] + needs: [Build, DevDax, GPU, MultiNuma] uses: ./.github/workflows/coverage.yml From 058ebf45ca1227405467790f23443230037d2826 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 14 Oct 2024 15:51:06 +0200 Subject: [PATCH 170/352] Add QEMU to Coverage Signed-off-by: Lukasz Dorau --- .github/workflows/pr_push.yml | 2 +- .github/workflows/qemu.yml | 11 +++++++++-- scripts/qemu/run-build.sh | 10 +++++++++- scripts/qemu/run-tests.sh | 19 +++++++++++++++++++ 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pr_push.yml b/.github/workflows/pr_push.yml index 7750eb3c0..ab0ef15b3 100644 --- a/.github/workflows/pr_push.yml +++ b/.github/workflows/pr_push.yml @@ -111,5 +111,5 @@ jobs: needs: [Build] uses: ./.github/workflows/multi_numa.yml Coverage: - needs: [Build, DevDax, GPU, MultiNuma] + needs: [Build, DevDax, GPU, MultiNuma, Qemu] uses: ./.github/workflows/coverage.yml diff --git a/.github/workflows/qemu.yml b/.github/workflows/qemu.yml index fa3089b67..7834a8b31 100644 --- a/.github/workflows/qemu.yml +++ b/.github/workflows/qemu.yml @@ -86,7 +86,7 @@ jobs: rsync -az -e "ssh -p 2222" ${{github.workspace}}/umf/ testuser@127.0.0.1:/home/testuser/ ssh testuser@127.0.0.1 -p 2222 -t "sudo chown -R testuser:users /home/testuser" - ssh testuser@127.0.0.1 -p 2222 -t "bash /home/testuser/scripts/qemu/run-build.sh" + ssh testuser@127.0.0.1 -p 2222 -t "bash /home/testuser/scripts/qemu/run-build.sh COVERAGE" ssh testuser@127.0.0.1 -p 2222 -t "sudo shutdown -h now" - name: Run tests in QEMU @@ -102,6 +102,13 @@ jobs: echo "\n ### Testing ${config_name} ###" umf/scripts/qemu/start_qemu.sh ${config_name} - ssh testuser@127.0.0.1 -p 2222 -t "bash /home/testuser/scripts/qemu/run-tests.sh" + ssh testuser@127.0.0.1 -p 2222 -t "bash /home/testuser/scripts/qemu/run-tests.sh COVERAGE ${config_name}" + scp -r -P 2222 testuser@127.0.0.1:/home/testuser/coverage ./ ssh testuser@127.0.0.1 -p 2222 -t "sudo shutdown -h now" done + ls -al ./coverage + + - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 + with: + name: exports-coverage-qemu-all + path: coverage diff --git a/scripts/qemu/run-build.sh b/scripts/qemu/run-build.sh index 666bd2200..06d6043f6 100755 --- a/scripts/qemu/run-build.sh +++ b/scripts/qemu/run-build.sh @@ -5,9 +5,16 @@ set -e +[ "$1" = "COVERAGE" ] && COVERAGE=ON || COVERAGE=OFF + +# This is ${UMF_DIR}/scripts/qemu/run-build.sh file, so +UMF_DIR=$(dirname $0)/../.. +cd $UMF_DIR +pwd + echo password | sudo -Sk apt-get update echo password | sudo -Sk apt-get install -y git cmake gcc g++ pkg-config \ - numactl libnuma-dev hwloc libhwloc-dev libjemalloc-dev libtbb-dev valgrind + numactl libnuma-dev hwloc libhwloc-dev libjemalloc-dev libtbb-dev valgrind lcov mkdir build cd build @@ -21,6 +28,7 @@ cmake .. \ -DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON \ -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON \ -DUMF_BUILD_EXAMPLES=ON \ + -DUMF_USE_COVERAGE=${COVERAGE} \ -DUMF_TESTS_FAIL_ON_SKIP=ON make -j $(nproc) diff --git a/scripts/qemu/run-tests.sh b/scripts/qemu/run-tests.sh index 2faa68831..69f187990 100755 --- a/scripts/qemu/run-tests.sh +++ b/scripts/qemu/run-tests.sh @@ -5,6 +5,18 @@ set -e +COVERAGE=$1 +XML_CONFIG_FILE=$2 + +CONFIG_NAME=$(echo $XML_CONFIG_FILE | cut -d. -f1) # remove the '.xml' extension +COVERAGE_DIR=${HOME}/coverage +mkdir -p $COVERAGE_DIR + +# This is ${UMF_DIR}/scripts/qemu/run-build.sh file, so +UMF_DIR=$(dirname $0)/../.. +cd $UMF_DIR +UMF_DIR=$(pwd) + # Drop caches, restores free memory on NUMA nodes echo password | sudo sync; echo password | sudo sh -c "/usr/bin/echo 3 > /proc/sys/vm/drop_caches" @@ -20,6 +32,13 @@ ctest --verbose numactl -N 0 ctest --output-on-failure numactl -N 1 ctest --output-on-failure +if [ "$COVERAGE" = "COVERAGE" ]; then + COVERAGE_FILE_NAME=exports-coverage-qemu-$CONFIG_NAME + echo "COVERAGE_FILE_NAME: $COVERAGE_FILE_NAME" + ../scripts/coverage/coverage_capture.sh $COVERAGE_FILE_NAME + mv ./$COVERAGE_FILE_NAME $COVERAGE_DIR +fi + # run tests under valgrind echo "Running tests under valgrind memcheck ..." ../test/test_valgrind.sh .. . memcheck From c04141269c1432d0c6f7ce7008595d8a23b8b0d5 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Tue, 15 Oct 2024 13:17:24 +0200 Subject: [PATCH 171/352] Add ProxyLib to Coverage Signed-off-by: Lukasz Dorau --- .github/workflows/pr_push.yml | 2 +- .github/workflows/proxy_lib.yml | 21 ++++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr_push.yml b/.github/workflows/pr_push.yml index ab0ef15b3..50f8f1aa9 100644 --- a/.github/workflows/pr_push.yml +++ b/.github/workflows/pr_push.yml @@ -111,5 +111,5 @@ jobs: needs: [Build] uses: ./.github/workflows/multi_numa.yml Coverage: - needs: [Build, DevDax, GPU, MultiNuma, Qemu] + needs: [Build, DevDax, GPU, MultiNuma, Qemu, ProxyLib] uses: ./.github/workflows/coverage.yml diff --git a/.github/workflows/proxy_lib.yml b/.github/workflows/proxy_lib.yml index 581819c49..3babd205e 100644 --- a/.github/workflows/proxy_lib.yml +++ b/.github/workflows/proxy_lib.yml @@ -9,6 +9,8 @@ permissions: env: BUILD_DIR : "${{github.workspace}}/build" INSTL_DIR : "${{github.workspace}}/../install-dir" + COVERAGE_DIR : "${{github.workspace}}/coverage" + COVERAGE_NAME : "exports-coverage-proxy" jobs: proxy-ubuntu: @@ -30,7 +32,7 @@ jobs: - name: Install apt packages run: | sudo apt-get update - sudo apt-get install -y cmake libhwloc-dev libjemalloc-dev libtbb-dev + sudo apt-get install -y cmake libhwloc-dev libjemalloc-dev libtbb-dev lcov - name: Set ptrace value for IPC test run: sudo bash -c "echo 0 > /proc/sys/kernel/yama/ptrace_scope" @@ -52,6 +54,7 @@ jobs: -DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON -DUMF_TESTS_FAIL_ON_SKIP=ON -DUMF_PROXY_LIB_BASED_ON_POOL=${{matrix.proxy_lib_pool}} + ${{ matrix.build_type == 'Debug' && '-DUMF_USE_COVERAGE=ON' || '' }} - name: Build UMF run: cmake --build ${{env.BUILD_DIR}} -j $(nproc) @@ -71,3 +74,19 @@ jobs: - name: Run "/usr/bin/date" with proxy library working-directory: ${{env.BUILD_DIR}} run: UMF_PROXY="page.disposition=shared-shm" LD_PRELOAD=./lib/libumf_proxy.so /usr/bin/date + + - name: Check coverage + if: ${{ matrix.build_type == 'Debug' }} + working-directory: ${{env.BUILD_DIR}} + run: | + export COVERAGE_FILE_NAME=${{env.COVERAGE_NAME}}-proxy_lib_pool-${{matrix.proxy_lib_pool}} + echo "COVERAGE_FILE_NAME: $COVERAGE_FILE_NAME" + ../scripts/coverage/coverage_capture.sh $COVERAGE_FILE_NAME + mkdir -p ${{env.COVERAGE_DIR}} + mv ./$COVERAGE_FILE_NAME ${{env.COVERAGE_DIR}} + + - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 + if: ${{ matrix.build_type == 'Debug' }} + with: + name: ${{env.COVERAGE_NAME}}-proxy_lib_pool-${{matrix.proxy_lib_pool}} + path: ${{env.COVERAGE_DIR}} From 72cb5f7be0f9cfb19ef882452b32d30381394285 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Tue, 15 Oct 2024 10:58:10 +0200 Subject: [PATCH 172/352] Add debug message to umfMemoryTrackerRemove() Signed-off-by: Lukasz Dorau --- src/provider/provider_tracking.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/provider/provider_tracking.c b/src/provider/provider_tracking.c index d65cf6f4f..5dd96382c 100644 --- a/src/provider/provider_tracking.c +++ b/src/provider/provider_tracking.c @@ -80,6 +80,11 @@ static umf_result_t umfMemoryTrackerRemove(umf_memory_tracker_handle_t hTracker, return UMF_RESULT_ERROR_UNKNOWN; } + tracker_value_t *v = value; + + LOG_DEBUG("memory region removed: tracker=%p, ptr=%p, size=%zu", + (void *)hTracker, ptr, v->size); + umf_ba_free(hTracker->tracker_allocator, value); return UMF_RESULT_SUCCESS; From 1b32ade12ed52dec54776e0d10061b4920998e5a Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Tue, 15 Oct 2024 21:53:08 +0200 Subject: [PATCH 173/352] Fix trackingFree() - do not add a not removed entry Do not add memory back to the tracker, if it had not been removed. Signed-off-by: Lukasz Dorau --- src/provider/provider_tracking.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/provider/provider_tracking.c b/src/provider/provider_tracking.c index 5dd96382c..5e10a9404 100644 --- a/src/provider/provider_tracking.c +++ b/src/provider/provider_tracking.c @@ -337,6 +337,7 @@ static umf_result_t trackingAllocationMerge(void *hProvider, void *lowPtr, static umf_result_t trackingFree(void *hProvider, void *ptr, size_t size) { umf_result_t ret; + umf_result_t ret_remove = UMF_RESULT_ERROR_UNKNOWN; umf_tracking_memory_provider_t *p = (umf_tracking_memory_provider_t *)hProvider; @@ -345,13 +346,13 @@ static umf_result_t trackingFree(void *hProvider, void *ptr, size_t size) { // could allocate the memory at address `ptr` before a call to umfMemoryTrackerRemove // resulting in inconsistent state. if (ptr) { - ret = umfMemoryTrackerRemove(p->hTracker, ptr); - if (ret != UMF_RESULT_SUCCESS) { + ret_remove = umfMemoryTrackerRemove(p->hTracker, ptr); + if (ret_remove != UMF_RESULT_SUCCESS) { // DO NOT return an error here, because the tracking provider // cannot change behaviour of the upstream provider. LOG_ERR("failed to remove the region from the tracker, ptr=%p, " "size=%zu, ret = %d", - ptr, size, ret); + ptr, size, ret_remove); } } @@ -371,6 +372,12 @@ static umf_result_t trackingFree(void *hProvider, void *ptr, size_t size) { ret = umfMemoryProviderFree(p->hUpstream, ptr, size); if (ret != UMF_RESULT_SUCCESS) { LOG_ERR("upstream provider is failed to free the memory"); + // Do not add memory back to the tracker, + // if it had not been removed. + if (ret_remove != UMF_RESULT_SUCCESS) { + return ret; + } + if (umfMemoryTrackerAdd(p->hTracker, p->pool, ptr, size) != UMF_RESULT_SUCCESS) { LOG_ERR( From b866b7cc4befbf12404e85e9e32fa99ef3233c16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Wed, 9 Oct 2024 13:07:37 +0200 Subject: [PATCH 174/352] [CI] Rename sub-workflows with "reusable_" prefix --- .github/workflows/pr_push.yml | 88 ++++--------------- .../{basic.yml => reusable_basic.yml} | 0 ...benchmarks.yml => reusable_benchmarks.yml} | 0 .github/workflows/reusable_code_style.yml | 43 +++++++++ .../{coverage.yml => reusable_coverage.yml} | 4 +- .../workflows/{dax.yml => reusable_dax.yml} | 0 .github/workflows/reusable_docs_build.yml | 32 +++++++ .../workflows/{fast.yml => reusable_fast.yml} | 0 .../workflows/{gpu.yml => reusable_gpu.yml} | 0 ...multi_numa.yml => reusable_multi_numa.yml} | 0 .../{proxy_lib.yml => reusable_proxy_lib.yml} | 0 .../workflows/{qemu.yml => reusable_qemu.yml} | 0 ...sanitizers.yml => reusable_sanitizers.yml} | 0 ...spellcheck.yml => reusable_spellcheck.yml} | 0 .../{valgrind.yml => reusable_valgrind.yml} | 0 15 files changed, 93 insertions(+), 74 deletions(-) rename .github/workflows/{basic.yml => reusable_basic.yml} (100%) rename .github/workflows/{benchmarks.yml => reusable_benchmarks.yml} (100%) create mode 100644 .github/workflows/reusable_code_style.yml rename .github/workflows/{coverage.yml => reusable_coverage.yml} (91%) rename .github/workflows/{dax.yml => reusable_dax.yml} (100%) create mode 100644 .github/workflows/reusable_docs_build.yml rename .github/workflows/{fast.yml => reusable_fast.yml} (100%) rename .github/workflows/{gpu.yml => reusable_gpu.yml} (100%) rename .github/workflows/{multi_numa.yml => reusable_multi_numa.yml} (100%) rename .github/workflows/{proxy_lib.yml => reusable_proxy_lib.yml} (100%) rename .github/workflows/{qemu.yml => reusable_qemu.yml} (100%) rename .github/workflows/{sanitizers.yml => reusable_sanitizers.yml} (100%) rename .github/workflows/{spellcheck.yml => reusable_spellcheck.yml} (100%) rename .github/workflows/{valgrind.yml => reusable_valgrind.yml} (100%) diff --git a/.github/workflows/pr_push.yml b/.github/workflows/pr_push.yml index 50f8f1aa9..84b9e7537 100644 --- a/.github/workflows/pr_push.yml +++ b/.github/workflows/pr_push.yml @@ -1,4 +1,5 @@ -# Checks required for a PR to merge. This workflow mostly call other workflows. +# Run checks required for a PR to merge and verify if post-merge commit is valid. +# This workflow only call other workflows. name: PR/push on: @@ -16,100 +17,43 @@ permissions: jobs: CodeStyle: - name: Coding style - runs-on: ${{ github.repository_owner == 'oneapi-src' && 'intel-ubuntu-22.04' || 'ubuntu-latest' }} - - steps: - - name: Checkout repository - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - fetch-depth: 0 - - - name: Install apt packages - run: | - sudo apt-get update - sudo apt-get install -y black cmake clang-format-15 cmake-format libhwloc-dev - - - name: Configure CMake - run: > - cmake - -B ${{github.workspace}}/build - -DUMF_FORMAT_CODE_STYLE=ON - -DUMF_BUILD_TESTS=OFF - -DUMF_BUILD_LEVEL_ZERO_PROVIDER=OFF - -DUMF_BUILD_CUDA_PROVIDER=OFF - -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=OFF - - - name: Check C/C++ formatting - run: cmake --build build --target clang-format-check - - - name: Check CMake formatting - run: | - cmake --build build --target cmake-format-apply - git diff --exit-code - - - name: Check Python formatting - run: cmake --build build --target black-format-check - + uses: ./.github/workflows/reusable_code_style.yml DocsBuild: - name: Build docs - runs-on: ${{ github.repository_owner == 'oneapi-src' && 'intel-ubuntu-22.04' || 'ubuntu-latest' }} - - steps: - - name: Checkout repository - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - fetch-depth: 0 - - - name: Install doxygen - run: | - sudo apt-get update - sudo apt-get install -y doxygen - - - name: Install pip requirements - run: python3 -m pip install -r third_party/requirements.txt - - - name: Setup PATH for python - run: echo "$HOME/.local/bin" >> $GITHUB_PATH - - - name: Build the documentation - working-directory: scripts - run: python3 generate_docs.py - + uses: ./.github/workflows/reusable_docs_build.yml Spellcheck: - uses: ./.github/workflows/spellcheck.yml + uses: ./.github/workflows/reusable_spellcheck.yml FastBuild: name: Fast builds needs: [Spellcheck, CodeStyle] - uses: ./.github/workflows/fast.yml + uses: ./.github/workflows/reusable_fast.yml Build: name: Basic builds needs: [FastBuild] - uses: ./.github/workflows/basic.yml + uses: ./.github/workflows/reusable_basic.yml DevDax: needs: [FastBuild] - uses: ./.github/workflows/dax.yml + uses: ./.github/workflows/reusable_dax.yml Sanitizers: needs: [FastBuild] - uses: ./.github/workflows/sanitizers.yml + uses: ./.github/workflows/reusable_sanitizers.yml Qemu: needs: [FastBuild] - uses: ./.github/workflows/qemu.yml + uses: ./.github/workflows/reusable_qemu.yml Benchmarks: needs: [Build] - uses: ./.github/workflows/benchmarks.yml + uses: ./.github/workflows/reusable_benchmarks.yml ProxyLib: needs: [Build] - uses: ./.github/workflows/proxy_lib.yml + uses: ./.github/workflows/reusable_proxy_lib.yml GPU: needs: [Build] - uses: ./.github/workflows/gpu.yml + uses: ./.github/workflows/reusable_gpu.yml Valgrind: needs: [Build] - uses: ./.github/workflows/valgrind.yml + uses: ./.github/workflows/reusable_valgrind.yml MultiNuma: needs: [Build] - uses: ./.github/workflows/multi_numa.yml + uses: ./.github/workflows/reusable_multi_numa.yml Coverage: needs: [Build, DevDax, GPU, MultiNuma, Qemu, ProxyLib] - uses: ./.github/workflows/coverage.yml + uses: ./.github/workflows/reusable_coverage.yml diff --git a/.github/workflows/basic.yml b/.github/workflows/reusable_basic.yml similarity index 100% rename from .github/workflows/basic.yml rename to .github/workflows/reusable_basic.yml diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/reusable_benchmarks.yml similarity index 100% rename from .github/workflows/benchmarks.yml rename to .github/workflows/reusable_benchmarks.yml diff --git a/.github/workflows/reusable_code_style.yml b/.github/workflows/reusable_code_style.yml new file mode 100644 index 000000000..10ddf644a --- /dev/null +++ b/.github/workflows/reusable_code_style.yml @@ -0,0 +1,43 @@ +name: Code Style + +on: workflow_call + +permissions: + contents: read + +jobs: + CodeStyle: + name: Coding style + runs-on: ${{ github.repository_owner == 'oneapi-src' && 'intel-ubuntu-22.04' || 'ubuntu-latest' }} + + steps: + - name: Checkout repository + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + + - name: Install apt packages + run: | + sudo apt-get update + sudo apt-get install -y black cmake clang-format-15 cmake-format libhwloc-dev + + - name: Configure CMake + run: > + cmake + -B ${{github.workspace}}/build + -DUMF_FORMAT_CODE_STYLE=ON + -DUMF_BUILD_TESTS=OFF + -DUMF_BUILD_LEVEL_ZERO_PROVIDER=OFF + -DUMF_BUILD_CUDA_PROVIDER=OFF + -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=OFF + + - name: Check C/C++ formatting + run: cmake --build build --target clang-format-check + + - name: Check CMake formatting + run: | + cmake --build build --target cmake-format-apply + git diff --exit-code + + - name: Check Python formatting + run: cmake --build build --target black-format-check diff --git a/.github/workflows/coverage.yml b/.github/workflows/reusable_coverage.yml similarity index 91% rename from .github/workflows/coverage.yml rename to .github/workflows/reusable_coverage.yml index 08816c37a..b71836fa6 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/reusable_coverage.yml @@ -1,4 +1,4 @@ -# Coverage build +# Coverage build - gather artifacts from other builds and merge them into a single report name: Coverage on: workflow_call @@ -20,7 +20,7 @@ jobs: with: fetch-depth: 0 - - name: Install dependencies (ubuntu-latest) + - name: Install dependencies run: | sudo apt-get update sudo apt-get install -y lcov diff --git a/.github/workflows/dax.yml b/.github/workflows/reusable_dax.yml similarity index 100% rename from .github/workflows/dax.yml rename to .github/workflows/reusable_dax.yml diff --git a/.github/workflows/reusable_docs_build.yml b/.github/workflows/reusable_docs_build.yml new file mode 100644 index 000000000..959c81864 --- /dev/null +++ b/.github/workflows/reusable_docs_build.yml @@ -0,0 +1,32 @@ +name: Docs build + +on: workflow_call + +permissions: + contents: read + +jobs: + DocsBuild: + name: Docs build + runs-on: ${{ github.repository_owner == 'oneapi-src' && 'intel-ubuntu-22.04' || 'ubuntu-latest' }} + + steps: + - name: Checkout repository + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + + - name: Install doxygen + run: | + sudo apt-get update + sudo apt-get install -y doxygen + + - name: Install pip requirements + run: python3 -m pip install -r third_party/requirements.txt + + - name: Setup PATH for python + run: echo "$HOME/.local/bin" >> $GITHUB_PATH + + - name: Build the documentation + working-directory: scripts + run: python3 generate_docs.py diff --git a/.github/workflows/fast.yml b/.github/workflows/reusable_fast.yml similarity index 100% rename from .github/workflows/fast.yml rename to .github/workflows/reusable_fast.yml diff --git a/.github/workflows/gpu.yml b/.github/workflows/reusable_gpu.yml similarity index 100% rename from .github/workflows/gpu.yml rename to .github/workflows/reusable_gpu.yml diff --git a/.github/workflows/multi_numa.yml b/.github/workflows/reusable_multi_numa.yml similarity index 100% rename from .github/workflows/multi_numa.yml rename to .github/workflows/reusable_multi_numa.yml diff --git a/.github/workflows/proxy_lib.yml b/.github/workflows/reusable_proxy_lib.yml similarity index 100% rename from .github/workflows/proxy_lib.yml rename to .github/workflows/reusable_proxy_lib.yml diff --git a/.github/workflows/qemu.yml b/.github/workflows/reusable_qemu.yml similarity index 100% rename from .github/workflows/qemu.yml rename to .github/workflows/reusable_qemu.yml diff --git a/.github/workflows/sanitizers.yml b/.github/workflows/reusable_sanitizers.yml similarity index 100% rename from .github/workflows/sanitizers.yml rename to .github/workflows/reusable_sanitizers.yml diff --git a/.github/workflows/spellcheck.yml b/.github/workflows/reusable_spellcheck.yml similarity index 100% rename from .github/workflows/spellcheck.yml rename to .github/workflows/reusable_spellcheck.yml diff --git a/.github/workflows/valgrind.yml b/.github/workflows/reusable_valgrind.yml similarity index 100% rename from .github/workflows/valgrind.yml rename to .github/workflows/reusable_valgrind.yml From 59e9dfc4babf7746707a0f0d04fa903c36d5c0d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Wed, 9 Oct 2024 13:44:43 +0200 Subject: [PATCH 175/352] [CI] Merge spell check with code style check into a single job --- .github/workflows/pr_push.yml | 8 +++---- ...ble_code_style.yml => reusable_checks.yml} | 13 ++++++++--- .github/workflows/reusable_spellcheck.yml | 23 ------------------- 3 files changed, 13 insertions(+), 31 deletions(-) rename .github/workflows/{reusable_code_style.yml => reusable_checks.yml} (76%) delete mode 100644 .github/workflows/reusable_spellcheck.yml diff --git a/.github/workflows/pr_push.yml b/.github/workflows/pr_push.yml index 84b9e7537..8f7818a4e 100644 --- a/.github/workflows/pr_push.yml +++ b/.github/workflows/pr_push.yml @@ -16,15 +16,13 @@ permissions: contents: read jobs: - CodeStyle: - uses: ./.github/workflows/reusable_code_style.yml + CodeCheck: + uses: ./.github/workflows/reusable_checks.yml DocsBuild: uses: ./.github/workflows/reusable_docs_build.yml - Spellcheck: - uses: ./.github/workflows/reusable_spellcheck.yml FastBuild: name: Fast builds - needs: [Spellcheck, CodeStyle] + needs: [CodeCheck, DocsBuild] uses: ./.github/workflows/reusable_fast.yml Build: name: Basic builds diff --git a/.github/workflows/reusable_code_style.yml b/.github/workflows/reusable_checks.yml similarity index 76% rename from .github/workflows/reusable_code_style.yml rename to .github/workflows/reusable_checks.yml index 10ddf644a..643ef61c3 100644 --- a/.github/workflows/reusable_code_style.yml +++ b/.github/workflows/reusable_checks.yml @@ -1,4 +1,6 @@ -name: Code Style +# Basic checks on the code, incl. coding style and spelling. +# TODO: add license check +name: Basic checks on: workflow_call @@ -6,8 +8,8 @@ permissions: contents: read jobs: - CodeStyle: - name: Coding style + CodeCheck: + name: Coding style and spell check runs-on: ${{ github.repository_owner == 'oneapi-src' && 'intel-ubuntu-22.04' || 'ubuntu-latest' }} steps: @@ -41,3 +43,8 @@ jobs: - name: Check Python formatting run: cmake --build build --target black-format-check + + - name: Run a spell check + uses: crate-ci/typos@b63f421581dce830bda2f597a678cb7776b41877 # v1.18.2 + with: + config: ./.github/workflows/.spellcheck-conf.toml \ No newline at end of file diff --git a/.github/workflows/reusable_spellcheck.yml b/.github/workflows/reusable_spellcheck.yml deleted file mode 100644 index dbd6f1c8e..000000000 --- a/.github/workflows/reusable_spellcheck.yml +++ /dev/null @@ -1,23 +0,0 @@ -# Checks spelling issues in the repo -name: SpellCheck - -on: workflow_call - -permissions: - contents: read - -jobs: - analyze: - name: Run spell check - runs-on: ${{ github.repository_owner == 'oneapi-src' && 'intel-ubuntu-22.04' || 'ubuntu-latest' }} - - steps: - - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - fetch-depth: 0 - - - name: Run a spell check - uses: crate-ci/typos@b63f421581dce830bda2f597a678cb7776b41877 # v1.18.2 - with: - config: ./.github/workflows/.spellcheck-conf.toml From e7c331724e5e8503804541a56c2d9e6b76cc4ea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Wed, 9 Oct 2024 14:00:52 +0200 Subject: [PATCH 176/352] [CI] Run all Valgrind tools in a single job --- .github/workflows/reusable_valgrind.yml | 15 +++++++++------ test/test_valgrind.sh | 2 ++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/.github/workflows/reusable_valgrind.yml b/.github/workflows/reusable_valgrind.yml index 40d4e6535..86ceb68c6 100644 --- a/.github/workflows/reusable_valgrind.yml +++ b/.github/workflows/reusable_valgrind.yml @@ -1,3 +1,4 @@ +# Run tests with valgrind intstrumentation tools: memcheck, drd, helgrind name: Valgrind on: workflow_call @@ -8,10 +9,6 @@ permissions: jobs: valgrind: name: Valgrind - strategy: - fail-fast: false - matrix: - tool: ['memcheck', 'drd', 'helgrind'] runs-on: ubuntu-latest steps: @@ -42,5 +39,11 @@ jobs: - name: Build run: cmake --build ${{github.workspace}}/build --config Debug -j$(nproc) - - name: Run tests under valgrind - run: ${{github.workspace}}/test/test_valgrind.sh ${{github.workspace}} ${{github.workspace}}/build ${{matrix.tool}} + - name: Run tests with 'memcheck' + run: ${{github.workspace}}/test/test_valgrind.sh ${{github.workspace}} ${{github.workspace}}/build memcheck + + - name: Run tests with 'drd' + run: ${{github.workspace}}/test/test_valgrind.sh ${{github.workspace}} ${{github.workspace}}/build drd + + - name: Run tests with 'helgrind' + run: ${{github.workspace}}/test/test_valgrind.sh ${{github.workspace}} ${{github.workspace}}/build helgrind diff --git a/test/test_valgrind.sh b/test/test_valgrind.sh index 4b8b25b3b..262a86784 100755 --- a/test/test_valgrind.sh +++ b/test/test_valgrind.sh @@ -145,6 +145,8 @@ for test in $(ls -1 umf_test-*); do fi || true done +rm -rf ${BUILD_DIR}/test/cpuid + [ $ANY_TEST_FAILED -eq 0 ] && echo PASSED && exit 0 echo From f65a78ebe15f8d3bae901223f19cd0a5d98fd940 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Wed, 9 Oct 2024 14:21:06 +0200 Subject: [PATCH 177/352] [CI] Remove flag check in Windows' "Fast builds" it's already covered in "Basic builds". --- .github/workflows/reusable_fast.yml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/.github/workflows/reusable_fast.yml b/.github/workflows/reusable_fast.yml index 997c4441c..e25de68a1 100644 --- a/.github/workflows/reusable_fast.yml +++ b/.github/workflows/reusable_fast.yml @@ -133,16 +133,6 @@ jobs: working-directory: ${{env.BUILD_DIR}} run: ctest --output-on-failure --test-dir test -C Release - - name: check /DEPENDENTLOADFLAG (Windows only) - if: matrix.os == 'windows-latest' - run: ${{github.workspace}}/.github/scripts/check_dll_flags.ps1 ${{env.BUILD_DIR}}/bin/Release/umf.dll - shell: pwsh - - - name: check /DEPENDENTLOADFLAG in umf_proxy.dll - if: matrix.os == 'windows-latest' - run: ${{github.workspace}}/.github/scripts/check_dll_flags.ps1 ${{env.BUILD_DIR}}/src/proxy_lib/Release/umf_proxy.dll - shell: pwsh - # TODO: We could add some script to verify metadata of dll's (selected fields, perhaps) # ref. https://superuser.com/questions/381276/what-are-some-nice-command-line-ways-to-inspect-dll-exe-details - name: Print metadata of our dll's From 2ad5ace3c956a1744ce350975085c9231a9a954d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Wed, 9 Oct 2024 14:50:47 +0200 Subject: [PATCH 178/352] [CI] Do Bandit scan only on Linux and move it to 'checks' workflow --- .github/workflows/bandit.yml | 35 --------------------------- .github/workflows/pr_push.yml | 4 +-- .github/workflows/reusable_checks.yml | 15 ++++++++---- 3 files changed, 12 insertions(+), 42 deletions(-) delete mode 100644 .github/workflows/bandit.yml diff --git a/.github/workflows/bandit.yml b/.github/workflows/bandit.yml deleted file mode 100644 index acb64034b..000000000 --- a/.github/workflows/bandit.yml +++ /dev/null @@ -1,35 +0,0 @@ -# Bandit static analysis (for Python code) -name: Bandit -on: - push: - branches-ignore: - - 'dependabot/**' - pull_request: - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -permissions: - contents: read - -jobs: - bandit: - name: Bandit - strategy: - matrix: - os: [ubuntu-latest, windows-latest] - runs-on: ${{ (matrix.os == 'ubuntu-latest' && github.repository_owner == 'oneapi-src') && 'intel-ubuntu-22.04' || matrix.os }} - - steps: - - name: Checkout repository - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - fetch-depth: 0 - - - name: Install Bandit - run: python3 -m pip install bandit - - # Run Bandit recursively, but omit _deps directory (with 3rd party code) - - name: Run Bandit - run: python3 -m bandit -r . -x '/_deps/' diff --git a/.github/workflows/pr_push.yml b/.github/workflows/pr_push.yml index 8f7818a4e..8ba8b94fa 100644 --- a/.github/workflows/pr_push.yml +++ b/.github/workflows/pr_push.yml @@ -16,13 +16,13 @@ permissions: contents: read jobs: - CodeCheck: + CodeChecks: uses: ./.github/workflows/reusable_checks.yml DocsBuild: uses: ./.github/workflows/reusable_docs_build.yml FastBuild: name: Fast builds - needs: [CodeCheck, DocsBuild] + needs: [CodeChecks, DocsBuild] uses: ./.github/workflows/reusable_fast.yml Build: name: Basic builds diff --git a/.github/workflows/reusable_checks.yml b/.github/workflows/reusable_checks.yml index 643ef61c3..5b7bc6f85 100644 --- a/.github/workflows/reusable_checks.yml +++ b/.github/workflows/reusable_checks.yml @@ -1,4 +1,4 @@ -# Basic checks on the code, incl. coding style and spelling. +# Basic checks on the code, incl. coding style, spelling, bandit analysis. # TODO: add license check name: Basic checks @@ -8,8 +8,8 @@ permissions: contents: read jobs: - CodeCheck: - name: Coding style and spell check + CodeChecks: + name: Basic code checks runs-on: ${{ github.repository_owner == 'oneapi-src' && 'intel-ubuntu-22.04' || 'ubuntu-latest' }} steps: @@ -18,10 +18,11 @@ jobs: with: fetch-depth: 0 - - name: Install apt packages + - name: Install dependencies run: | sudo apt-get update sudo apt-get install -y black cmake clang-format-15 cmake-format libhwloc-dev + python3 -m pip install bandit - name: Configure CMake run: > @@ -47,4 +48,8 @@ jobs: - name: Run a spell check uses: crate-ci/typos@b63f421581dce830bda2f597a678cb7776b41877 # v1.18.2 with: - config: ./.github/workflows/.spellcheck-conf.toml \ No newline at end of file + config: ./.github/workflows/.spellcheck-conf.toml + + # Run Bandit recursively, but omit _deps directory (with 3rd party code) + - name: Run Bandit + run: python3 -m bandit -r . -x '/_deps/' From 0e235a7f465487172bf3061c386d111613e9f958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Wed, 9 Oct 2024 16:25:56 +0200 Subject: [PATCH 179/352] [CI] Move CodeQL and Trivy back into PR/Push workflow It seems Scorecard is accepting reusable workflows now. Verified on my fork where workflows works properly and there's no change in the Score. --- .github/workflows/pr_push.yml | 12 ++++++++++++ .../{codeql.yml => reusable_codeql.yml} | 14 +------------- .../workflows/{trivy.yml => reusable_trivy.yml} | 17 +---------------- 3 files changed, 14 insertions(+), 29 deletions(-) rename .github/workflows/{codeql.yml => reusable_codeql.yml} (86%) rename .github/workflows/{trivy.yml => reusable_trivy.yml} (69%) diff --git a/.github/workflows/pr_push.yml b/.github/workflows/pr_push.yml index 8ba8b94fa..b8df73975 100644 --- a/.github/workflows/pr_push.yml +++ b/.github/workflows/pr_push.yml @@ -55,3 +55,15 @@ jobs: Coverage: needs: [Build, DevDax, GPU, MultiNuma, Qemu, ProxyLib] uses: ./.github/workflows/reusable_coverage.yml + CodeQL: + needs: [Build] + permissions: + contents: read + security-events: write + uses: ./.github/workflows/reusable_codeql.yml + Trivy: + needs: [Build] + permissions: + contents: read + security-events: write + uses: ./.github/workflows/reusable_trivy.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/reusable_codeql.yml similarity index 86% rename from .github/workflows/codeql.yml rename to .github/workflows/reusable_codeql.yml index 4a8f3ceb5..e2ffae10a 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/reusable_codeql.yml @@ -1,19 +1,7 @@ # CodeQL static analysis name: CodeQL -# Due to lower score on Scorecard we're running this separately from -# "PR/push" workflow. For some reason permissions weren't properly set -# or recognized (by Scorecard). If Scorecard changes its behavior we can -# go back to use 'workflow_call' trigger. -on: - push: - branches-ignore: - - 'dependabot/**' - pull_request: - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true +on: workflow_call permissions: contents: read diff --git a/.github/workflows/trivy.yml b/.github/workflows/reusable_trivy.yml similarity index 69% rename from .github/workflows/trivy.yml rename to .github/workflows/reusable_trivy.yml index 21a76d0cd..c10229276 100644 --- a/.github/workflows/trivy.yml +++ b/.github/workflows/reusable_trivy.yml @@ -1,22 +1,7 @@ # Runs linter for Docker files name: Trivy -# Due to lower score on Scorecard we're running this separately from -# "PR/push" workflow. For some reason permissions weren't properly set -# or recognized (by Scorecard). If Scorecard changes its behavior we can -# use 'workflow_call' trigger. -on: - push: - branches-ignore: - - 'dependabot/**' - pull_request: - paths: - - '.github/docker/*Dockerfile' - - '.github/workflows/trivy.yml' - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true +on: workflow_call permissions: contents: read From 10b93917e571f5ac9edd284dfc823c169116fdf1 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 16 Oct 2024 09:52:52 +0200 Subject: [PATCH 180/352] [CI] Fix all pip installations Latest distros do not allow global pip installation. Python packages have to be installed in venv, on Linux. Signed-off-by: Lukasz Dorau --- .github/workflows/docs.yml | 9 ++++++-- .github/workflows/reusable_checks.yml | 11 ++++++++-- .github/workflows/reusable_codeql.yml | 25 +++++++++++++++-------- .github/workflows/reusable_docs_build.yml | 12 ++++++----- .github/workflows/reusable_qemu.yml | 9 +++++++- 5 files changed, 47 insertions(+), 19 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 6e128b603..3d9bfc29b 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -29,8 +29,13 @@ jobs: sudo apt-get update sudo apt-get install -y doxygen - - name: Install pip requirements - run: python3 -m pip install -r third_party/requirements.txt + # Latest distros do not allow global pip installation + - name: Install Python requirements in venv + run: | + python3 -m venv .venv + . .venv/bin/activate + echo "$PATH" >> $GITHUB_PATH + python3 -m pip install -r third_party/requirements.txt - name: Setup PATH for python run: echo "$HOME/.local/bin" >> $GITHUB_PATH diff --git a/.github/workflows/reusable_checks.yml b/.github/workflows/reusable_checks.yml index 5b7bc6f85..e3e264b0d 100644 --- a/.github/workflows/reusable_checks.yml +++ b/.github/workflows/reusable_checks.yml @@ -22,6 +22,13 @@ jobs: run: | sudo apt-get update sudo apt-get install -y black cmake clang-format-15 cmake-format libhwloc-dev + + # Latest distros do not allow global pip installation + - name: Install Python requirements in venv + run: | + python3 -m venv .venv + . .venv/bin/activate + echo "$PATH" >> $GITHUB_PATH python3 -m pip install bandit - name: Configure CMake @@ -50,6 +57,6 @@ jobs: with: config: ./.github/workflows/.spellcheck-conf.toml - # Run Bandit recursively, but omit _deps directory (with 3rd party code) + # Run Bandit recursively, but omit _deps directory (with 3rd party code) and python's venv - name: Run Bandit - run: python3 -m bandit -r . -x '/_deps/' + run: python3 -m bandit -r . -x '/_deps/,/.venv/' diff --git a/.github/workflows/reusable_codeql.yml b/.github/workflows/reusable_codeql.yml index e2ffae10a..e76456310 100644 --- a/.github/workflows/reusable_codeql.yml +++ b/.github/workflows/reusable_codeql.yml @@ -44,27 +44,34 @@ jobs: with: languages: cpp - - name: Initialize vcpkg - if: ${{ matrix.os == 'windows-latest' }} + - name: "[Win] Initialize vcpkg" + if: matrix.os == 'windows-latest' uses: lukka/run-vcpkg@5e0cab206a5ea620130caf672fce3e4a6b5666a1 # v11.5 with: vcpkgGitCommitId: 3dd44b931481d7a8e9ba412621fa810232b66289 vcpkgDirectory: ${{env.BUILD_DIR}}/vcpkg vcpkgJsonGlob: '**/vcpkg.json' - - name: Install dependencies - if: ${{ matrix.os == 'windows-latest' }} - run: vcpkg install - shell: pwsh # Specifies PowerShell as the shell for running the script. + - name: "[Win] Install dependencies" + if: matrix.os == 'windows-latest' + run: | + vcpkg install + python3 -m pip install -r third_party/requirements.txt - - name: Install apt packages + - name: "[Lin] Install apt packages" if: matrix.os == 'ubuntu-latest' run: | sudo apt-get update sudo apt-get install -y cmake clang libhwloc-dev libnuma-dev libjemalloc-dev libtbb-dev - - name: Install pip packages - run: python3 -m pip install -r third_party/requirements.txt + # Latest distros do not allow global pip installation + - name: "[Lin] Install Python requirements in venv" + if: matrix.os == 'ubuntu-latest' + run: | + python3 -m venv .venv + . .venv/bin/activate + echo "$PATH" >> $GITHUB_PATH + python3 -m pip install -r third_party/requirements.txt - name: Configure CMake run: > diff --git a/.github/workflows/reusable_docs_build.yml b/.github/workflows/reusable_docs_build.yml index 959c81864..269560c67 100644 --- a/.github/workflows/reusable_docs_build.yml +++ b/.github/workflows/reusable_docs_build.yml @@ -21,11 +21,13 @@ jobs: sudo apt-get update sudo apt-get install -y doxygen - - name: Install pip requirements - run: python3 -m pip install -r third_party/requirements.txt - - - name: Setup PATH for python - run: echo "$HOME/.local/bin" >> $GITHUB_PATH + # Latest distros do not allow global pip installation + - name: Install Python requirements in venv + run: | + python3 -m venv .venv + . .venv/bin/activate + echo "$PATH" >> $GITHUB_PATH + python3 -m pip install -r third_party/requirements.txt - name: Build the documentation working-directory: scripts diff --git a/.github/workflows/reusable_qemu.yml b/.github/workflows/reusable_qemu.yml index 7834a8b31..7d6724cdd 100644 --- a/.github/workflows/reusable_qemu.yml +++ b/.github/workflows/reusable_qemu.yml @@ -29,7 +29,14 @@ jobs: sudo apt-get update sudo apt-get install -y qemu-system genisoimage qemu-utils \ libvirt-clients libvirt-daemon-system libvirt-daemon virtinst bridge-utils - pip install -r umf/scripts/qemu/requirements.txt + + # Latest distros do not allow global pip installation + - name: Install Python requirements in venv + run: | + python3 -m venv .venv + . .venv/bin/activate + echo "$PATH" >> $GITHUB_PATH + python3 -m pip install -r umf/scripts/qemu/requirements.txt - name: Add user to kvm group run: sudo usermod -a -G kvm,libvirt $USER From b9fb35204055571682c765b15ff65a468b924db5 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Thu, 17 Oct 2024 11:23:17 +0200 Subject: [PATCH 181/352] Fix updating offset_mmap in file_alloc_aligned() Fixes: #796 Signed-off-by: Lukasz Dorau --- src/provider/provider_file_memory.c | 58 ++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/src/provider/provider_file_memory.c b/src/provider/provider_file_memory.c index bb8cad2e3..274aab0b2 100644 --- a/src/provider/provider_file_memory.c +++ b/src/provider/provider_file_memory.c @@ -263,22 +263,38 @@ static umf_result_t file_mmap_aligned(file_memory_provider_t *file_provider, return UMF_RESULT_ERROR_INVALID_ARGUMENT; // arithmetic overflow } - if (offset_fd + extended_size > size_fd) { - if (utils_fallocate(fd, offset_fd, extended_size)) { + // offset_fd has to be also page-aligned since it is the offset of mmap() + size_t aligned_offset_fd = offset_fd; + rest = aligned_offset_fd & (page_size - 1); + if (rest) { + aligned_offset_fd += page_size - rest; + } + if (aligned_offset_fd < offset_fd) { + LOG_ERR("arithmetic overflow of file offset"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; // arithmetic overflow + } + + if (aligned_offset_fd + extended_size > size_fd) { + size_t new_size_fd = aligned_offset_fd + extended_size; + if (utils_fallocate(fd, size_fd, new_size_fd - size_fd)) { LOG_ERR("cannot grow the file size from %zu to %zu", size_fd, - offset_fd + extended_size); + new_size_fd); return UMF_RESULT_ERROR_UNKNOWN; } - LOG_DEBUG("file size grown from %zu to %zu", size_fd, - offset_fd + extended_size); - file_provider->size_fd = size_fd = offset_fd + extended_size; + LOG_DEBUG("file size grown from %zu to %zu", size_fd, new_size_fd); + file_provider->size_fd = new_size_fd; + } + + if (aligned_offset_fd > offset_fd) { + file_provider->offset_fd = aligned_offset_fd; } ASSERT_IS_ALIGNED(extended_size, page_size); - ASSERT_IS_ALIGNED(offset_fd, page_size); + ASSERT_IS_ALIGNED(aligned_offset_fd, page_size); - void *ptr = utils_mmap_file(NULL, extended_size, prot, flag, fd, offset_fd); + void *ptr = + utils_mmap_file(NULL, extended_size, prot, flag, fd, aligned_offset_fd); if (ptr == NULL) { LOG_PERR("memory mapping failed"); return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; @@ -292,6 +308,10 @@ static umf_result_t file_mmap_aligned(file_memory_provider_t *file_provider, ptr, extended_size); } + LOG_DEBUG( + "inserted a value to the map of memory mapping (addr=%p, size=%zu)", + ptr, extended_size); + file_provider->base_mmap = ptr; file_provider->size_mmap = extended_size; file_provider->offset_mmap = 0; @@ -335,19 +355,31 @@ static umf_result_t file_alloc_aligned(file_memory_provider_t *file_provider, } size_t new_offset_mmap = new_aligned_ptr - (uintptr_t)base_mmap; + size_t new_offset_fd = + file_provider->offset_fd + new_offset_mmap - file_provider->offset_mmap; + if (file_provider->size_mmap - new_offset_mmap < size) { umf_result = file_mmap_aligned(file_provider, size, alignment); if (umf_result != UMF_RESULT_SUCCESS) { utils_mutex_unlock(&file_provider->lock); return umf_result; } + + assert(file_provider->base_mmap); + + // file_provider-> base_mmap, offset_mmap, offset_fd + // were updated by file_mmap_aligned(): + new_aligned_ptr = (uintptr_t)file_provider->base_mmap; + new_offset_mmap = 0; // == file_provider->offset_mmap + new_offset_fd = file_provider->offset_fd; + + ASSERT_IS_ALIGNED(new_aligned_ptr, alignment); } - size_t old_offset_mmap = file_provider->offset_mmap; - file_provider->offset_mmap = new_offset_mmap; - *alloc_offset_fd = - file_provider->offset_fd + new_offset_mmap - old_offset_mmap; - file_provider->offset_fd = *alloc_offset_fd + size; + *alloc_offset_fd = new_offset_fd; + + file_provider->offset_fd = new_offset_fd + size; + file_provider->offset_mmap = new_offset_mmap + size; *out_addr = (void *)new_aligned_ptr; From 62444d34cf8600bd4ba27a308d53b8f1c5c9bd45 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Thu, 17 Oct 2024 11:25:39 +0200 Subject: [PATCH 182/352] Add the two_allocations test Signed-off-by: Lukasz Dorau --- test/provider_file_memory.cpp | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/test/provider_file_memory.cpp b/test/provider_file_memory.cpp index a00f31adc..b2c71635d 100644 --- a/test/provider_file_memory.cpp +++ b/test/provider_file_memory.cpp @@ -183,6 +183,38 @@ INSTANTIATE_TEST_SUITE_P(fileProviderTest, FileProviderParamsDefault, TEST_P(FileProviderParamsDefault, create_destroy) {} +TEST_P(FileProviderParamsDefault, two_allocations) { + umf_result_t umf_result; + void *ptr1 = nullptr; + void *ptr2 = nullptr; + size_t size = page_plus_64; + size_t alignment = page_size; + + umf_result = umfMemoryProviderAlloc(provider.get(), size, alignment, &ptr1); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(ptr1, nullptr); + + umf_result = umfMemoryProviderAlloc(provider.get(), size, alignment, &ptr2); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(ptr2, nullptr); + + ASSERT_NE(ptr1, ptr2); + if ((uintptr_t)ptr1 > (uintptr_t)ptr2) { + ASSERT_GT((uintptr_t)ptr1 - (uintptr_t)ptr2, size); + } else { + ASSERT_GT((uintptr_t)ptr2 - (uintptr_t)ptr1, size); + } + + memset(ptr1, 0x11, size); + memset(ptr2, 0x22, size); + + umf_result = umfMemoryProviderFree(provider.get(), ptr1, size); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); + + umf_result = umfMemoryProviderFree(provider.get(), ptr2, size); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); +} + TEST_P(FileProviderParamsDefault, alloc_page64_align_0) { test_alloc_free_success(provider.get(), page_plus_64, 0, PURGE_NONE); } From 3034a848a95fc2a2abb1c7a55d6a2584d370ffde Mon Sep 17 00:00:00 2001 From: Sergei Vinogradov Date: Sun, 20 Oct 2024 23:23:56 +0200 Subject: [PATCH 183/352] Remove an unnecessary parameter in openHandlesFn lambda --- test/ipcFixtures.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ipcFixtures.hpp b/test/ipcFixtures.hpp index 22d687eac..776ea7aab 100644 --- a/test/ipcFixtures.hpp +++ b/test/ipcFixtures.hpp @@ -461,7 +461,7 @@ TEST_P(umfIpcTest, ConcurrentOpenCloseHandles) { umf_test::syncthreads_barrier syncthreads(NTHREADS); - auto openHandlesFn = [this, &ipcHandles, &openedIpcHandles, &syncthreads, + auto openHandlesFn = [&ipcHandles, &openedIpcHandles, &syncthreads, &pool](size_t tid) { syncthreads(); for (auto ipcHandle : ipcHandles) { From 7a210f0db6e8a083e5c2c86a000fc3831f600eb0 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 21 Oct 2024 09:24:56 +0200 Subject: [PATCH 184/352] Add parameter to destroy upstream_memory_provider in finalize() Signed-off-by: Lukasz Dorau --- include/umf/providers/provider_coarse.h | 3 ++ src/provider/provider_coarse.c | 17 ++++++++++ test/disjointCoarseMallocPool.cpp | 45 ++++++++++++++++++++++--- 3 files changed, 61 insertions(+), 4 deletions(-) diff --git a/include/umf/providers/provider_coarse.h b/include/umf/providers/provider_coarse.h index 16d11fd77..22b59a61b 100644 --- a/include/umf/providers/provider_coarse.h +++ b/include/umf/providers/provider_coarse.h @@ -69,6 +69,9 @@ typedef struct coarse_memory_provider_params_t { /// 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) diff --git a/src/provider/provider_coarse.c b/src/provider/provider_coarse.c index 872d994be..800463d8a 100644 --- a/src/provider/provider_coarse.c +++ b/src/provider/provider_coarse.c @@ -31,6 +31,9 @@ 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; @@ -898,6 +901,13 @@ static umf_result_t coarse_memory_provider_initialize(void *params, 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) { @@ -909,6 +919,8 @@ static umf_result_t coarse_memory_provider_initialize(void *params, 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; @@ -1081,6 +1093,11 @@ static void coarse_memory_provider_finalize(void *provider) { 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); } diff --git a/test/disjointCoarseMallocPool.cpp b/test/disjointCoarseMallocPool.cpp index b3eb3f91b..fcb3238ee 100644 --- a/test/disjointCoarseMallocPool.cpp +++ b/test/disjointCoarseMallocPool.cpp @@ -59,6 +59,7 @@ TEST_F(test, disjointCoarseMallocPool_name_upstream) { 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; @@ -75,7 +76,9 @@ TEST_F(test, disjointCoarseMallocPool_name_upstream) { 0); umfMemoryProviderDestroy(coarse_memory_provider); - umfMemoryProviderDestroy(malloc_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, disjointCoarseMallocPool_name_no_upstream) { @@ -129,6 +132,7 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_basic) { 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; @@ -150,7 +154,7 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_basic) { umf_memory_pool_handle_t pool; umf_result = umfPoolCreate(umfDisjointPoolOps(), coarse_memory_provider, &disjoint_memory_pool_params, - UMF_POOL_CREATE_FLAG_NONE, &pool); + UMF_POOL_CREATE_FLAG_OWN_PROVIDER, &pool); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(pool, nullptr); @@ -282,8 +286,10 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_basic) { ASSERT_EQ(GetStats(prov).alloc_size, init_buffer_size); umfPoolDestroy(pool); - umfMemoryProviderDestroy(coarse_memory_provider); - umfMemoryProviderDestroy(malloc_memory_provider); + // 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) { @@ -760,6 +766,37 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_wrong_params_4) { umfMemoryProviderDestroy(malloc_memory_provider); } +// wrong parameters: destroy_upstream_memory_provider is true, but an upstream provider is not provided +TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_wrong_params_5) { + umf_result_t umf_result; + + const size_t init_buffer_size = 20 * MB; + + // Preallocate some memory + std::unique_ptr buffer(new char[init_buffer_size]); + void *buf = buffer.get(); + ASSERT_NE(buf, nullptr); + memset(buf, 0, init_buffer_size); + + 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, disjointCoarseMallocPool_split_merge) { umf_memory_provider_handle_t malloc_memory_provider; umf_result_t umf_result; From 9957bb75c0fd44e9345ec58de9f039809fd2a5bb Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 21 Oct 2024 11:38:01 +0200 Subject: [PATCH 185/352] Fix similar error messages Replace "provider is failed to" with "provider failed to". Signed-off-by: Lukasz Dorau --- src/provider/provider_tracking.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/provider/provider_tracking.c b/src/provider/provider_tracking.c index 5e10a9404..70f63f937 100644 --- a/src/provider/provider_tracking.c +++ b/src/provider/provider_tracking.c @@ -362,7 +362,7 @@ static umf_result_t trackingFree(void *hProvider, void *ptr, size_t size) { ret = umfMemoryProviderPutIPCHandle(p->hUpstream, cache_value->providerIpcData); if (ret != UMF_RESULT_SUCCESS) { - LOG_ERR("upstream provider is failed to put IPC handle, ptr=%p, " + LOG_ERR("upstream provider failed to put IPC handle, ptr=%p, " "size=%zu, ret = %d", ptr, size, ret); } @@ -371,7 +371,7 @@ static umf_result_t trackingFree(void *hProvider, void *ptr, size_t size) { ret = umfMemoryProviderFree(p->hUpstream, ptr, size); if (ret != UMF_RESULT_SUCCESS) { - LOG_ERR("upstream provider is failed to free the memory"); + LOG_ERR("upstream provider failed to free the memory"); // Do not add memory back to the tracker, // if it had not been removed. if (ret_remove != UMF_RESULT_SUCCESS) { @@ -537,18 +537,18 @@ static umf_result_t trackingGetIpcHandle(void *provider, const void *ptr, ret = umfMemoryProviderGetIPCHandle(p->hUpstream, ptr, size, providerIpcData); if (ret != UMF_RESULT_SUCCESS) { - LOG_ERR("upstream provider is failed to get IPC handle"); + LOG_ERR("upstream provider failed to get IPC handle"); return ret; } ret = umfMemoryProviderGetIPCHandleSize(p->hUpstream, &ipcDataSize); if (ret != UMF_RESULT_SUCCESS) { - LOG_ERR("upstream provider is failed to get the size of IPC " + LOG_ERR("upstream provider failed to get the size of IPC " "handle"); ret = umfMemoryProviderPutIPCHandle(p->hUpstream, providerIpcData); if (ret != UMF_RESULT_SUCCESS) { - LOG_ERR("upstream provider is failed to put IPC handle"); + LOG_ERR("upstream provider failed to put IPC handle"); } return ret; } @@ -560,7 +560,7 @@ static umf_result_t trackingGetIpcHandle(void *provider, const void *ptr, ret = umfMemoryProviderPutIPCHandle(p->hUpstream, providerIpcData); if (ret != UMF_RESULT_SUCCESS) { - LOG_ERR("upstream provider is failed to put IPC handle"); + LOG_ERR("upstream provider failed to put IPC handle"); } return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; } @@ -586,7 +586,7 @@ static umf_result_t trackingGetIpcHandle(void *provider, const void *ptr, ret = umfMemoryProviderPutIPCHandle(p->hUpstream, providerIpcData); if (ret != UMF_RESULT_SUCCESS) { - LOG_ERR("upstream provider is failed to put IPC handle"); + LOG_ERR("upstream provider failed to put IPC handle"); return ret; } if (insRes == ENOMEM) { @@ -632,7 +632,7 @@ static umf_result_t trackingOpenIpcHandle(void *provider, void *providerIpcData, ret = umfMemoryProviderOpenIPCHandle(p->hUpstream, providerIpcData, ptr); if (ret != UMF_RESULT_SUCCESS) { - LOG_ERR("upstream provider is failed to open IPC handle"); + LOG_ERR("upstream provider failed to open IPC handle"); return ret; } size_t bufferSize = getDataSizeFromIpcHandle(providerIpcData); @@ -642,7 +642,7 @@ static umf_result_t trackingOpenIpcHandle(void *provider, void *providerIpcData, "ret = %d", *ptr, bufferSize, ret); if (umfMemoryProviderCloseIPCHandle(p->hUpstream, *ptr, bufferSize)) { - LOG_ERR("upstream provider is failed to close IPC handle, ptr=%p, " + LOG_ERR("upstream provider failed to close IPC handle, ptr=%p, " "size=%zu", *ptr, bufferSize); } From 80f07fd8ea4405e62266edbb348e863743f05846 Mon Sep 17 00:00:00 2001 From: Agata Momot Date: Mon, 21 Oct 2024 09:15:38 +0000 Subject: [PATCH 186/352] fix: replace UT_ASSERTs with GTEST asserts ref. #569 --- test/memspaces/memspace_host_all.cpp | 6 +++--- test/memspaces/memspace_numa.cpp | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/test/memspaces/memspace_host_all.cpp b/test/memspaces/memspace_host_all.cpp index 846bd5fe0..3462b87dc 100644 --- a/test/memspaces/memspace_host_all.cpp +++ b/test/memspaces/memspace_host_all.cpp @@ -126,7 +126,7 @@ TEST_F(memspaceHostAllProviderTest, hostAllDefaults) { EXPECT_BIND_MASK_EQ(ptr1, ptr2); auto ret2 = munmap(ptr2, size); - UT_ASSERTeq(ret2, 0); + ASSERT_EQ(ret2, 0); ret = umfMemoryProviderFree(hProvider, ptr1, size); ASSERT_EQ(ret, UMF_RESULT_SUCCESS); @@ -181,10 +181,10 @@ TEST_F(memspaceHostAllProviderTest, HostAllVsCopy) { ASSERT_BIND_MODE_EQ(ptr2, MPOL_BIND); ret = umfMemoryProviderFree(hProvider1, ptr1, SIZE_4K); - UT_ASSERTeq(ret, UMF_RESULT_SUCCESS); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); ret = umfMemoryProviderFree(hProvider2, ptr2, SIZE_4K); - UT_ASSERTeq(ret, UMF_RESULT_SUCCESS); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); umfMemoryProviderDestroy(hProvider1); umfMemoryProviderDestroy(hProvider2); diff --git a/test/memspaces/memspace_numa.cpp b/test/memspaces/memspace_numa.cpp index b10ed4e58..068df6886 100644 --- a/test/memspaces/memspace_numa.cpp +++ b/test/memspaces/memspace_numa.cpp @@ -152,10 +152,10 @@ TEST_F(memspaceNumaTest, memspaceCopyTarget) { ASSERT_BIND_MODE_EQ(ptr1, ptr2); ret = umfMemoryProviderFree(hProvider1, ptr1, SIZE_4K); - UT_ASSERTeq(ret, UMF_RESULT_SUCCESS); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); ret = umfMemoryProviderFree(hProvider2, ptr2, SIZE_4K); - UT_ASSERTeq(ret, UMF_RESULT_SUCCESS); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); umfMemoryProviderDestroy(hProvider1); umfMemoryProviderDestroy(hProvider2); @@ -211,10 +211,10 @@ TEST_F(memspaceNumaTest, memspaceDeleteTarget) { ASSERT_BIND_MODE_EQ(ptr1, ptr2); ret = umfMemoryProviderFree(hProvider1, ptr1, SIZE_4K); - UT_ASSERTeq(ret, UMF_RESULT_SUCCESS); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); ret = umfMemoryProviderFree(hProvider2, ptr2, SIZE_4K); - UT_ASSERTeq(ret, UMF_RESULT_SUCCESS); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); umfMemoryProviderDestroy(hProvider1); umfMemoryProviderDestroy(hProvider2); From 4b668af5d7ec80e4f176796c67b675057a3f34b6 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 21 Oct 2024 14:36:27 +0200 Subject: [PATCH 187/352] Add optional coarse provider to umfPoolTest fixture Add optional coarse provider to umfPoolTest fixture. Add 5th argument (coarse_memory_provider_params_t *) to the poolCreateExtParams tuple (can be nullptr). If it is non-nullptr, coarse provider is created with the given provider as the upstream provider. It will be used to test the following providers: - file provider - devdax provider as the upstream providers with the coarse provider and different pool managers. Signed-off-by: Lukasz Dorau --- test/memoryPoolAPI.cpp | 8 ++++--- test/poolFixtures.hpp | 44 +++++++++++++++++++++++++++------- test/pools/disjoint_pool.cpp | 6 ++--- test/pools/jemalloc_pool.cpp | 8 ++++--- test/pools/pool_base_alloc.cpp | 2 +- test/pools/scalable_pool.cpp | 3 ++- 6 files changed, 51 insertions(+), 20 deletions(-) diff --git a/test/memoryPoolAPI.cpp b/test/memoryPoolAPI.cpp index 96fd634c6..d761780d0 100644 --- a/test/memoryPoolAPI.cpp +++ b/test/memoryPoolAPI.cpp @@ -181,14 +181,16 @@ TEST_F(test, BasicPoolByPtrTest) { INSTANTIATE_TEST_SUITE_P( mallocPoolTest, umfPoolTest, ::testing::Values(poolCreateExtParams{&MALLOC_POOL_OPS, nullptr, - &UMF_NULL_PROVIDER_OPS, nullptr}, + &UMF_NULL_PROVIDER_OPS, nullptr, + nullptr}, poolCreateExtParams{umfProxyPoolOps(), nullptr, - &MALLOC_PROVIDER_OPS, nullptr})); + &MALLOC_PROVIDER_OPS, nullptr, + nullptr})); INSTANTIATE_TEST_SUITE_P(mallocMultiPoolTest, umfMultiPoolTest, ::testing::Values(poolCreateExtParams{ umfProxyPoolOps(), nullptr, &MALLOC_PROVIDER_OPS, - nullptr})); + nullptr, nullptr})); INSTANTIATE_TEST_SUITE_P(umfPoolWithCreateFlagsTest, umfPoolWithCreateFlagsTest, ::testing::Values(0, diff --git a/test/poolFixtures.hpp b/test/poolFixtures.hpp index 1285c57bf..b2b580b26 100644 --- a/test/poolFixtures.hpp +++ b/test/poolFixtures.hpp @@ -2,11 +2,12 @@ // Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#ifndef UMF_TEST_MEMORY_POOL_OPS_HPP -#define UMF_TEST_MEMORY_POOL_OPS_HPP +#ifndef UMF_TEST_POOL_FIXTURES_HPP +#define UMF_TEST_POOL_FIXTURES_HPP 1 #include "pool.hpp" #include "provider.hpp" +#include "umf/providers/provider_coarse.h" #include #include @@ -17,21 +18,46 @@ #include "../malloc_compliance_tests.hpp" -using poolCreateExtParams = std::tuple; +using poolCreateExtParams = + std::tuple; umf::pool_unique_handle_t poolCreateExtUnique(poolCreateExtParams params) { - umf_memory_pool_handle_t hPool; - auto [pool_ops, pool_params, provider_ops, provider_params] = params; + auto [pool_ops, pool_params, provider_ops, provider_params, coarse_params] = + params; + umf_memory_provider_handle_t upstream_provider = nullptr; umf_memory_provider_handle_t provider = nullptr; - auto ret = - umfMemoryProviderCreate(provider_ops, provider_params, &provider); + umf_memory_pool_handle_t hPool = nullptr; + umf_result_t ret; + + ret = umfMemoryProviderCreate(provider_ops, provider_params, + &upstream_provider); EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + EXPECT_NE(upstream_provider, nullptr); + + 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); + EXPECT_NE(hPool, nullptr); return umf::pool_unique_handle_t(hPool, &umfPoolDestroy); } @@ -407,4 +433,4 @@ TEST_P(umfPoolTest, realloc_compliance) { TEST_P(umfPoolTest, free_compliance) { free_compliance_test(pool.get()); } -#endif /* UMF_TEST_MEMORY_POOL_OPS_HPP */ +#endif /* UMF_TEST_POOL_FIXTURES_HPP */ diff --git a/test/pools/disjoint_pool.cpp b/test/pools/disjoint_pool.cpp index d7612f4d5..09488c92b 100644 --- a/test/pools/disjoint_pool.cpp +++ b/test/pools/disjoint_pool.cpp @@ -148,17 +148,17 @@ auto defaultPoolConfig = poolConfig(); INSTANTIATE_TEST_SUITE_P(disjointPoolTests, umfPoolTest, ::testing::Values(poolCreateExtParams{ umfDisjointPoolOps(), (void *)&defaultPoolConfig, - &MALLOC_PROVIDER_OPS, nullptr})); + &MALLOC_PROVIDER_OPS, nullptr, nullptr})); INSTANTIATE_TEST_SUITE_P( disjointPoolTests, umfMemTest, ::testing::Values(std::make_tuple( poolCreateExtParams{umfDisjointPoolOps(), (void *)&defaultPoolConfig, &MOCK_OUT_OF_MEM_PROVIDER_OPS, - (void *)&defaultPoolConfig.Capacity}, + (void *)&defaultPoolConfig.Capacity, nullptr}, static_cast(defaultPoolConfig.Capacity) / 2))); INSTANTIATE_TEST_SUITE_P(disjointMultiPoolTests, umfMultiPoolTest, ::testing::Values(poolCreateExtParams{ umfDisjointPoolOps(), (void *)&defaultPoolConfig, - &MALLOC_PROVIDER_OPS, nullptr})); + &MALLOC_PROVIDER_OPS, nullptr, nullptr})); diff --git a/test/pools/jemalloc_pool.cpp b/test/pools/jemalloc_pool.cpp index 331c96f04..8659e9836 100644 --- a/test/pools/jemalloc_pool.cpp +++ b/test/pools/jemalloc_pool.cpp @@ -15,7 +15,8 @@ auto defaultParams = umfOsMemoryProviderParamsDefault(); INSTANTIATE_TEST_SUITE_P(jemallocPoolTest, umfPoolTest, ::testing::Values(poolCreateExtParams{ umfJemallocPoolOps(), nullptr, - umfOsMemoryProviderOps(), &defaultParams})); + umfOsMemoryProviderOps(), &defaultParams, + nullptr})); // this test makes sure that jemalloc does not use // memory provider to allocate metadata (and hence @@ -30,8 +31,9 @@ TEST_F(test, metadataNotAllocatedUsingProvider) { auto params = umfOsMemoryProviderParamsDefault(); params.protection = UMF_PROTECTION_NONE; - auto pool = poolCreateExtUnique( - {umfJemallocPoolOps(), nullptr, umfOsMemoryProviderOps(), ¶ms}); + auto pool = + poolCreateExtUnique({umfJemallocPoolOps(), nullptr, + umfOsMemoryProviderOps(), ¶ms, nullptr}); std::vector> allocs; for (size_t i = 0; i < numAllocs; i++) { diff --git a/test/pools/pool_base_alloc.cpp b/test/pools/pool_base_alloc.cpp index ec07a7c2f..7c9a3701a 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})); + &umf_test::BASE_PROVIDER_OPS, nullptr, nullptr})); diff --git a/test/pools/scalable_pool.cpp b/test/pools/scalable_pool.cpp index bdd0682f5..2be29eb9d 100644 --- a/test/pools/scalable_pool.cpp +++ b/test/pools/scalable_pool.cpp @@ -12,4 +12,5 @@ auto defaultParams = umfOsMemoryProviderParamsDefault(); INSTANTIATE_TEST_SUITE_P(scalablePoolTest, umfPoolTest, ::testing::Values(poolCreateExtParams{ umfScalablePoolOps(), nullptr, - umfOsMemoryProviderOps(), &defaultParams})); + umfOsMemoryProviderOps(), &defaultParams, + nullptr})); From 357349fb1e44166b1e72f73a1cc468680bd2e5e3 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Fri, 18 Oct 2024 13:50:27 -0700 Subject: [PATCH 188/352] Fix CUDA provider to use proper context --- src/provider/provider_cuda.c | 58 ++++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/src/provider/provider_cuda.c b/src/provider/provider_cuda.c index 85d6d9b79..4d7a26516 100644 --- a/src/provider/provider_cuda.c +++ b/src/provider/provider_cuda.c @@ -51,6 +51,8 @@ typedef struct cu_ops_t { CUresult (*cuGetErrorName)(CUresult error, const char **pStr); CUresult (*cuGetErrorString)(CUresult error, const char **pStr); + CUresult (*cuCtxGetCurrent)(CUcontext *pctx); + CUresult (*cuCtxSetCurrent)(CUcontext ctx); } cu_ops_t; static cu_ops_t g_cu_ops; @@ -117,11 +119,16 @@ static void init_cu_global_state(void) { utils_get_symbol_addr(0, "cuGetErrorName", lib_name); *(void **)&g_cu_ops.cuGetErrorString = utils_get_symbol_addr(0, "cuGetErrorString", lib_name); + *(void **)&g_cu_ops.cuCtxGetCurrent = + utils_get_symbol_addr(0, "cuCtxGetCurrent", lib_name); + *(void **)&g_cu_ops.cuCtxSetCurrent = + utils_get_symbol_addr(0, "cuCtxSetCurrent", lib_name); if (!g_cu_ops.cuMemGetAllocationGranularity || !g_cu_ops.cuMemAlloc || !g_cu_ops.cuMemAllocHost || !g_cu_ops.cuMemAllocManaged || !g_cu_ops.cuMemFree || !g_cu_ops.cuMemFreeHost || - !g_cu_ops.cuGetErrorName || !g_cu_ops.cuGetErrorString) { + !g_cu_ops.cuGetErrorName || !g_cu_ops.cuGetErrorString || + !g_cu_ops.cuCtxGetCurrent || !g_cu_ops.cuCtxSetCurrent) { LOG_ERR("Required CUDA symbols not found."); Init_cu_global_state_failed = true; } @@ -190,6 +197,31 @@ static void cu_memory_provider_finalize(void *provider) { umf_ba_global_free(provider); } +/* + * This function is used by the CUDA provider to make sure that + * the required context is set. If the current context is + * not the required one, it will be saved in restore_ctx. + */ +static inline umf_result_t set_context(CUcontext required_ctx, + CUcontext *restore_ctx) { + CUcontext current_ctx = NULL; + CUresult cu_result = g_cu_ops.cuCtxGetCurrent(¤t_ctx); + if (cu_result != CUDA_SUCCESS) { + LOG_ERR("cuCtxGetCurrent() failed."); + return cu2umf_result(cu_result); + } + *restore_ctx = current_ctx; + if (current_ctx != required_ctx) { + cu_result = g_cu_ops.cuCtxSetCurrent(required_ctx); + if (cu_result != CUDA_SUCCESS) { + LOG_ERR("cuCtxSetCurrent() failed."); + return cu2umf_result(cu_result); + } + } + + return UMF_RESULT_SUCCESS; +} + static umf_result_t cu_memory_provider_alloc(void *provider, size_t size, size_t alignment, void **resultPtr) { @@ -205,6 +237,14 @@ static umf_result_t cu_memory_provider_alloc(void *provider, size_t size, return UMF_RESULT_ERROR_NOT_SUPPORTED; } + // Remember current context and set the one from the provider + CUcontext restore_ctx = NULL; + umf_result_t umf_result = set_context(cu_provider->context, &restore_ctx); + if (umf_result != UMF_RESULT_SUCCESS) { + LOG_ERR("Failed to set CUDA context, ret = %d", umf_result); + return umf_result; + } + CUresult cu_result = CUDA_SUCCESS; switch (cu_provider->memory_type) { case UMF_MEMORY_TYPE_HOST: { @@ -224,17 +264,29 @@ static umf_result_t cu_memory_provider_alloc(void *provider, size_t size, // this shouldn't happen as we check the memory_type settings during // the initialization LOG_ERR("unsupported USM memory type"); + assert(false); return UMF_RESULT_ERROR_UNKNOWN; } + umf_result = set_context(restore_ctx, &restore_ctx); + if (umf_result != UMF_RESULT_SUCCESS) { + LOG_ERR("Failed to restore CUDA context, ret = %d", umf_result); + } + + umf_result = cu2umf_result(cu_result); + if (umf_result != UMF_RESULT_SUCCESS) { + LOG_ERR("Failed to allocate memory, cu_result = %d, ret = %d", + cu_result, umf_result); + return umf_result; + } + // check the alignment if (alignment > 0 && ((uintptr_t)(*resultPtr) % alignment) != 0) { cu_memory_provider_free(provider, *resultPtr, size); LOG_ERR("unsupported alignment size"); return UMF_RESULT_ERROR_INVALID_ALIGNMENT; } - - return cu2umf_result(cu_result); + return umf_result; } static umf_result_t cu_memory_provider_free(void *provider, void *ptr, From b20cf014cb23e27dd88353b3b8a5870476c1a713 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Thu, 17 Oct 2024 09:01:14 -0700 Subject: [PATCH 189/352] Updated CUDA provider tests --- test/providers/cuda_helpers.cpp | 58 +++++++++++++++++++++++---- test/providers/cuda_helpers.h | 4 ++ test/providers/provider_cuda.cpp | 69 +++++++++++++++----------------- 3 files changed, 86 insertions(+), 45 deletions(-) diff --git a/test/providers/cuda_helpers.cpp b/test/providers/cuda_helpers.cpp index 366efc197..2b332dde1 100644 --- a/test/providers/cuda_helpers.cpp +++ b/test/providers/cuda_helpers.cpp @@ -17,6 +17,7 @@ struct libcu_ops { CUresult (*cuInit)(unsigned int flags); CUresult (*cuCtxCreate)(CUcontext *pctx, unsigned int flags, CUdevice dev); CUresult (*cuCtxDestroy)(CUcontext ctx); + CUresult (*cuCtxGetCurrent)(CUcontext *pctx); CUresult (*cuDeviceGet)(CUdevice *device, int ordinal); CUresult (*cuMemAlloc)(CUdeviceptr *dptr, size_t size); CUresult (*cuMemFree)(CUdeviceptr dptr); @@ -26,7 +27,9 @@ struct libcu_ops { CUresult (*cuMemFreeHost)(void *p); CUresult (*cuMemsetD32)(CUdeviceptr dstDevice, unsigned int pattern, size_t size); - CUresult (*cuMemcpyDtoH)(void *dstHost, CUdeviceptr srcDevice, size_t size); + CUresult (*cuMemcpy)(CUdeviceptr dst, CUdeviceptr src, size_t size); + CUresult (*cuPointerGetAttribute)(void *data, CUpointer_attribute attribute, + CUdeviceptr ptr); CUresult (*cuPointerGetAttributes)(unsigned int numAttributes, CUpointer_attribute *attributes, void **data, CUdeviceptr ptr); @@ -74,6 +77,12 @@ int InitCUDAOps() { fprintf(stderr, "cuCtxDestroy symbol not found in %s\n", lib_name); return -1; } + *(void **)&libcu_ops.cuCtxGetCurrent = + utils_get_symbol_addr(cuDlHandle.get(), "cuCtxGetCurrent", lib_name); + if (libcu_ops.cuCtxGetCurrent == nullptr) { + fprintf(stderr, "cuCtxGetCurrent symbol not found in %s\n", lib_name); + return -1; + } *(void **)&libcu_ops.cuDeviceGet = utils_get_symbol_addr(cuDlHandle.get(), "cuDeviceGet", lib_name); if (libcu_ops.cuDeviceGet == nullptr) { @@ -116,10 +125,17 @@ int InitCUDAOps() { fprintf(stderr, "cuMemsetD32_v2 symbol not found in %s\n", lib_name); return -1; } - *(void **)&libcu_ops.cuMemcpyDtoH = - utils_get_symbol_addr(cuDlHandle.get(), "cuMemcpyDtoH_v2", lib_name); - if (libcu_ops.cuMemcpyDtoH == nullptr) { - fprintf(stderr, "cuMemcpyDtoH_v2 symbol not found in %s\n", lib_name); + *(void **)&libcu_ops.cuMemcpy = + utils_get_symbol_addr(cuDlHandle.get(), "cuMemcpy", lib_name); + if (libcu_ops.cuMemcpy == nullptr) { + fprintf(stderr, "cuMemcpy symbol not found in %s\n", lib_name); + return -1; + } + *(void **)&libcu_ops.cuPointerGetAttribute = utils_get_symbol_addr( + cuDlHandle.get(), "cuPointerGetAttribute", lib_name); + if (libcu_ops.cuPointerGetAttribute == nullptr) { + fprintf(stderr, "cuPointerGetAttribute symbol not found in %s\n", + lib_name); return -1; } *(void **)&libcu_ops.cuPointerGetAttributes = utils_get_symbol_addr( @@ -140,6 +156,7 @@ int InitCUDAOps() { libcu_ops.cuInit = cuInit; libcu_ops.cuCtxCreate = cuCtxCreate; libcu_ops.cuCtxDestroy = cuCtxDestroy; + libcu_ops.cuCtxGetCurrent = cuCtxGetCurrent; libcu_ops.cuDeviceGet = cuDeviceGet; libcu_ops.cuMemAlloc = cuMemAlloc; libcu_ops.cuMemAllocHost = cuMemAllocHost; @@ -147,7 +164,8 @@ int InitCUDAOps() { libcu_ops.cuMemFree = cuMemFree; libcu_ops.cuMemFreeHost = cuMemFreeHost; libcu_ops.cuMemsetD32 = cuMemsetD32; - libcu_ops.cuMemcpyDtoH = cuMemcpyDtoH; + libcu_ops.cuMemcpy = cuMemcpy; + libcu_ops.cuPointerGetAttribute = cuPointerGetAttribute; libcu_ops.cuPointerGetAttributes = cuPointerGetAttributes; return 0; @@ -193,9 +211,10 @@ int cuda_copy(CUcontext context, CUdevice device, void *dst_ptr, void *src_ptr, (void)device; int ret = 0; - CUresult res = libcu_ops.cuMemcpyDtoH(dst_ptr, (CUdeviceptr)src_ptr, size); + CUresult res = + libcu_ops.cuMemcpy((CUdeviceptr)dst_ptr, (CUdeviceptr)src_ptr, size); if (res != CUDA_SUCCESS) { - fprintf(stderr, "cuMemcpyDtoH() failed!\n"); + fprintf(stderr, "cuMemcpy() failed!\n"); return -1; } @@ -230,6 +249,29 @@ umf_usm_memory_type_t get_mem_type(CUcontext context, void *ptr) { return UMF_MEMORY_TYPE_UNKNOWN; } +CUcontext get_mem_context(void *ptr) { + CUcontext context; + CUresult res = libcu_ops.cuPointerGetAttribute( + &context, CU_POINTER_ATTRIBUTE_CONTEXT, (CUdeviceptr)ptr); + if (res != CUDA_SUCCESS) { + fprintf(stderr, "cuPointerGetAttribute() failed!\n"); + return nullptr; + } + + return context; +} + +CUcontext get_current_context() { + CUcontext context; + CUresult res = libcu_ops.cuCtxGetCurrent(&context); + if (res != CUDA_SUCCESS) { + fprintf(stderr, "cuCtxGetCurrent() failed!\n"); + return nullptr; + } + + return context; +} + UTIL_ONCE_FLAG cuda_init_flag; int InitResult; void init_cuda_once() { diff --git a/test/providers/cuda_helpers.h b/test/providers/cuda_helpers.h index 3227fc9c5..5e42153bb 100644 --- a/test/providers/cuda_helpers.h +++ b/test/providers/cuda_helpers.h @@ -26,6 +26,10 @@ int cuda_copy(CUcontext context, CUdevice device, void *dst_ptr, void *src_ptr, umf_usm_memory_type_t get_mem_type(CUcontext context, void *ptr); +CUcontext get_mem_context(void *ptr); + +CUcontext get_current_context(); + cuda_memory_provider_params_t create_cuda_prov_params(umf_usm_memory_type_t memory_type); diff --git a/test/providers/provider_cuda.cpp b/test/providers/provider_cuda.cpp index f563d45c8..4bdbbba73 100644 --- a/test/providers/provider_cuda.cpp +++ b/test/providers/provider_cuda.cpp @@ -21,10 +21,8 @@ using namespace umf_test; class CUDAMemoryAccessor : public MemoryAccessor { public: - void init(CUcontext hContext, CUdevice hDevice) { - hDevice_ = hDevice; - hContext_ = hContext; - } + CUDAMemoryAccessor(CUcontext hContext, CUdevice hDevice) + : hDevice_(hDevice), hContext_(hContext) {} void fill(void *ptr, size_t size, const void *pattern, size_t pattern_size) { @@ -53,7 +51,7 @@ class CUDAMemoryAccessor : public MemoryAccessor { }; using CUDAProviderTestParams = - std::tuple; + std::tuple; struct umfCUDAProviderTest : umf_test::test, @@ -62,23 +60,12 @@ struct umfCUDAProviderTest void SetUp() override { test::SetUp(); - auto [memory_type, accessor] = this->GetParam(); - params = create_cuda_prov_params(memory_type); + auto [cuda_params, accessor] = this->GetParam(); + params = cuda_params; memAccessor = accessor; - if (memory_type == UMF_MEMORY_TYPE_DEVICE) { - ((CUDAMemoryAccessor *)memAccessor) - ->init((CUcontext)params.cuda_context_handle, - params.cuda_device_handle); - } } - void TearDown() override { - if (params.cuda_context_handle) { - int ret = destroy_context((CUcontext)params.cuda_context_handle); - ASSERT_EQ(ret, 0); - } - test::TearDown(); - } + void TearDown() override { test::TearDown(); } cuda_memory_provider_params_t params; MemoryAccessor *memAccessor = nullptr; @@ -87,6 +74,7 @@ struct umfCUDAProviderTest TEST_P(umfCUDAProviderTest, basic) { const size_t size = 1024 * 8; const uint32_t pattern = 0xAB; + CUcontext expected_current_context = get_current_context(); // create CUDA provider umf_memory_provider_handle_t provider = nullptr; @@ -113,6 +101,12 @@ TEST_P(umfCUDAProviderTest, basic) { // use the allocated memory - fill it with a 0xAB pattern memAccessor->fill(ptr, size, &pattern, sizeof(pattern)); + CUcontext actual_mem_context = get_mem_context(ptr); + ASSERT_EQ(actual_mem_context, (CUcontext)params.cuda_context_handle); + + CUcontext actual_current_context = get_current_context(); + ASSERT_EQ(actual_current_context, expected_current_context); + umf_usm_memory_type_t memoryTypeActual = get_mem_type((CUcontext)params.cuda_context_handle, ptr); ASSERT_EQ(memoryTypeActual, params.memory_type); @@ -132,6 +126,7 @@ TEST_P(umfCUDAProviderTest, basic) { } TEST_P(umfCUDAProviderTest, allocInvalidSize) { + CUcontext expected_current_context = get_current_context(); // create CUDA provider umf_memory_provider_handle_t provider = nullptr; umf_result_t umf_result = @@ -151,32 +146,32 @@ TEST_P(umfCUDAProviderTest, allocInvalidSize) { ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); } - // destroy context and try to alloc some memory - destroy_context((CUcontext)params.cuda_context_handle); - params.cuda_context_handle = 0; - umf_result = umfMemoryProviderAlloc(provider, 128, 0, &ptr); - ASSERT_EQ(umf_result, UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC); - - const char *message; - int32_t error; - umfMemoryProviderGetLastNativeError(provider, &message, &error); - ASSERT_EQ(error, CUDA_ERROR_INVALID_CONTEXT); - const char *expected_message = - "CUDA_ERROR_INVALID_CONTEXT - invalid device context"; - ASSERT_EQ(strncmp(message, expected_message, strlen(expected_message)), 0); + CUcontext actual_current_context = get_current_context(); + ASSERT_EQ(actual_current_context, expected_current_context); + + umfMemoryProviderDestroy(provider); } // TODO add tests that mixes CUDA Memory Provider and Disjoint Pool -CUDAMemoryAccessor cuAccessor; +cuda_memory_provider_params_t cuParams_device_memory = + create_cuda_prov_params(UMF_MEMORY_TYPE_DEVICE); +cuda_memory_provider_params_t cuParams_shared_memory = + create_cuda_prov_params(UMF_MEMORY_TYPE_SHARED); +cuda_memory_provider_params_t cuParams_host_memory = + create_cuda_prov_params(UMF_MEMORY_TYPE_HOST); + +CUDAMemoryAccessor + cuAccessor((CUcontext)cuParams_device_memory.cuda_context_handle, + (CUdevice)cuParams_device_memory.cuda_device_handle); HostMemoryAccessor hostAccessor; INSTANTIATE_TEST_SUITE_P( umfCUDAProviderTestSuite, umfCUDAProviderTest, ::testing::Values( - CUDAProviderTestParams{UMF_MEMORY_TYPE_DEVICE, &cuAccessor}, - CUDAProviderTestParams{UMF_MEMORY_TYPE_SHARED, &hostAccessor}, - CUDAProviderTestParams{UMF_MEMORY_TYPE_HOST, &hostAccessor})); + CUDAProviderTestParams{cuParams_device_memory, &cuAccessor}, + CUDAProviderTestParams{cuParams_shared_memory, &hostAccessor}, + CUDAProviderTestParams{cuParams_host_memory, &hostAccessor})); // TODO: add IPC API GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(umfIpcTest); @@ -185,5 +180,5 @@ INSTANTIATE_TEST_SUITE_P(umfCUDAProviderTestSuite, umfIpcTest, ::testing::Values(ipcTestParams{ umfProxyPoolOps(), nullptr, umfCUDAMemoryProviderOps(), - &cuParams_device_memory, &l0Accessor})); + &cuParams_device_memory, &cuAccessor})); */ From 41419d10f9c2e0a63a99230a4d8b5897e74b9ab4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Plewa?= Date: Mon, 21 Oct 2024 16:39:18 +0200 Subject: [PATCH 190/352] Add .mailmap --- .mailmap | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .mailmap diff --git a/.mailmap b/.mailmap new file mode 100644 index 000000000..de589da03 --- /dev/null +++ b/.mailmap @@ -0,0 +1,7 @@ +Rafał Rudnicki +Igor Chorążewicz + <83662296+szadam@users.noreply.github.com> +Adam Szopiński +Adam Szopiński Adam +Adam Szopiński szadam +Sergei Vinogradov From b00d12022acba89940b97247038dbd02cb1201f8 Mon Sep 17 00:00:00 2001 From: Rafal Rudnicki Date: Sun, 20 Oct 2024 22:38:36 +0200 Subject: [PATCH 191/352] small fix for Coarse Provider html documentation --- scripts/docs_config/api.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/scripts/docs_config/api.rst b/scripts/docs_config/api.rst index bc9b83056..6f8feb1fc 100644 --- a/scripts/docs_config/api.rst +++ b/scripts/docs_config/api.rst @@ -84,9 +84,11 @@ Coarse Provider ------------------------------------------ A memory provider that can provide memory from: -1) a given pre-allocated buffer (the fixed-size memory provider option) or -2) from an additional upstream provider (e.g. provider that does not support the free() operation - like the File memory provider or the DevDax memory provider - see below). + +1) A given pre-allocated buffer (the fixed-size memory provider option) or +2) From an additional upstream provider (e.g. provider that does not support + the free() operation like the File memory provider or the DevDax memory + provider - see below). .. doxygenfile:: provider_coarse.h :sections: define enum typedef func var From 29c4aacce09c48f85fec620ed90a979fd2884918 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 21 Oct 2024 11:03:50 +0200 Subject: [PATCH 192/352] Add umfCoarseMemoryProviderParamsDefault() Signed-off-by: Lukasz Dorau --- include/umf/providers/provider_coarse.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/umf/providers/provider_coarse.h b/include/umf/providers/provider_coarse.h index 22b59a61b..6ed6e0fbc 100644 --- a/include/umf/providers/provider_coarse.h +++ b/include/umf/providers/provider_coarse.h @@ -9,6 +9,8 @@ #define UMF_COARSE_PROVIDER_H #include +#include + #include #ifdef __cplusplus @@ -98,6 +100,15 @@ umf_memory_provider_ops_t *umfCoarseMemoryProviderOps(void); 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 From 9c91404e4be101a275a6066d39aee213d708c806 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 21 Oct 2024 21:02:12 +0200 Subject: [PATCH 193/352] Add the jemalloc_coarse_file and scalable_coarse_file tests Add the jemalloc_coarse_file and scalable_coarse_file tests that test the coarse provider with upstream file provider and two pool managers: jemalloc and scalable pool. Signed-off-by: Lukasz Dorau --- test/CMakeLists.txt | 23 +++++++-- test/pools/jemalloc_coarse_file.cpp | 16 ++++++ test/pools/pool_coarse_file.hpp | 19 +++++++ test/pools/scalable_coarse_file.cpp | 16 ++++++ .../drd-umf_test-jemalloc_coarse_file.supp | 34 +++++++++++++ .../drd-umf_test-scalable_coarse_file.supp | 49 +++++++++++++++++++ ...elgrind-umf_test-jemalloc_coarse_file.supp | 34 +++++++++++++ ...elgrind-umf_test-scalable_coarse_file.supp | 49 +++++++++++++++++++ 8 files changed, 236 insertions(+), 4 deletions(-) create mode 100644 test/pools/jemalloc_coarse_file.cpp create mode 100644 test/pools/pool_coarse_file.hpp create mode 100644 test/pools/scalable_coarse_file.cpp create mode 100644 test/supp/drd-umf_test-jemalloc_coarse_file.supp create mode 100644 test/supp/drd-umf_test-scalable_coarse_file.supp create mode 100644 test/supp/helgrind-umf_test-jemalloc_coarse_file.supp create mode 100644 test/supp/helgrind-umf_test-scalable_coarse_file.supp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8a03fd195..6c2e5d591 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -168,7 +168,7 @@ if(UMF_BUILD_LIBUMF_POOL_DISJOINT) endif() if(UMF_BUILD_LIBUMF_POOL_DISJOINT - AND UMF_BUILD_LIBUMF_POOL_JEMALLOC + AND UMF_POOL_JEMALLOC_ENABLED AND UMF_POOL_SCALABLE_ENABLED AND (NOT UMF_DISABLE_HWLOC)) add_umf_test( @@ -177,7 +177,7 @@ if(UMF_BUILD_LIBUMF_POOL_DISJOINT LIBS disjoint_pool jemalloc_pool ${JEMALLOC_LIBRARIES}) endif() -if(UMF_BUILD_LIBUMF_POOL_JEMALLOC AND (NOT UMF_DISABLE_HWLOC)) +if(UMF_POOL_JEMALLOC_ENABLED AND (NOT UMF_DISABLE_HWLOC)) add_umf_test( NAME jemalloc_pool SRCS pools/jemalloc_pool.cpp malloc_compliance_tests.cpp @@ -190,8 +190,7 @@ if(UMF_POOL_SCALABLE_ENABLED AND (NOT UMF_DISABLE_HWLOC)) endif() if(LINUX AND (NOT UMF_DISABLE_HWLOC)) # OS-specific functions are implemented - # only for - # Linux now + # only for Linux now if(PkgConfig_FOUND) pkg_check_modules(LIBNUMA numa) endif() @@ -257,6 +256,22 @@ if(LINUX AND (NOT UMF_DISABLE_HWLOC)) # OS-specific functions are implemented NAME provider_file_memory SRCS provider_file_memory.cpp LIBS ${UMF_UTILS_FOR_TEST}) + + # This test requires Linux-only file memory provider + if(UMF_POOL_JEMALLOC_ENABLED) + add_umf_test( + NAME jemalloc_coarse_file + SRCS pools/jemalloc_coarse_file.cpp malloc_compliance_tests.cpp + LIBS jemalloc_pool) + endif() + + # This test requires Linux-only file memory provider + if(UMF_POOL_SCALABLE_ENABLED) + add_umf_test( + NAME scalable_coarse_file SRCS pools/scalable_coarse_file.cpp + malloc_compliance_tests.cpp) + endif() + if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND UMF_BUILD_FUZZTESTS) add_subdirectory(fuzz) endif() diff --git a/test/pools/jemalloc_coarse_file.cpp b/test/pools/jemalloc_coarse_file.cpp new file mode 100644 index 000000000..4c38082c0 --- /dev/null +++ b/test/pools/jemalloc_coarse_file.cpp @@ -0,0 +1,16 @@ +// Copyright (C) 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 "umf/pools/pool_jemalloc.h" + +#include "pool_coarse_file.hpp" + +auto coarseParams = umfCoarseMemoryProviderParamsDefault(); +auto fileParams = umfFileMemoryProviderParamsDefault(FILE_PATH); + +INSTANTIATE_TEST_SUITE_P(jemallocCoarseFileTest, umfPoolTest, + ::testing::Values(poolCreateExtParams{ + umfJemallocPoolOps(), nullptr, + umfFileMemoryProviderOps(), &fileParams, + &coarseParams})); diff --git a/test/pools/pool_coarse_file.hpp b/test/pools/pool_coarse_file.hpp new file mode 100644 index 000000000..0ec48f2fb --- /dev/null +++ b/test/pools/pool_coarse_file.hpp @@ -0,0 +1,19 @@ +// Copyright (C) 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_TEST_POOL_COARSE_FILE_HPP +#define UMF_TEST_POOL_COARSE_FILE_HPP 1 + +#include "umf/providers/provider_coarse.h" +#include "umf/providers/provider_file_memory.h" + +#include "pool.hpp" +#include "poolFixtures.hpp" + +using umf_test::test; +using namespace umf_test; + +#define FILE_PATH ((char *)"/tmp/file_provider") + +#endif /* UMF_TEST_POOL_COARSE_FILE_HPP */ diff --git a/test/pools/scalable_coarse_file.cpp b/test/pools/scalable_coarse_file.cpp new file mode 100644 index 000000000..c6687c79e --- /dev/null +++ b/test/pools/scalable_coarse_file.cpp @@ -0,0 +1,16 @@ +// Copyright (C) 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 "umf/pools/pool_scalable.h" + +#include "pool_coarse_file.hpp" + +auto coarseParams = umfCoarseMemoryProviderParamsDefault(); +auto fileParams = umfFileMemoryProviderParamsDefault(FILE_PATH); + +INSTANTIATE_TEST_SUITE_P(scalableCoarseFileTest, umfPoolTest, + ::testing::Values(poolCreateExtParams{ + umfScalablePoolOps(), nullptr, + umfFileMemoryProviderOps(), &fileParams, + &coarseParams})); diff --git a/test/supp/drd-umf_test-jemalloc_coarse_file.supp b/test/supp/drd-umf_test-jemalloc_coarse_file.supp new file mode 100644 index 000000000..fd071432b --- /dev/null +++ b/test/supp/drd-umf_test-jemalloc_coarse_file.supp @@ -0,0 +1,34 @@ +{ + False-positive ConflictingAccess in libjemalloc.so + drd:ConflictingAccess + obj:*/libjemalloc.so* + ... + fun:mallocx + ... +} + +{ + False-positive ConflictingAccess in libjemalloc.so + drd:ConflictingAccess + obj:*/libjemalloc.so* + ... + fun:op_free + ... +} + +{ + False-positive ConflictingAccess in libjemalloc.so + drd:ConflictingAccess + obj:*/libjemalloc.so* + ... + fun:__nptl_deallocate_tsd + ... +} + +{ + False-positive ConflictingAccess in critnib_insert + drd:ConflictingAccess + fun:store + fun:critnib_insert + ... +} diff --git a/test/supp/drd-umf_test-scalable_coarse_file.supp b/test/supp/drd-umf_test-scalable_coarse_file.supp new file mode 100644 index 000000000..65640f6c3 --- /dev/null +++ b/test/supp/drd-umf_test-scalable_coarse_file.supp @@ -0,0 +1,49 @@ +{ + False-positive ConflictingAccess in libtbbmalloc.so + drd:ConflictingAccess + obj:*/libtbbmalloc.so* +} + +{ + False-positive ConflictingAccess in libtbbmalloc.so + drd:ConflictingAccess + obj:*/libtbbmalloc.so* + ... + fun:tbb_malloc + ... +} + +{ + False-positive ConflictingAccess in libtbbmalloc.so + drd:ConflictingAccess + obj:*/libtbbmalloc.so* + ... + fun:tbb_aligned_malloc + ... +} + +{ + False-positive ConflictingAccess in libtbbmalloc.so + drd:ConflictingAccess + obj:*/libtbbmalloc.so* + ... + fun:tbb_free + ... +} + +{ + False-positive ConflictingAccess in libtbbmalloc.so + drd:ConflictingAccess + obj:*/libtbbmalloc.so* + ... + fun:__nptl_deallocate_tsd + ... +} + +{ + False-positive ConflictingAccess in _Z22pow2AlignedAllocHelperP17umf_memory_pool_t + drd:ConflictingAccess + fun:memset + fun:_Z22pow2AlignedAllocHelperP17umf_memory_pool_t + ... +} diff --git a/test/supp/helgrind-umf_test-jemalloc_coarse_file.supp b/test/supp/helgrind-umf_test-jemalloc_coarse_file.supp new file mode 100644 index 000000000..18774f387 --- /dev/null +++ b/test/supp/helgrind-umf_test-jemalloc_coarse_file.supp @@ -0,0 +1,34 @@ +{ + False-positive Race in libjemalloc.so + Helgrind:Race + obj:*/libjemalloc.so* + ... + fun:mallocx + ... +} + +{ + False-positive Race in libjemalloc.so + Helgrind:Race + obj:*/libjemalloc.so* + ... + fun:op_free + ... +} + +{ + False-positive Race in libjemalloc.so + Helgrind:Race + obj:*/libjemalloc.so* + ... + fun:__nptl_deallocate_tsd + ... +} + +{ + False-positive Race in critnib_insert + Helgrind:Race + fun:store + fun:critnib_insert + ... +} diff --git a/test/supp/helgrind-umf_test-scalable_coarse_file.supp b/test/supp/helgrind-umf_test-scalable_coarse_file.supp new file mode 100644 index 000000000..650edf514 --- /dev/null +++ b/test/supp/helgrind-umf_test-scalable_coarse_file.supp @@ -0,0 +1,49 @@ +{ + False-positive Race in libtbbmalloc.so + Helgrind:Race + obj:*/libtbbmalloc.so* +} + +{ + False-positive Race in libtbbmalloc.so + Helgrind:Race + obj:*/libtbbmalloc.so* + ... + fun:tbb_malloc + ... +} + +{ + False-positive Race in libtbbmalloc.so + Helgrind:Race + obj:*/libtbbmalloc.so* + ... + fun:tbb_aligned_malloc + ... +} + +{ + False-positive Race in libtbbmalloc.so + Helgrind:Race + obj:*/libtbbmalloc.so* + ... + fun:tbb_free + ... +} + +{ + False-positive Race in libtbbmalloc.so + Helgrind:Race + obj:*/libtbbmalloc.so* + ... + fun:__nptl_deallocate_tsd + ... +} + +{ + False-positive Race in _Z22pow2AlignedAllocHelperP17umf_memory_pool_t + Helgrind:Race + fun:memset + fun:_Z22pow2AlignedAllocHelperP17umf_memory_pool_t + ... +} From 730c3442043265649d71085e1c6be8de26f96ed2 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 21 Oct 2024 21:09:28 +0200 Subject: [PATCH 194/352] Compute partial coverage on forks Signed-off-by: Lukasz Dorau --- .github/workflows/pr_push.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/pr_push.yml b/.github/workflows/pr_push.yml index b8df73975..86fa50fd2 100644 --- a/.github/workflows/pr_push.yml +++ b/.github/workflows/pr_push.yml @@ -53,8 +53,15 @@ jobs: needs: [Build] uses: ./.github/workflows/reusable_multi_numa.yml Coverage: + # total coverage (on upstream only) + if: github.repository == 'oneapi-src/unified-memory-framework' needs: [Build, DevDax, GPU, MultiNuma, Qemu, ProxyLib] uses: ./.github/workflows/reusable_coverage.yml + Coverage_partial: + # partial coverage (on forks) + if: github.repository != 'oneapi-src/unified-memory-framework' + needs: [Build, Qemu, ProxyLib] + uses: ./.github/workflows/reusable_coverage.yml CodeQL: needs: [Build] permissions: From 0c90bac72399469e2714e209723cc0f658f05264 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 21 Oct 2024 21:11:14 +0200 Subject: [PATCH 195/352] Make debug messages in utils_mmap_file() more verbose Signed-off-by: Lukasz Dorau --- src/utils/utils_linux_common.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/utils/utils_linux_common.c b/src/utils/utils_linux_common.c index f1e6beb5d..7f7d55c6f 100644 --- a/src/utils/utils_linux_common.c +++ b/src/utils/utils_linux_common.c @@ -60,7 +60,10 @@ void *utils_mmap_file(void *hint_addr, size_t length, int prot, int flags, return NULL; } - LOG_DEBUG("file mapped with the MAP_PRIVATE flag"); + LOG_DEBUG("file mapped with the MAP_PRIVATE flag (fd=%i, offset=%zu, " + "length=%zu)", + fd, fd_offset, length); + return addr; } @@ -72,7 +75,9 @@ void *utils_mmap_file(void *hint_addr, size_t length, int prot, int flags, addr = utils_mmap(hint_addr, length, prot, flags | sync_flags, fd, fd_offset); if (addr) { - LOG_DEBUG("file mapped with the MAP_SYNC flag"); + LOG_DEBUG("file mapped with the MAP_SYNC flag (fd=%i, offset=%zu, " + "length=%zu)", + fd, fd_offset, length); return addr; } @@ -85,7 +90,9 @@ void *utils_mmap_file(void *hint_addr, size_t length, int prot, int flags, const int shared_flags = (flags & (~MAP_SYNC)) | MAP_SHARED; addr = utils_mmap(hint_addr, length, prot, shared_flags, fd, fd_offset); if (addr) { - LOG_DEBUG("file mapped with the MAP_SHARED flag"); + LOG_DEBUG("file mapped with the MAP_SHARED flag (fd=%i, " + "offset=%zu, length=%zu)", + fd, fd_offset, length); return addr; } From 9371b3d49573f5e3a4afaf7388e89e895d767e7d Mon Sep 17 00:00:00 2001 From: Rafal Rudnicki Date: Tue, 22 Oct 2024 09:53:54 +0200 Subject: [PATCH 196/352] show GPU type in GPU workflow name --- .github/workflows/reusable_gpu.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/reusable_gpu.yml b/.github/workflows/reusable_gpu.yml index 91e13b674..1a5d54230 100644 --- a/.github/workflows/reusable_gpu.yml +++ b/.github/workflows/reusable_gpu.yml @@ -15,8 +15,8 @@ env: COVERAGE_DIR : "${{github.workspace}}/coverage" jobs: - gpu: - name: Build + gpu-Level-Zero: + name: Level-Zero env: VCPKG_PATH: "${{github.workspace}}/../../../../vcpkg/packages/hwloc_x64-windows;${{github.workspace}}/../../../../vcpkg/packages/tbb_x64-windows;${{github.workspace}}/../../../../vcpkg/packages/jemalloc_x64-windows" COVERAGE_NAME : "exports-coverage-gpu" @@ -127,7 +127,7 @@ jobs: path: ${{env.COVERAGE_DIR}} gpu-CUDA: - name: Build + name: CUDA env: COVERAGE_NAME : "exports-coverage-gpu-CUDA" # run only on upstream; forks will not have the HW From 59293b19f938a5ec6ec3fa4a17bf2ab69ef43450 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Mon, 21 Oct 2024 14:00:34 +0200 Subject: [PATCH 197/352] [CMake] Don't use deprecated function Switch from FetchContent_Populate to FetchContent_MakeAvailable. Fixes: #734 --- examples/cuda_shared_memory/CMakeLists.txt | 2 +- examples/ipc_level_zero/CMakeLists.txt | 2 +- examples/level_zero_shared_memory/CMakeLists.txt | 2 +- src/CMakeLists.txt | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/cuda_shared_memory/CMakeLists.txt b/examples/cuda_shared_memory/CMakeLists.txt index 8a5300910..d374b1993 100644 --- a/examples/cuda_shared_memory/CMakeLists.txt +++ b/examples/cuda_shared_memory/CMakeLists.txt @@ -38,7 +38,7 @@ FetchContent_Declare( FetchContent_GetProperties(cuda-headers) if(NOT cuda-headers_POPULATED) - FetchContent_Populate(cuda-headers) + FetchContent_MakeAvailable(cuda-headers) endif() set(CUDA_INCLUDE_DIRS diff --git a/examples/ipc_level_zero/CMakeLists.txt b/examples/ipc_level_zero/CMakeLists.txt index 18b9f542e..1928a26ad 100644 --- a/examples/ipc_level_zero/CMakeLists.txt +++ b/examples/ipc_level_zero/CMakeLists.txt @@ -39,7 +39,7 @@ FetchContent_Declare( FetchContent_GetProperties(level-zero-loader) if(NOT level-zero-loader_POPULATED) - FetchContent_Populate(level-zero-loader) + FetchContent_MakeAvailable(level-zero-loader) endif() set(LEVEL_ZERO_INCLUDE_DIRS diff --git a/examples/level_zero_shared_memory/CMakeLists.txt b/examples/level_zero_shared_memory/CMakeLists.txt index 86d22941f..e013b3229 100644 --- a/examples/level_zero_shared_memory/CMakeLists.txt +++ b/examples/level_zero_shared_memory/CMakeLists.txt @@ -39,7 +39,7 @@ FetchContent_Declare( FetchContent_GetProperties(level-zero-loader) if(NOT level-zero-loader_POPULATED) - FetchContent_Populate(level-zero-loader) + FetchContent_MakeAvailable(level-zero-loader) endif() set(LEVEL_ZERO_INCLUDE_DIRS diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 873dc6d92..52875ffe2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -35,7 +35,7 @@ if(UMF_BUILD_LEVEL_ZERO_PROVIDER AND (UMF_BUILD_GPU_TESTS FetchContent_GetProperties(level-zero-loader) if(NOT level-zero-loader_POPULATED) - FetchContent_Populate(level-zero-loader) + FetchContent_MakeAvailable(level-zero-loader) endif() set(LEVEL_ZERO_INCLUDE_DIRS @@ -65,7 +65,7 @@ if(UMF_BUILD_CUDA_PROVIDER) FetchContent_GetProperties(cuda-headers) if(NOT cuda-headers_POPULATED) - FetchContent_Populate(cuda-headers) + FetchContent_MakeAvailable(cuda-headers) endif() set(CUDA_INCLUDE_DIRS From 794cbde17013730ed56d1c6427ae07fce7938ffb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Mon, 21 Oct 2024 15:30:22 +0200 Subject: [PATCH 198/352] [CMake] Remove redundant check for '_POPULATED' targets 'FetchContent_MakeAvailable' function verifies that for us. --- CMakeLists.txt | 12 ++---------- examples/cuda_shared_memory/CMakeLists.txt | 6 +----- examples/ipc_level_zero/CMakeLists.txt | 6 +----- examples/level_zero_shared_memory/CMakeLists.txt | 6 +----- src/CMakeLists.txt | 12 ++---------- 5 files changed, 7 insertions(+), 35 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 42eeb50eb..e880418f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -149,11 +149,7 @@ else() GIT_TAG ${UMF_HWLOC_TAG} PATCH_COMMAND ${HWLOC_PATCH} SOURCE_SUBDIR contrib/windows-cmake/ FIND_PACKAGE_ARGS) - - FetchContent_GetProperties(hwloc_targ) - if(NOT hwloc_targ_POPULATED) - FetchContent_MakeAvailable(hwloc_targ) - endif() + FetchContent_MakeAvailable(hwloc_targ) set(LIBHWLOC_INCLUDE_DIRS ${hwloc_targ_SOURCE_DIR}/include;${hwloc_targ_BINARY_DIR}/include) @@ -178,11 +174,7 @@ else() GIT_REPOSITORY ${UMF_HWLOC_REPO} GIT_TAG ${UMF_HWLOC_TAG} PATCH_COMMAND ${HWLOC_PATCH}) - - FetchContent_GetProperties(hwloc_targ) - if(NOT hwloc_targ_POPULATED) - FetchContent_MakeAvailable(hwloc_targ) - endif() + FetchContent_MakeAvailable(hwloc_targ) add_custom_command( COMMAND ./autogen.sh diff --git a/examples/cuda_shared_memory/CMakeLists.txt b/examples/cuda_shared_memory/CMakeLists.txt index d374b1993..dd8567c14 100644 --- a/examples/cuda_shared_memory/CMakeLists.txt +++ b/examples/cuda_shared_memory/CMakeLists.txt @@ -35,11 +35,7 @@ FetchContent_Declare( GIT_REPOSITORY ${CUDA_REPO} GIT_TAG ${CUDA_TAG} EXCLUDE_FROM_ALL) - -FetchContent_GetProperties(cuda-headers) -if(NOT cuda-headers_POPULATED) - FetchContent_MakeAvailable(cuda-headers) -endif() +FetchContent_MakeAvailable(cuda-headers) set(CUDA_INCLUDE_DIRS ${cuda-headers_SOURCE_DIR} diff --git a/examples/ipc_level_zero/CMakeLists.txt b/examples/ipc_level_zero/CMakeLists.txt index 1928a26ad..01c96d875 100644 --- a/examples/ipc_level_zero/CMakeLists.txt +++ b/examples/ipc_level_zero/CMakeLists.txt @@ -36,11 +36,7 @@ FetchContent_Declare( GIT_REPOSITORY ${LEVEL_ZERO_LOADER_REPO} GIT_TAG ${LEVEL_ZERO_LOADER_TAG} EXCLUDE_FROM_ALL) - -FetchContent_GetProperties(level-zero-loader) -if(NOT level-zero-loader_POPULATED) - FetchContent_MakeAvailable(level-zero-loader) -endif() +FetchContent_MakeAvailable(level-zero-loader) set(LEVEL_ZERO_INCLUDE_DIRS ${level-zero-loader_SOURCE_DIR}/include diff --git a/examples/level_zero_shared_memory/CMakeLists.txt b/examples/level_zero_shared_memory/CMakeLists.txt index e013b3229..042879c5c 100644 --- a/examples/level_zero_shared_memory/CMakeLists.txt +++ b/examples/level_zero_shared_memory/CMakeLists.txt @@ -36,11 +36,7 @@ FetchContent_Declare( GIT_REPOSITORY ${LEVEL_ZERO_LOADER_REPO} GIT_TAG ${LEVEL_ZERO_LOADER_TAG} EXCLUDE_FROM_ALL) - -FetchContent_GetProperties(level-zero-loader) -if(NOT level-zero-loader_POPULATED) - FetchContent_MakeAvailable(level-zero-loader) -endif() +FetchContent_MakeAvailable(level-zero-loader) set(LEVEL_ZERO_INCLUDE_DIRS ${level-zero-loader_SOURCE_DIR}/include diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 52875ffe2..e2e1c6f55 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -32,11 +32,7 @@ if(UMF_BUILD_LEVEL_ZERO_PROVIDER AND (UMF_BUILD_GPU_TESTS GIT_REPOSITORY ${LEVEL_ZERO_LOADER_REPO} GIT_TAG ${LEVEL_ZERO_LOADER_TAG} EXCLUDE_FROM_ALL) - - FetchContent_GetProperties(level-zero-loader) - if(NOT level-zero-loader_POPULATED) - FetchContent_MakeAvailable(level-zero-loader) - endif() + FetchContent_MakeAvailable(level-zero-loader) set(LEVEL_ZERO_INCLUDE_DIRS ${level-zero-loader_SOURCE_DIR}/include @@ -62,11 +58,7 @@ if(UMF_BUILD_CUDA_PROVIDER) GIT_REPOSITORY ${CUDA_REPO} GIT_TAG ${CUDA_TAG} EXCLUDE_FROM_ALL) - - FetchContent_GetProperties(cuda-headers) - if(NOT cuda-headers_POPULATED) - FetchContent_MakeAvailable(cuda-headers) - endif() + FetchContent_MakeAvailable(cuda-headers) set(CUDA_INCLUDE_DIRS ${cuda-headers_SOURCE_DIR} From 25fbea789109b268eac4a5c3e9d209c75d999631 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Mon, 21 Oct 2024 14:02:42 +0200 Subject: [PATCH 199/352] Bump GTEST version to the newest in our testing --- test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8a03fd195..b1aa5d67a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -9,7 +9,7 @@ include(FetchContent) FetchContent_Declare( googletest GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG release-1.12.1) + GIT_TAG v1.15.2) # For Windows: Prevent overriding the parent project's compiler/linker settings set(gtest_force_shared_crt From 5073009ac6641c1606ea5b4230618abe91b4fef4 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Tue, 22 Oct 2024 11:56:18 +0200 Subject: [PATCH 200/352] Add missing base tests for providers It increase code coverage of the src/memory_provider.c file from: 149/164 lines (90.9 %) to: 163/164 lines (99.4 %) Signed-off-by: Lukasz Dorau --- test/memoryProviderAPI.cpp | 64 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/test/memoryProviderAPI.cpp b/test/memoryProviderAPI.cpp index 41196de34..5208f8157 100644 --- a/test/memoryProviderAPI.cpp +++ b/test/memoryProviderAPI.cpp @@ -146,6 +146,39 @@ TEST_F(test, memoryProviderOpsNullAllocationSplitAllocationMergeFields) { umfMemoryProviderDestroy(hProvider); } +TEST_F(test, memoryProviderOpsNullAllIPCFields) { + umf_memory_provider_ops_t provider_ops = UMF_NULL_PROVIDER_OPS; + provider_ops.ipc.get_ipc_handle_size = nullptr; + provider_ops.ipc.get_ipc_handle = nullptr; + provider_ops.ipc.put_ipc_handle = nullptr; + provider_ops.ipc.open_ipc_handle = nullptr; + provider_ops.ipc.close_ipc_handle = nullptr; + + umf_memory_provider_handle_t hProvider; + auto ret = umfMemoryProviderCreate(&provider_ops, nullptr, &hProvider); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + size_t size; + ret = umfMemoryProviderGetIPCHandleSize(hProvider, &size); + ASSERT_EQ(ret, UMF_RESULT_ERROR_NOT_SUPPORTED); + + void *ptr = nullptr; + void *providerIpcData = nullptr; + ret = umfMemoryProviderGetIPCHandle(hProvider, ptr, size, providerIpcData); + ASSERT_EQ(ret, UMF_RESULT_ERROR_NOT_SUPPORTED); + + ret = umfMemoryProviderPutIPCHandle(hProvider, providerIpcData); + ASSERT_EQ(ret, UMF_RESULT_ERROR_NOT_SUPPORTED); + + ret = umfMemoryProviderOpenIPCHandle(hProvider, providerIpcData, &ptr); + ASSERT_EQ(ret, UMF_RESULT_ERROR_NOT_SUPPORTED); + + ret = umfMemoryProviderCloseIPCHandle(hProvider, ptr, size); + ASSERT_EQ(ret, UMF_RESULT_ERROR_NOT_SUPPORTED); + + umfMemoryProviderDestroy(hProvider); +} + ////////////////// Negative test cases ///////////////// TEST_F(test, memoryProviderCreateNullOps) { @@ -256,6 +289,37 @@ TEST_F(test, memoryProviderOpsNullCloseIpcHandle) { ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); } +TEST_F(test, memoryProviderOpsNullAllocationSplitAllocationMergeNegative) { + umf_memory_provider_ops_t provider_ops = UMF_NULL_PROVIDER_OPS; + umf_memory_provider_handle_t hProvider; + + auto ret = umfMemoryProviderCreate(&provider_ops, nullptr, &hProvider); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + ret = umfMemoryProviderAllocationSplit(hProvider, nullptr, 2 * 4096, 4096); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + ret = + umfMemoryProviderAllocationMerge(hProvider, nullptr, nullptr, 2 * 4096); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + void *lowPtr = (void *)0xBAD; + void *highPtr = (void *)((uintptr_t)lowPtr + 4096); + size_t totalSize = 0; + ret = + umfMemoryProviderAllocationMerge(hProvider, lowPtr, highPtr, totalSize); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + totalSize = 4096; + lowPtr = (void *)0xBAD; + highPtr = (void *)((uintptr_t)lowPtr + 2 * totalSize); + ret = + umfMemoryProviderAllocationMerge(hProvider, lowPtr, highPtr, totalSize); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + umfMemoryProviderDestroy(hProvider); +} + struct providerInitializeTest : umf_test::test, ::testing::WithParamInterface {}; From 45806bb07bbb7cf47b814389b2fe4a61607e94df Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Tue, 22 Oct 2024 13:48:16 +0200 Subject: [PATCH 201/352] Implement purge_lazy/_force() API of the Coarse provider Signed-off-by: Lukasz Dorau --- src/provider/provider_coarse.c | 38 ++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/src/provider/provider_coarse.c b/src/provider/provider_coarse.c index 800463d8a..ca63664ef 100644 --- a/src/provider/provider_coarse.c +++ b/src/provider/provider_coarse.c @@ -1535,6 +1535,40 @@ coarse_memory_provider_get_stats(void *provider, return UMF_RESULT_SUCCESS; } +static umf_result_t coarse_memory_provider_purge_lazy(void *provider, void *ptr, + size_t size) { + if (provider == NULL || ptr == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + 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) { + if (provider == NULL || ptr == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + 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, @@ -1719,12 +1753,12 @@ umf_memory_provider_ops_t UMF_COARSE_MEMORY_PROVIDER_OPS = { .get_min_page_size = coarse_memory_provider_get_min_page_size, .get_name = coarse_memory_provider_get_name, .ext.free = coarse_memory_provider_free, + .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 /* - .ext.purge_lazy = coarse_memory_provider_purge_lazy, - .ext.purge_force = coarse_memory_provider_purge_force, .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, From c878ed427c8c773289fb668850b71ae834145ef4 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Tue, 22 Oct 2024 15:11:01 +0200 Subject: [PATCH 202/352] Add tests for purge_lazy/_force() of Coarse provider Signed-off-by: Lukasz Dorau --- test/disjointCoarseMallocPool.cpp | 123 ++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/test/disjointCoarseMallocPool.cpp b/test/disjointCoarseMallocPool.cpp index fcb3238ee..adeec7f81 100644 --- a/test/disjointCoarseMallocPool.cpp +++ b/test/disjointCoarseMallocPool.cpp @@ -1004,3 +1004,126 @@ TEST_P(CoarseWithMemoryStrategyTest, umfMemoryProviderDestroy(coarse_memory_provider); umfMemoryProviderDestroy(malloc_memory_provider); } + +TEST_P(CoarseWithMemoryStrategyTest, + disjointCoarseMallocPool_purge_no_upstream) { + umf_result_t umf_result; + + const size_t init_buffer_size = 20 * MB; + + // Preallocate some memory + std::unique_ptr buffer(new char[init_buffer_size]); + void *buf = buffer.get(); + ASSERT_NE(buf, nullptr); + memset(buf, 0, init_buffer_size); + + 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, + disjointCoarseMallocPool_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 a8096ca7ae1ee4e2d1fbf9a8c2c86003bd3a3278 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Tue, 22 Oct 2024 15:21:57 +0200 Subject: [PATCH 203/352] Change FILE_PATH of a test file from /tmp/ to a local one Change FILE_PATH from /tmp/file_provider to ./tmp_file_provider, because it is safer (/tmp/ can be unavailable). Signed-off-by: Lukasz Dorau --- test/pools/pool_coarse_file.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/pools/pool_coarse_file.hpp b/test/pools/pool_coarse_file.hpp index 0ec48f2fb..3d147b687 100644 --- a/test/pools/pool_coarse_file.hpp +++ b/test/pools/pool_coarse_file.hpp @@ -14,6 +14,6 @@ using umf_test::test; using namespace umf_test; -#define FILE_PATH ((char *)"/tmp/file_provider") +#define FILE_PATH ((char *)"tmp_file_provider") #endif /* UMF_TEST_POOL_COARSE_FILE_HPP */ From bffefda606c90d0163e1d0b68a3dc09fca290897 Mon Sep 17 00:00:00 2001 From: Rafal Rudnicki Date: Fri, 11 Oct 2024 16:37:22 +0200 Subject: [PATCH 204/352] use pools not only providers in IPC tests --- test/CMakeLists.txt | 9 +- test/common/ipc_common.c | 102 +++++++++--------- test/common/ipc_common.h | 16 +-- test/ipc_devdax_prov_consumer.c | 7 +- test/ipc_devdax_prov_producer.c | 7 +- test/ipc_file_prov_consumer.c | 5 +- test/ipc_file_prov_producer.c | 5 +- test/ipc_os_prov_consumer.c | 6 +- test/ipc_os_prov_producer.c | 6 +- test/providers/ipc_level_zero_prov_consumer.c | 8 +- test/providers/ipc_level_zero_prov_producer.c | 8 +- 11 files changed, 106 insertions(+), 73 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 5d0f69da4..3725622da 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -397,13 +397,14 @@ function(add_umf_ipc_test) WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) set_tests_properties(${TEST_NAME} PROPERTIES LABELS "umf") + set_tests_properties(${TEST_NAME} PROPERTIES TIMEOUT 60) if(NOT UMF_TESTS_FAIL_ON_SKIP) set_tests_properties(${TEST_NAME} PROPERTIES SKIP_RETURN_CODE 125) endif() endfunction() if(LINUX) - if(NOT UMF_DISABLE_HWLOC) + if(NOT UMF_DISABLE_HWLOC AND UMF_POOL_SCALABLE_ENABLED) build_umf_test( NAME ipc_os_prov_consumer @@ -457,7 +458,9 @@ if(LINUX) # TODO add IPC tests for CUDA - if(UMF_BUILD_GPU_TESTS AND UMF_BUILD_LEVEL_ZERO_PROVIDER) + if(UMF_BUILD_GPU_TESTS + AND UMF_BUILD_LEVEL_ZERO_PROVIDER + AND UMF_BUILD_LIBUMF_POOL_DISJOINT) build_umf_test( NAME ipc_level_zero_prov_consumer @@ -468,6 +471,7 @@ if(LINUX) providers/level_zero_helpers.cpp LIBS ze_loader + disjoint_pool ${UMF_UTILS_FOR_TEST}) build_umf_test( NAME @@ -479,6 +483,7 @@ if(LINUX) providers/level_zero_helpers.cpp LIBS ze_loader + disjoint_pool ${UMF_UTILS_FOR_TEST}) target_include_directories(umf_test-ipc_level_zero_prov_producer PRIVATE ${LEVEL_ZERO_INCLUDE_DIRS}) diff --git a/test/common/ipc_common.c b/test/common/ipc_common.c index 910bb187c..fdc9643f3 100644 --- a/test/common/ipc_common.c +++ b/test/common/ipc_common.c @@ -110,9 +110,9 @@ int consumer_connect(int port) { return ret; } -int run_consumer(int port, umf_memory_provider_ops_t *provider_ops, - void *provider_params, memcopy_callback_t memcopy_callback, - void *memcopy_ctx) { +int run_consumer(int port, umf_memory_pool_ops_t *pool_ops, void *pool_params, + umf_memory_provider_ops_t *provider_ops, void *provider_params, + memcopy_callback_t memcopy_callback, void *memcopy_ctx) { char consumer_message[MSG_SIZE]; int producer_socket = -1; int ret = -1; @@ -131,16 +131,23 @@ int run_consumer(int port, umf_memory_provider_ops_t *provider_ops, return -1; } + umf_memory_pool_handle_t pool; + umf_result = umfPoolCreate(pool_ops, provider, pool_params, 0, &pool); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "[consumer] ERROR: creating memory pool failed\n"); + goto err_umfMemoryProviderDestroy; + } + producer_socket = consumer_connect(port); if (producer_socket < 0) { - goto err_umfMemoryProviderDestroy; + goto err_umfMemoryPoolDestroy; } // allocate the zeroed receive buffer char *recv_buffer = calloc(1, MSG_SIZE); if (!recv_buffer) { fprintf(stderr, "[consumer] ERROR: out of memory\n"); - goto err_umfMemoryProviderDestroy; + goto err_umfMemoryPoolDestroy; } // get the size of the IPC handle from the producer @@ -183,7 +190,7 @@ int run_consumer(int port, umf_memory_provider_ops_t *provider_ops, len); void *SHM_ptr; - umf_result = umfMemoryProviderOpenIPCHandle(provider, IPC_handle, &SHM_ptr); + umf_result = umfOpenIPCHandle(pool, IPC_handle, &SHM_ptr); if (umf_result == UMF_RESULT_ERROR_NOT_SUPPORTED) { fprintf(stderr, "[consumer] SKIP: opening the IPC handle is not supported\n"); @@ -240,8 +247,7 @@ int run_consumer(int port, umf_memory_provider_ops_t *provider_ops, err_closeIPCHandle: // we do not know the exact size of the remote shared memory - umf_result = umfMemoryProviderCloseIPCHandle(provider, SHM_ptr, - sizeof(unsigned long long)); + umf_result = umfCloseIPCHandle(SHM_ptr); if (umf_result != UMF_RESULT_SUCCESS) { fprintf(stderr, "[consumer] ERROR: closing the IPC handle failed\n"); } @@ -252,6 +258,9 @@ int run_consumer(int port, umf_memory_provider_ops_t *provider_ops, err_close_producer_socket: close(producer_socket); +err_umfMemoryPoolDestroy: + umfPoolDestroy(pool); + err_umfMemoryProviderDestroy: umfMemoryProviderDestroy(provider); @@ -303,9 +312,9 @@ int producer_connect(int port) { return -1; } -int run_producer(int port, umf_memory_provider_ops_t *provider_ops, - void *provider_params, memcopy_callback_t memcopy_callback, - void *memcopy_ctx) { +int run_producer(int port, umf_memory_pool_ops_t *pool_ops, void *pool_params, + umf_memory_provider_ops_t *provider_ops, void *provider_params, + memcopy_callback_t memcopy_callback, void *memcopy_ctx) { int ret = -1; umf_memory_provider_handle_t provider = NULL; umf_result_t umf_result = UMF_RESULT_ERROR_UNKNOWN; @@ -321,12 +330,19 @@ int run_producer(int port, umf_memory_provider_ops_t *provider_ops, return -1; } + umf_memory_pool_handle_t pool; + umf_result = umfPoolCreate(pool_ops, provider, pool_params, 0, &pool); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "[producer] ERROR: creating memory pool failed\n"); + goto err_umfMemoryProviderDestroy; + } + size_t page_size; umf_result = umfMemoryProviderGetMinPageSize(provider, NULL, &page_size); if (umf_result != UMF_RESULT_SUCCESS) { fprintf(stderr, "[producer] ERROR: getting the minimum page size failed\n"); - goto err_umfMemoryProviderDestroy; + goto err_umfMemoryPoolDestroy; } // Make 3 allocations of size: 1 page, 2 pages and 3 pages @@ -335,45 +351,36 @@ int run_producer(int port, umf_memory_provider_ops_t *provider_ops, size_t ptr2_size = 2 * page_size; size_t size_IPC_shared_memory = 3 * page_size; - umf_result = umfMemoryProviderAlloc(provider, ptr1_size, 0, &ptr1); - if (umf_result != UMF_RESULT_SUCCESS) { + ptr1 = umfPoolMalloc(pool, ptr1_size); + if (ptr1 == NULL) { fprintf(stderr, "[producer] ERROR: allocating 1 page failed\n"); - goto err_umfMemoryProviderDestroy; + goto err_umfMemoryPoolDestroy; } - umf_result = umfMemoryProviderAlloc(provider, ptr2_size, 0, &ptr2); - if (umf_result != UMF_RESULT_SUCCESS) { + ptr2 = umfPoolMalloc(pool, ptr2_size); + if (ptr2 == NULL) { fprintf(stderr, "[producer] ERROR: allocating 2 pages failed\n"); goto err_free_ptr1; } - umf_result = umfMemoryProviderAlloc(provider, size_IPC_shared_memory, 0, - &IPC_shared_memory); - if (umf_result != UMF_RESULT_SUCCESS) { + IPC_shared_memory = umfPoolMalloc(pool, size_IPC_shared_memory); + if (IPC_shared_memory == NULL) { fprintf(stderr, "[producer] ERROR: allocating 3 pages failed\n"); goto err_free_ptr2; } // get size of the IPC handle size_t IPC_handle_size; - umf_result = umfMemoryProviderGetIPCHandleSize(provider, &IPC_handle_size); - if (umf_result != UMF_RESULT_SUCCESS) { - fprintf(stderr, - "[producer] ERROR: getting size of the IPC handle failed\n"); - goto err_free_IPC_shared_memory; - } + umf_ipc_handle_t IPC_handle = NULL; - // allocate data for IPC provider - void *IPC_handle = malloc(IPC_handle_size); - if (IPC_handle == NULL) { - fprintf(stderr, - "[producer] ERROR: allocating memory for IPC handle failed\n"); + // get the IPC handle + umf_result = + umfGetIPCHandle(IPC_shared_memory, &IPC_handle, &IPC_handle_size); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "[producer] ERROR: getting the IPC handle failed\n"); goto err_free_IPC_shared_memory; } - // zero the IPC handle and the shared memory - memset(IPC_handle, 0, IPC_handle_size); - // save a random number (&provider) in the shared memory unsigned long long SHM_number_1 = (unsigned long long)&provider; memcopy_callback(IPC_shared_memory, &SHM_number_1, sizeof(SHM_number_1), @@ -382,16 +389,6 @@ int run_producer(int port, umf_memory_provider_ops_t *provider_ops, fprintf(stderr, "[producer] My shared memory contains a number: %llu\n", SHM_number_1); - // get the IPC handle from the OS memory provider - umf_result = umfMemoryProviderGetIPCHandle( - provider, IPC_shared_memory, size_IPC_shared_memory, IPC_handle); - if (umf_result != UMF_RESULT_SUCCESS) { - fprintf(stderr, - "[producer] ERROR: getting the IPC handle from the OS memory " - "provider failed\n"); - goto err_free_IPC_handle; - } - fprintf(stderr, "[producer] Got the IPC handle\n"); producer_socket = producer_connect(port); @@ -494,22 +491,25 @@ int run_producer(int port, umf_memory_provider_ops_t *provider_ops, close(producer_socket); err_PutIPCHandle: - umf_result = umfMemoryProviderPutIPCHandle(provider, IPC_handle); + umf_result = umfPutIPCHandle(IPC_handle); if (umf_result != UMF_RESULT_SUCCESS) { fprintf(stderr, "[producer] ERROR: putting the IPC handle failed\n"); } fprintf(stderr, "[producer] Put the IPC handle\n"); -err_free_IPC_handle: - free(IPC_handle); err_free_IPC_shared_memory: - (void)umfMemoryProviderFree(provider, IPC_shared_memory, - size_IPC_shared_memory); + (void)umfFree(IPC_shared_memory); + err_free_ptr2: - (void)umfMemoryProviderFree(provider, ptr2, ptr2_size); + (void)umfFree(ptr2); + err_free_ptr1: - (void)umfMemoryProviderFree(provider, ptr1, ptr1_size); + (void)umfFree(ptr1); + +err_umfMemoryPoolDestroy: + umfPoolDestroy(pool); + err_umfMemoryProviderDestroy: umfMemoryProviderDestroy(provider); diff --git a/test/common/ipc_common.h b/test/common/ipc_common.h index a73b01435..89303899b 100644 --- a/test/common/ipc_common.h +++ b/test/common/ipc_common.h @@ -8,7 +8,10 @@ #ifndef UMF_TEST_IPC_COMMON_H #define UMF_TEST_IPC_COMMON_H +#include +#include #include +#include // pointer to the function that returns void and accept two int values typedef void (*memcopy_callback_t)(void *dst, const void *src, size_t size, @@ -17,11 +20,12 @@ typedef void (*memcopy_callback_t)(void *dst, const void *src, size_t size, int producer_connect(int port); int consumer_connect(int port); -int run_producer(int port, umf_memory_provider_ops_t *provider_ops, - void *provider_params, memcopy_callback_t memcopy_callback, - void *memcopy_ctx); -int run_consumer(int port, umf_memory_provider_ops_t *provider_ops, - void *provider_params, memcopy_callback_t memcopy_callback, - void *memcopy_ctx); +int run_producer(int port, umf_memory_pool_ops_t *pool_ops, void *pool_params, + umf_memory_provider_ops_t *provider_ops, void *provider_params, + memcopy_callback_t memcopy_callback, void *memcopy_ctx); + +int run_consumer(int port, umf_memory_pool_ops_t *pool_ops, void *pool_params, + umf_memory_provider_ops_t *provider_ops, void *provider_params, + memcopy_callback_t memcopy_callback, void *memcopy_ctx); #endif // UMF_TEST_IPC_COMMON_H diff --git a/test/ipc_devdax_prov_consumer.c b/test/ipc_devdax_prov_consumer.c index f1d576500..a8fd8211d 100644 --- a/test/ipc_devdax_prov_consumer.c +++ b/test/ipc_devdax_prov_consumer.c @@ -36,6 +36,9 @@ int main(int argc, char *argv[]) { umf_devdax_memory_provider_params_t devdax_params = umfDevDaxMemoryProviderParamsDefault(path, atol(size)); - return run_consumer(port, umfDevDaxMemoryProviderOps(), &devdax_params, - memcopy, NULL); + void *pool_params = NULL; + + return run_consumer(port, umfScalablePoolOps(), pool_params, + umfDevDaxMemoryProviderOps(), &devdax_params, memcopy, + NULL); } diff --git a/test/ipc_devdax_prov_producer.c b/test/ipc_devdax_prov_producer.c index c462706db..90afe64dd 100644 --- a/test/ipc_devdax_prov_producer.c +++ b/test/ipc_devdax_prov_producer.c @@ -36,6 +36,9 @@ int main(int argc, char *argv[]) { umf_devdax_memory_provider_params_t devdax_params = umfDevDaxMemoryProviderParamsDefault(path, atol(size)); - return run_producer(port, umfDevDaxMemoryProviderOps(), &devdax_params, - memcopy, NULL); + void *pool_params = NULL; + + return run_producer(port, umfScalablePoolOps(), pool_params, + umfDevDaxMemoryProviderOps(), &devdax_params, memcopy, + NULL); } diff --git a/test/ipc_file_prov_consumer.c b/test/ipc_file_prov_consumer.c index d1e622efe..6c53ad320 100644 --- a/test/ipc_file_prov_consumer.c +++ b/test/ipc_file_prov_consumer.c @@ -43,6 +43,9 @@ int main(int argc, char *argv[]) { file_params.visibility = UMF_MEM_MAP_SHARED; } - return run_consumer(port, umfFileMemoryProviderOps(), &file_params, memcopy, + void *pool_params = NULL; + + return run_consumer(port, umfScalablePoolOps(), pool_params, + umfFileMemoryProviderOps(), &file_params, memcopy, NULL); } diff --git a/test/ipc_file_prov_producer.c b/test/ipc_file_prov_producer.c index 1e7052efb..ee9d96f1e 100644 --- a/test/ipc_file_prov_producer.c +++ b/test/ipc_file_prov_producer.c @@ -43,6 +43,9 @@ int main(int argc, char *argv[]) { file_params.visibility = UMF_MEM_MAP_SHARED; } - return run_producer(port, umfFileMemoryProviderOps(), &file_params, memcopy, + void *pool_params = NULL; + + return run_producer(port, umfScalablePoolOps(), pool_params, + umfFileMemoryProviderOps(), &file_params, memcopy, NULL); } diff --git a/test/ipc_os_prov_consumer.c b/test/ipc_os_prov_consumer.c index 7df1e7049..34f51fe1c 100644 --- a/test/ipc_os_prov_consumer.c +++ b/test/ipc_os_prov_consumer.c @@ -29,6 +29,8 @@ int main(int argc, char *argv[]) { os_params.shm_name = argv[2]; } - return run_consumer(port, umfOsMemoryProviderOps(), &os_params, memcopy, - NULL); + void *pool_params = NULL; + + return run_consumer(port, umfScalablePoolOps(), pool_params, + umfOsMemoryProviderOps(), &os_params, memcopy, NULL); } diff --git a/test/ipc_os_prov_producer.c b/test/ipc_os_prov_producer.c index a9a2ab56c..623244902 100644 --- a/test/ipc_os_prov_producer.c +++ b/test/ipc_os_prov_producer.c @@ -29,6 +29,8 @@ int main(int argc, char *argv[]) { os_params.shm_name = argv[2]; } - return run_producer(port, umfOsMemoryProviderOps(), &os_params, memcopy, - NULL); + void *pool_params = NULL; + + return run_producer(port, umfScalablePoolOps(), pool_params, + umfOsMemoryProviderOps(), &os_params, memcopy, NULL); } diff --git a/test/providers/ipc_level_zero_prov_consumer.c b/test/providers/ipc_level_zero_prov_consumer.c index 6d59ced53..009988b98 100644 --- a/test/providers/ipc_level_zero_prov_consumer.c +++ b/test/providers/ipc_level_zero_prov_consumer.c @@ -8,6 +8,7 @@ #include #include +#include #include #include "ipc_common.h" @@ -25,6 +26,9 @@ int main(int argc, char *argv[]) { level_zero_memory_provider_params_t l0_params = create_level_zero_prov_params(UMF_MEMORY_TYPE_DEVICE); - return run_consumer(port, umfLevelZeroMemoryProviderOps(), &l0_params, - memcopy, &l0_params); + umf_disjoint_pool_params_t pool_params = umfDisjointPoolParamsDefault(); + + return run_consumer(port, umfDisjointPoolOps(), &pool_params, + umfLevelZeroMemoryProviderOps(), &l0_params, memcopy, + &l0_params); } diff --git a/test/providers/ipc_level_zero_prov_producer.c b/test/providers/ipc_level_zero_prov_producer.c index d2d95d885..11485c85e 100644 --- a/test/providers/ipc_level_zero_prov_producer.c +++ b/test/providers/ipc_level_zero_prov_producer.c @@ -8,6 +8,7 @@ #include #include +#include #include #include "ipc_common.h" @@ -25,6 +26,9 @@ int main(int argc, char *argv[]) { level_zero_memory_provider_params_t l0_params = create_level_zero_prov_params(UMF_MEMORY_TYPE_DEVICE); - return run_producer(port, umfLevelZeroMemoryProviderOps(), &l0_params, - memcopy, &l0_params); + umf_disjoint_pool_params_t pool_params = umfDisjointPoolParamsDefault(); + + return run_producer(port, umfDisjointPoolOps(), &pool_params, + umfLevelZeroMemoryProviderOps(), &l0_params, memcopy, + &l0_params); } From a83d012009d012eb87bb3e30c7248b99d0e564df Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Tue, 22 Oct 2024 12:52:49 -0700 Subject: [PATCH 205/352] Minor fix in ipcFixture.hpp --- test/ipcFixtures.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/ipcFixtures.hpp b/test/ipcFixtures.hpp index 776ea7aab..78e085a19 100644 --- a/test/ipcFixtures.hpp +++ b/test/ipcFixtures.hpp @@ -69,8 +69,8 @@ struct umfIpcTest : umf_test::test, umf::pool_unique_handle_t makePool() { // TODO: The function is similar to poolCreateExt function // from memoryPool.hpp - umf_memory_provider_handle_t hProvider; - umf_memory_pool_handle_t hPool; + umf_memory_provider_handle_t hProvider = NULL; + umf_memory_pool_handle_t hPool = NULL; auto ret = umfMemoryProviderCreate(providerOps, providerParams, &hProvider); From 521d8a0e21c75f5f30b2495501f8d7ba4092c6e8 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Tue, 22 Oct 2024 07:39:45 -0700 Subject: [PATCH 206/352] Add tests for CUDA provider --- test/providers/provider_cuda.cpp | 63 ++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/test/providers/provider_cuda.cpp b/test/providers/provider_cuda.cpp index 4bdbbba73..c0173bb82 100644 --- a/test/providers/provider_cuda.cpp +++ b/test/providers/provider_cuda.cpp @@ -125,6 +125,43 @@ TEST_P(umfCUDAProviderTest, basic) { umfMemoryProviderDestroy(provider); } +TEST_P(umfCUDAProviderTest, getPageSize) { + umf_memory_provider_handle_t provider = nullptr; + umf_result_t umf_result = + umfMemoryProviderCreate(umfCUDAMemoryProviderOps(), ¶ms, &provider); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(provider, nullptr); + + size_t recommendedPageSize = 0; + umf_result = umfMemoryProviderGetRecommendedPageSize(provider, 0, + &recommendedPageSize); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_GE(recommendedPageSize, 0); + + size_t minPageSize = 0; + umf_result = + umfMemoryProviderGetMinPageSize(provider, nullptr, &minPageSize); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_GE(minPageSize, 0); + + ASSERT_GE(recommendedPageSize, minPageSize); + + umfMemoryProviderDestroy(provider); +} + +TEST_P(umfCUDAProviderTest, getName) { + umf_memory_provider_handle_t provider = nullptr; + umf_result_t umf_result = + umfMemoryProviderCreate(umfCUDAMemoryProviderOps(), ¶ms, &provider); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(provider, nullptr); + + const char *name = umfMemoryProviderGetName(provider); + ASSERT_STREQ(name, "CUDA"); + + umfMemoryProviderDestroy(provider); +} + TEST_P(umfCUDAProviderTest, allocInvalidSize) { CUcontext expected_current_context = get_current_context(); // create CUDA provider @@ -152,6 +189,32 @@ TEST_P(umfCUDAProviderTest, allocInvalidSize) { umfMemoryProviderDestroy(provider); } +TEST_P(umfCUDAProviderTest, providerCreateInvalidArgs) { + umf_memory_provider_handle_t provider = nullptr; + umf_result_t umf_result = + umfMemoryProviderCreate(umfCUDAMemoryProviderOps(), nullptr, &provider); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + umf_result = umfMemoryProviderCreate(nullptr, ¶ms, nullptr); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} + +TEST_P(umfCUDAProviderTest, getPageSizeInvalidArgs) { + umf_memory_provider_handle_t provider = nullptr; + umf_result_t umf_result = + umfMemoryProviderCreate(umfCUDAMemoryProviderOps(), ¶ms, &provider); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(provider, nullptr); + + umf_result = umfMemoryProviderGetMinPageSize(provider, nullptr, nullptr); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + umf_result = umfMemoryProviderGetRecommendedPageSize(provider, 0, nullptr); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + umfMemoryProviderDestroy(provider); +} + // TODO add tests that mixes CUDA Memory Provider and Disjoint Pool cuda_memory_provider_params_t cuParams_device_memory = From 347b14bd05aa4756dae3640c48aed68407d1a552 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 23 Oct 2024 09:34:12 +0200 Subject: [PATCH 207/352] Fix: do not allocate too much memory in calloc_compliance_test() Signed-off-by: Lukasz Dorau --- test/malloc_compliance_tests.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/malloc_compliance_tests.cpp b/test/malloc_compliance_tests.cpp index c3c67ae21..06e3b5dd7 100644 --- a/test/malloc_compliance_tests.cpp +++ b/test/malloc_compliance_tests.cpp @@ -85,12 +85,11 @@ void calloc_compliance_test(umf_memory_pool_handle_t hPool) { // Checking that the memory returned by calloc is zero filled for (int i = 0; i < ITERATIONS; i++) { alloc_size = rand_alloc_size(MAX_ALLOC_SIZE); - alloc_ptr[i] = umfPoolCalloc(hPool, i + 1, alloc_size); + alloc_ptr[i] = umfPoolCalloc(hPool, 2, alloc_size); ASSERT_NE(alloc_ptr[i], nullptr) << "calloc returned NULL, couldn't allocate much memory"; - ASSERT_NE(bufferIsFilledWithChar(alloc_ptr[i], alloc_size * (i + 1), 0), - 0) + ASSERT_NE(bufferIsFilledWithChar(alloc_ptr[i], 2 * alloc_size, 0), 0) << "Memory returned by calloc was not zeroed"; } free_memory(hPool, alloc_ptr); From a7f8c8f978e69996ca4d93f5d2fe186e0a023323 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 23 Oct 2024 09:34:32 +0200 Subject: [PATCH 208/352] Add the jemalloc_coarse_devdax and scalable_coarse_devdax tests Add the jemalloc_coarse_devdax and scalable_coarse_devdax tests that test the coarse provider with upstream devdax provider and two pool managers: jemalloc and scalable pool. Signed-off-by: Lukasz Dorau --- test/CMakeLists.txt | 7 +++ test/poolFixtures.hpp | 18 +++++++ test/pools/jemalloc_coarse_devdax.cpp | 20 ++++++++ test/pools/jemalloc_coarse_file.cpp | 3 +- .../{pool_coarse_file.hpp => pool_coarse.hpp} | 7 ++- test/pools/scalable_coarse_devdax.cpp | 20 ++++++++ test/pools/scalable_coarse_file.cpp | 3 +- .../drd-umf_test-jemalloc_coarse_devdax.supp | 34 +++++++++++++ .../drd-umf_test-scalable_coarse_devdax.supp | 49 +++++++++++++++++++ ...grind-umf_test-jemalloc_coarse_devdax.supp | 34 +++++++++++++ ...grind-umf_test-scalable_coarse_devdax.supp | 49 +++++++++++++++++++ 11 files changed, 238 insertions(+), 6 deletions(-) create mode 100644 test/pools/jemalloc_coarse_devdax.cpp rename test/pools/{pool_coarse_file.hpp => pool_coarse.hpp} (68%) create mode 100644 test/pools/scalable_coarse_devdax.cpp create mode 100644 test/supp/drd-umf_test-jemalloc_coarse_devdax.supp create mode 100644 test/supp/drd-umf_test-scalable_coarse_devdax.supp create mode 100644 test/supp/helgrind-umf_test-jemalloc_coarse_devdax.supp create mode 100644 test/supp/helgrind-umf_test-scalable_coarse_devdax.supp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 5d0f69da4..c16173455 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -263,6 +263,10 @@ if(LINUX AND (NOT UMF_DISABLE_HWLOC)) # OS-specific functions are implemented NAME jemalloc_coarse_file SRCS pools/jemalloc_coarse_file.cpp malloc_compliance_tests.cpp LIBS jemalloc_pool) + add_umf_test( + NAME jemalloc_coarse_devdax + SRCS pools/jemalloc_coarse_devdax.cpp malloc_compliance_tests.cpp + LIBS jemalloc_pool) endif() # This test requires Linux-only file memory provider @@ -270,6 +274,9 @@ if(LINUX AND (NOT UMF_DISABLE_HWLOC)) # OS-specific functions are implemented add_umf_test( NAME scalable_coarse_file SRCS pools/scalable_coarse_file.cpp malloc_compliance_tests.cpp) + add_umf_test( + NAME scalable_coarse_devdax SRCS pools/scalable_coarse_devdax.cpp + malloc_compliance_tests.cpp) endif() if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND UMF_BUILD_FUZZTESTS) diff --git a/test/poolFixtures.hpp b/test/poolFixtures.hpp index b2b580b26..93d839391 100644 --- a/test/poolFixtures.hpp +++ b/test/poolFixtures.hpp @@ -8,6 +8,7 @@ #include "pool.hpp" #include "provider.hpp" #include "umf/providers/provider_coarse.h" +#include "umf/providers/provider_devdax_memory.h" #include #include @@ -66,6 +67,23 @@ struct umfPoolTest : umf_test::test, ::testing::WithParamInterface { void SetUp() override { test::SetUp(); + + auto [pool_ops, pool_params, provider_ops, provider_params, + coarse_params] = this->GetParam(); + if (provider_ops == umfDevDaxMemoryProviderOps()) { + char *path = getenv("UMF_TESTS_DEVDAX_PATH"); + if (path == nullptr || path[0] == 0) { + GTEST_SKIP() + << "Test skipped, UMF_TESTS_DEVDAX_PATH is not set"; + } + + char *size = getenv("UMF_TESTS_DEVDAX_SIZE"); + if (size == nullptr || size[0] == 0) { + GTEST_SKIP() + << "Test skipped, UMF_TESTS_DEVDAX_SIZE is not set"; + } + } + pool = poolCreateExtUnique(this->GetParam()); } diff --git a/test/pools/jemalloc_coarse_devdax.cpp b/test/pools/jemalloc_coarse_devdax.cpp new file mode 100644 index 000000000..ae98ecf4b --- /dev/null +++ b/test/pools/jemalloc_coarse_devdax.cpp @@ -0,0 +1,20 @@ +// Copyright (C) 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 "umf/pools/pool_jemalloc.h" +#include "umf/providers/provider_devdax_memory.h" + +#include "pool_coarse.hpp" + +auto coarseParams = umfCoarseMemoryProviderParamsDefault(); +auto devdaxParams = umfDevDaxMemoryProviderParamsDefault( + getenv("UMF_TESTS_DEVDAX_PATH"), getenv("UMF_TESTS_DEVDAX_SIZE") + ? atol(getenv("UMF_TESTS_DEVDAX_SIZE")) + : 0); + +INSTANTIATE_TEST_SUITE_P(jemallocCoarseDevDaxTest, umfPoolTest, + ::testing::Values(poolCreateExtParams{ + umfJemallocPoolOps(), nullptr, + umfDevDaxMemoryProviderOps(), &devdaxParams, + &coarseParams})); diff --git a/test/pools/jemalloc_coarse_file.cpp b/test/pools/jemalloc_coarse_file.cpp index 4c38082c0..7eb904903 100644 --- a/test/pools/jemalloc_coarse_file.cpp +++ b/test/pools/jemalloc_coarse_file.cpp @@ -3,8 +3,9 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include "umf/pools/pool_jemalloc.h" +#include "umf/providers/provider_file_memory.h" -#include "pool_coarse_file.hpp" +#include "pool_coarse.hpp" auto coarseParams = umfCoarseMemoryProviderParamsDefault(); auto fileParams = umfFileMemoryProviderParamsDefault(FILE_PATH); diff --git a/test/pools/pool_coarse_file.hpp b/test/pools/pool_coarse.hpp similarity index 68% rename from test/pools/pool_coarse_file.hpp rename to test/pools/pool_coarse.hpp index 3d147b687..7baa612f1 100644 --- a/test/pools/pool_coarse_file.hpp +++ b/test/pools/pool_coarse.hpp @@ -2,11 +2,10 @@ // Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -#ifndef UMF_TEST_POOL_COARSE_FILE_HPP -#define UMF_TEST_POOL_COARSE_FILE_HPP 1 +#ifndef UMF_TEST_POOL_COARSE_HPP +#define UMF_TEST_POOL_COARSE_HPP 1 #include "umf/providers/provider_coarse.h" -#include "umf/providers/provider_file_memory.h" #include "pool.hpp" #include "poolFixtures.hpp" @@ -16,4 +15,4 @@ using namespace umf_test; #define FILE_PATH ((char *)"tmp_file_provider") -#endif /* UMF_TEST_POOL_COARSE_FILE_HPP */ +#endif /* UMF_TEST_POOL_COARSE_HPP */ diff --git a/test/pools/scalable_coarse_devdax.cpp b/test/pools/scalable_coarse_devdax.cpp new file mode 100644 index 000000000..b5da7d242 --- /dev/null +++ b/test/pools/scalable_coarse_devdax.cpp @@ -0,0 +1,20 @@ +// Copyright (C) 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 "umf/pools/pool_scalable.h" +#include "umf/providers/provider_devdax_memory.h" + +#include "pool_coarse.hpp" + +auto coarseParams = umfCoarseMemoryProviderParamsDefault(); +auto devdaxParams = umfDevDaxMemoryProviderParamsDefault( + getenv("UMF_TESTS_DEVDAX_PATH"), getenv("UMF_TESTS_DEVDAX_SIZE") + ? atol(getenv("UMF_TESTS_DEVDAX_SIZE")) + : 0); + +INSTANTIATE_TEST_SUITE_P(scalableCoarseDevDaxTest, umfPoolTest, + ::testing::Values(poolCreateExtParams{ + umfScalablePoolOps(), nullptr, + umfDevDaxMemoryProviderOps(), &devdaxParams, + &coarseParams})); diff --git a/test/pools/scalable_coarse_file.cpp b/test/pools/scalable_coarse_file.cpp index c6687c79e..b83a12338 100644 --- a/test/pools/scalable_coarse_file.cpp +++ b/test/pools/scalable_coarse_file.cpp @@ -3,8 +3,9 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include "umf/pools/pool_scalable.h" +#include "umf/providers/provider_file_memory.h" -#include "pool_coarse_file.hpp" +#include "pool_coarse.hpp" auto coarseParams = umfCoarseMemoryProviderParamsDefault(); auto fileParams = umfFileMemoryProviderParamsDefault(FILE_PATH); diff --git a/test/supp/drd-umf_test-jemalloc_coarse_devdax.supp b/test/supp/drd-umf_test-jemalloc_coarse_devdax.supp new file mode 100644 index 000000000..fd071432b --- /dev/null +++ b/test/supp/drd-umf_test-jemalloc_coarse_devdax.supp @@ -0,0 +1,34 @@ +{ + False-positive ConflictingAccess in libjemalloc.so + drd:ConflictingAccess + obj:*/libjemalloc.so* + ... + fun:mallocx + ... +} + +{ + False-positive ConflictingAccess in libjemalloc.so + drd:ConflictingAccess + obj:*/libjemalloc.so* + ... + fun:op_free + ... +} + +{ + False-positive ConflictingAccess in libjemalloc.so + drd:ConflictingAccess + obj:*/libjemalloc.so* + ... + fun:__nptl_deallocate_tsd + ... +} + +{ + False-positive ConflictingAccess in critnib_insert + drd:ConflictingAccess + fun:store + fun:critnib_insert + ... +} diff --git a/test/supp/drd-umf_test-scalable_coarse_devdax.supp b/test/supp/drd-umf_test-scalable_coarse_devdax.supp new file mode 100644 index 000000000..65640f6c3 --- /dev/null +++ b/test/supp/drd-umf_test-scalable_coarse_devdax.supp @@ -0,0 +1,49 @@ +{ + False-positive ConflictingAccess in libtbbmalloc.so + drd:ConflictingAccess + obj:*/libtbbmalloc.so* +} + +{ + False-positive ConflictingAccess in libtbbmalloc.so + drd:ConflictingAccess + obj:*/libtbbmalloc.so* + ... + fun:tbb_malloc + ... +} + +{ + False-positive ConflictingAccess in libtbbmalloc.so + drd:ConflictingAccess + obj:*/libtbbmalloc.so* + ... + fun:tbb_aligned_malloc + ... +} + +{ + False-positive ConflictingAccess in libtbbmalloc.so + drd:ConflictingAccess + obj:*/libtbbmalloc.so* + ... + fun:tbb_free + ... +} + +{ + False-positive ConflictingAccess in libtbbmalloc.so + drd:ConflictingAccess + obj:*/libtbbmalloc.so* + ... + fun:__nptl_deallocate_tsd + ... +} + +{ + False-positive ConflictingAccess in _Z22pow2AlignedAllocHelperP17umf_memory_pool_t + drd:ConflictingAccess + fun:memset + fun:_Z22pow2AlignedAllocHelperP17umf_memory_pool_t + ... +} diff --git a/test/supp/helgrind-umf_test-jemalloc_coarse_devdax.supp b/test/supp/helgrind-umf_test-jemalloc_coarse_devdax.supp new file mode 100644 index 000000000..18774f387 --- /dev/null +++ b/test/supp/helgrind-umf_test-jemalloc_coarse_devdax.supp @@ -0,0 +1,34 @@ +{ + False-positive Race in libjemalloc.so + Helgrind:Race + obj:*/libjemalloc.so* + ... + fun:mallocx + ... +} + +{ + False-positive Race in libjemalloc.so + Helgrind:Race + obj:*/libjemalloc.so* + ... + fun:op_free + ... +} + +{ + False-positive Race in libjemalloc.so + Helgrind:Race + obj:*/libjemalloc.so* + ... + fun:__nptl_deallocate_tsd + ... +} + +{ + False-positive Race in critnib_insert + Helgrind:Race + fun:store + fun:critnib_insert + ... +} diff --git a/test/supp/helgrind-umf_test-scalable_coarse_devdax.supp b/test/supp/helgrind-umf_test-scalable_coarse_devdax.supp new file mode 100644 index 000000000..650edf514 --- /dev/null +++ b/test/supp/helgrind-umf_test-scalable_coarse_devdax.supp @@ -0,0 +1,49 @@ +{ + False-positive Race in libtbbmalloc.so + Helgrind:Race + obj:*/libtbbmalloc.so* +} + +{ + False-positive Race in libtbbmalloc.so + Helgrind:Race + obj:*/libtbbmalloc.so* + ... + fun:tbb_malloc + ... +} + +{ + False-positive Race in libtbbmalloc.so + Helgrind:Race + obj:*/libtbbmalloc.so* + ... + fun:tbb_aligned_malloc + ... +} + +{ + False-positive Race in libtbbmalloc.so + Helgrind:Race + obj:*/libtbbmalloc.so* + ... + fun:tbb_free + ... +} + +{ + False-positive Race in libtbbmalloc.so + Helgrind:Race + obj:*/libtbbmalloc.so* + ... + fun:__nptl_deallocate_tsd + ... +} + +{ + False-positive Race in _Z22pow2AlignedAllocHelperP17umf_memory_pool_t + Helgrind:Race + fun:memset + fun:_Z22pow2AlignedAllocHelperP17umf_memory_pool_t + ... +} From ca50f80a8cd5bafa5189825b352553fd45d44d11 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 23 Oct 2024 11:07:45 +0200 Subject: [PATCH 209/352] Split tests from disjointCoarseMallocPool.cpp Move all tests that do not use the disjoint_pool to a separate test file provider_coarse.cpp. This new file contains only pure provider tests of the coarse provider. Signed-off-by: Lukasz Dorau --- test/CMakeLists.txt | 2 + test/disjointCoarseMallocPool.cpp | 603 ---------------------------- test/provider_coarse.cpp | 638 ++++++++++++++++++++++++++++++ 3 files changed, 640 insertions(+), 603 deletions(-) create mode 100644 test/provider_coarse.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 4e33b9b58..8450f049f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -152,6 +152,8 @@ add_umf_test( SRCS utils/utils.cpp LIBS ${UMF_UTILS_FOR_TEST}) +add_umf_test(NAME provider_coarse SRCS provider_coarse.cpp) + if(UMF_BUILD_LIBUMF_POOL_DISJOINT) add_umf_test( NAME disjointPool diff --git a/test/disjointCoarseMallocPool.cpp b/test/disjointCoarseMallocPool.cpp index adeec7f81..d650815df 100644 --- a/test/disjointCoarseMallocPool.cpp +++ b/test/disjointCoarseMallocPool.cpp @@ -18,10 +18,6 @@ using umf_test::test; #define GetStats umfCoarseMemoryProviderGetStats -#define UPSTREAM_NAME "malloc" -#define BASE_NAME "coarse" -#define COARSE_NAME BASE_NAME " (" UPSTREAM_NAME ")" - umf_memory_provider_ops_t UMF_MALLOC_MEMORY_PROVIDER_OPS = umf::providerMakeCOps(); @@ -42,78 +38,6 @@ INSTANTIATE_TEST_SUITE_P( UMF_COARSE_MEMORY_STRATEGY_FASTEST_BUT_ONE, UMF_COARSE_MEMORY_STRATEGY_CHECK_ALL_SIZE)); -TEST_F(test, disjointCoarseMallocPool_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); - - 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, disjointCoarseMallocPool_name_no_upstream) { - umf_result_t umf_result; - - const size_t init_buffer_size = 20 * MB; - - // Preallocate some memory - std::unique_ptr buffer(new char[init_buffer_size]); - void *buf = buffer.get(); - ASSERT_NE(buf, nullptr); - memset(buf, 0, init_buffer_size); - - 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); - - ASSERT_EQ( - strcmp(umfMemoryProviderGetName(coarse_memory_provider), BASE_NAME), 0); - - umfMemoryProviderDestroy(coarse_memory_provider); -} - TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_basic) { umf_memory_provider_handle_t malloc_memory_provider; umf_result_t umf_result; @@ -600,530 +524,3 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMMapPool_random) { umfPoolDestroy(pool); umfMemoryProviderDestroy(coarse_memory_provider); } - -// negative tests - -TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_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 parameters: given no upstream_memory_provider -// nor init_buffer while exactly one of them must be set -TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_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, disjointCoarseMallocPool_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 - std::unique_ptr buffer(new char[init_buffer_size]); - void *buf = buffer.get(); - ASSERT_NE(buf, nullptr); - memset(buf, 0, init_buffer_size); - - 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, disjointCoarseMallocPool_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, disjointCoarseMallocPool_wrong_params_3) { - umf_result_t umf_result; - - const size_t init_buffer_size = 20 * MB; - - // Preallocate some memory - std::unique_ptr buffer(new char[init_buffer_size]); - void *buf = buffer.get(); - ASSERT_NE(buf, nullptr); - memset(buf, 0, init_buffer_size); - - 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, disjointCoarseMallocPool_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, disjointCoarseMallocPool_wrong_params_5) { - umf_result_t umf_result; - - const size_t init_buffer_size = 20 * MB; - - // Preallocate some memory - std::unique_ptr buffer(new char[init_buffer_size]); - void *buf = buffer.get(); - ASSERT_NE(buf, nullptr); - memset(buf, 0, init_buffer_size); - - 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, disjointCoarseMallocPool_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, - disjointCoarseMallocPool_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, - disjointCoarseMallocPool_purge_no_upstream) { - umf_result_t umf_result; - - const size_t init_buffer_size = 20 * MB; - - // Preallocate some memory - std::unique_ptr buffer(new char[init_buffer_size]); - void *buf = buffer.get(); - ASSERT_NE(buf, nullptr); - memset(buf, 0, init_buffer_size); - - 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, - disjointCoarseMallocPool_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); -} diff --git a/test/provider_coarse.cpp b/test/provider_coarse.cpp new file mode 100644 index 000000000..7d5c06c09 --- /dev/null +++ b/test/provider_coarse.cpp @@ -0,0 +1,638 @@ +/* + * 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 "malloc" +#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); + + 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 + std::unique_ptr buffer(new char[init_buffer_size]); + void *buf = buffer.get(); + ASSERT_NE(buf, nullptr); + memset(buf, 0, init_buffer_size); + + 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); + + 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 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 + std::unique_ptr buffer(new char[init_buffer_size]); + void *buf = buffer.get(); + ASSERT_NE(buf, nullptr); + memset(buf, 0, init_buffer_size); + + 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 + std::unique_ptr buffer(new char[init_buffer_size]); + void *buf = buffer.get(); + ASSERT_NE(buf, nullptr); + memset(buf, 0, init_buffer_size); + + 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 + std::unique_ptr buffer(new char[init_buffer_size]); + void *buf = buffer.get(); + ASSERT_NE(buf, nullptr); + memset(buf, 0, init_buffer_size); + + 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 + std::unique_ptr buffer(new char[init_buffer_size]); + void *buf = buffer.get(); + ASSERT_NE(buf, nullptr); + memset(buf, 0, init_buffer_size); + + 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 e5249227f1a83ccfa717d02eaf11a9099bfddd46 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Tue, 22 Oct 2024 07:39:56 -0700 Subject: [PATCH 210/352] Add tests for L0 provider --- test/providers/provider_level_zero.cpp | 111 +++++++++++++++++++++---- 1 file changed, 94 insertions(+), 17 deletions(-) diff --git a/test/providers/provider_level_zero.cpp b/test/providers/provider_level_zero.cpp index f1312a770..4403af46e 100644 --- a/test/providers/provider_level_zero.cpp +++ b/test/providers/provider_level_zero.cpp @@ -141,14 +141,9 @@ struct umfLevelZeroProviderTest auto [l0_params, accessor] = this->GetParam(); params = l0_params; - hDevice = (ze_device_handle_t)params.level_zero_device_handle; + memAccessor = accessor; hContext = (ze_context_handle_t)params.level_zero_context_handle; - if (params.memory_type == UMF_MEMORY_TYPE_HOST) { - ASSERT_EQ(hDevice, nullptr); - } else { - ASSERT_NE(hDevice, nullptr); - } ASSERT_NE(hContext, nullptr); switch (params.memory_type) { @@ -167,21 +162,14 @@ struct umfLevelZeroProviderTest } ASSERT_NE(zeMemoryTypeExpected, ZE_MEMORY_TYPE_UNKNOWN); - - memAccessor = accessor; } - void TearDown() override { - int ret = destroy_context(hContext); - ASSERT_EQ(ret, 0); - test::TearDown(); - } + void TearDown() override { test::TearDown(); } level_zero_memory_provider_params_t params; - ze_device_handle_t hDevice = nullptr; + MemoryAccessor *memAccessor = nullptr; ze_context_handle_t hContext = nullptr; ze_memory_type_t zeMemoryTypeExpected = ZE_MEMORY_TYPE_UNKNOWN; - MemoryAccessor *memAccessor = nullptr; }; GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(umfLevelZeroProviderTest); @@ -222,8 +210,97 @@ TEST_P(umfLevelZeroProviderTest, basic) { umfMemoryProviderDestroy(provider); } -// TODO add Level Zero Memory Provider specyfic tests -// TODO add negative test and check for Level Zero native errors +TEST_P(umfLevelZeroProviderTest, getPageSize) { + umf_memory_provider_handle_t provider = nullptr; + umf_result_t umf_result = umfMemoryProviderCreate( + umfLevelZeroMemoryProviderOps(), ¶ms, &provider); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(provider, nullptr); + + size_t recommendedPageSize = 0; + umf_result = umfMemoryProviderGetRecommendedPageSize(provider, 0, + &recommendedPageSize); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_GE(recommendedPageSize, 0); + + size_t minPageSize = 0; + umf_result = + umfMemoryProviderGetMinPageSize(provider, nullptr, &minPageSize); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_GE(minPageSize, 0); + + ASSERT_GE(recommendedPageSize, minPageSize); + + umfMemoryProviderDestroy(provider); +} + +TEST_P(umfLevelZeroProviderTest, getName) { + umf_memory_provider_handle_t provider = nullptr; + umf_result_t umf_result = umfMemoryProviderCreate( + umfLevelZeroMemoryProviderOps(), ¶ms, &provider); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(provider, nullptr); + + const char *name = umfMemoryProviderGetName(provider); + ASSERT_STREQ(name, "LEVEL_ZERO"); + + umfMemoryProviderDestroy(provider); +} + +TEST_P(umfLevelZeroProviderTest, allocInvalidSize) { + umf_memory_provider_handle_t provider = nullptr; + umf_result_t umf_result = umfMemoryProviderCreate( + umfLevelZeroMemoryProviderOps(), ¶ms, &provider); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(provider, nullptr); + + // try to alloc (int)-1 + void *ptr = nullptr; + umf_result = umfMemoryProviderAlloc(provider, -1, 0, &ptr); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC); + const char *message; + int32_t error; + umfMemoryProviderGetLastNativeError(provider, &message, &error); + ASSERT_EQ(error, ZE_RESULT_ERROR_UNSUPPORTED_SIZE); + + // in case of size == 0 we should got INVALID_ARGUMENT error + // NOTE: this is invalid only for the DEVICE or SHARED allocations + if (params.memory_type != UMF_MEMORY_TYPE_HOST) { + umf_result = umfMemoryProviderAlloc(provider, 0, 0, &ptr); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC); + umfMemoryProviderGetLastNativeError(provider, &message, &error); + ASSERT_EQ(error, ZE_RESULT_ERROR_UNSUPPORTED_SIZE); + } + + umfMemoryProviderDestroy(provider); +} + +TEST_P(umfLevelZeroProviderTest, providerCreateInvalidArgs) { + umf_memory_provider_handle_t provider = nullptr; + umf_result_t umf_result = umfMemoryProviderCreate( + umfLevelZeroMemoryProviderOps(), nullptr, &provider); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + umf_result = umfMemoryProviderCreate(nullptr, ¶ms, nullptr); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} + +TEST_P(umfLevelZeroProviderTest, getPageSizeInvalidArgs) { + umf_memory_provider_handle_t provider = nullptr; + umf_result_t umf_result = umfMemoryProviderCreate( + umfLevelZeroMemoryProviderOps(), ¶ms, &provider); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(provider, nullptr); + + umf_result = umfMemoryProviderGetMinPageSize(provider, nullptr, nullptr); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + umf_result = umfMemoryProviderGetRecommendedPageSize(provider, 0, nullptr); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + umfMemoryProviderDestroy(provider); +} + // TODO add tests that mixes Level Zero Memory Provider and Disjoint Pool level_zero_memory_provider_params_t l0Params_device_memory = From 9a47aae72b52a28ac657cdc345d4858f77e0175f Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 23 Oct 2024 10:57:25 +0200 Subject: [PATCH 211/352] Fix file_open_ipc_handle() Remove the wrong check - the paths: file_ipc_data->path and file_provider->path should be different. Signed-off-by: Lukasz Dorau --- src/provider/provider_file_memory.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/provider/provider_file_memory.c b/src/provider/provider_file_memory.c index 274aab0b2..73f78186e 100644 --- a/src/provider/provider_file_memory.c +++ b/src/provider/provider_file_memory.c @@ -665,10 +665,6 @@ static umf_result_t file_open_ipc_handle(void *provider, void *providerIpcData, umf_result_t ret = UMF_RESULT_SUCCESS; int fd; - if (strncmp(file_ipc_data->path, file_provider->path, PATH_MAX)) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - fd = utils_file_open(file_ipc_data->path); if (fd == -1) { LOG_PERR("opening the file to be mapped (%s) failed", From 319d1978c8c58115621aa9373a04043558867897 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 23 Oct 2024 10:42:36 +0200 Subject: [PATCH 212/352] Fix ipc_file_prov test: should use two different files Fix ipc_file_prov test: producer and consumer should use two different files. Signed-off-by: Lukasz Dorau --- test/ipc_file_prov.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/ipc_file_prov.sh b/test/ipc_file_prov.sh index 6807f4009..b3e3091a8 100755 --- a/test/ipc_file_prov.sh +++ b/test/ipc_file_prov.sh @@ -20,13 +20,13 @@ UMF_LOG_VAL="level:debug;flush:debug;output:stderr;pid:yes" rm -f ${FILE_NAME} echo "Starting ipc_file_prov CONSUMER on port $PORT ..." -UMF_LOG=$UMF_LOG_VAL ./umf_test-ipc_file_prov_consumer $PORT $FILE_NAME & +UMF_LOG=$UMF_LOG_VAL ./umf_test-ipc_file_prov_consumer $PORT ${FILE_NAME}_consumer & echo "Waiting 1 sec ..." sleep 1 echo "Starting ipc_file_prov PRODUCER on port $PORT ..." -UMF_LOG=$UMF_LOG_VAL ./umf_test-ipc_file_prov_producer $PORT $FILE_NAME +UMF_LOG=$UMF_LOG_VAL ./umf_test-ipc_file_prov_producer $PORT ${FILE_NAME}_producer # remove the SHM file rm -f ${FILE_NAME} From 6694f845c980cd12fae36ba23dcbee9d9090e124 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 23 Oct 2024 11:15:35 +0200 Subject: [PATCH 213/352] Fix ipc_file_prov_fsdax test: should use two different files Fix ipc_file_prov_fsdax test: producer and consumer should use two different FSDAX files. Signed-off-by: Lukasz Dorau --- test/ipc_file_prov_fsdax.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/ipc_file_prov_fsdax.sh b/test/ipc_file_prov_fsdax.sh index 56c540a65..6f8d75541 100755 --- a/test/ipc_file_prov_fsdax.sh +++ b/test/ipc_file_prov_fsdax.sh @@ -14,7 +14,13 @@ if [ "$UMF_TESTS_FSDAX_PATH" = "" ]; then exit 0 fi +if [ "$UMF_TESTS_FSDAX_PATH_2" = "" ]; then + echo "$0: Test skipped, UMF_TESTS_FSDAX_PATH_2 is not set"; + exit 0 +fi + FILE_NAME="$UMF_TESTS_FSDAX_PATH" +FILE_NAME_2="$UMF_TESTS_FSDAX_PATH_2" # port should be a number from the range <1024, 65535> PORT=$(( 1024 + ( $$ % ( 65535 - 1024 )))) @@ -31,7 +37,7 @@ echo "Waiting 1 sec ..." sleep 1 echo "Starting ipc_file_prov_fsdax PRODUCER on port $PORT ..." -UMF_LOG=$UMF_LOG_VAL ./umf_test-ipc_file_prov_producer $PORT $FILE_NAME "FSDAX" +UMF_LOG=$UMF_LOG_VAL ./umf_test-ipc_file_prov_producer $PORT $FILE_NAME_2 "FSDAX" # remove the SHM file rm -f ${FILE_NAME} From ddab0e68b997968a6b44f793d635e4022c7413c2 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 23 Oct 2024 12:10:36 +0200 Subject: [PATCH 214/352] Add UMF_TESTS_FSDAX_PATH_2 to CI Signed-off-by: Lukasz Dorau --- .github/workflows/reusable_dax.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/reusable_dax.yml b/.github/workflows/reusable_dax.yml index b776d3eff..24e5a1bdb 100644 --- a/.github/workflows/reusable_dax.yml +++ b/.github/workflows/reusable_dax.yml @@ -26,6 +26,7 @@ env: FSDAX_NAMESPACE : "1.0" FSDAX_PMEM: "pmem1" UMF_TESTS_FSDAX_PATH: "/mnt/pmem1/file" + UMF_TESTS_FSDAX_PATH_2: "/mnt/pmem1/file_2" BUILD_DIR : "${{github.workspace}}/build" INSTL_DIR : "${{github.workspace}}/../install-dir" COVERAGE_DIR : "${{github.workspace}}/coverage" @@ -55,11 +56,12 @@ jobs: run: | echo FSDAX_NAMESPACE="${{env.FSDAX_NAMESPACE}}" echo UMF_TESTS_FSDAX_PATH="${{env.UMF_TESTS_FSDAX_PATH}}" + echo UMF_TESTS_FSDAX_PATH_2="${{env.UMF_TESTS_FSDAX_PATH_2}}" ndctl list --namespace=namespace${{env.FSDAX_NAMESPACE}} ls -al /dev/${{env.FSDAX_PMEM}} /mnt/${{env.FSDAX_PMEM}} mount | grep -e "/dev/${{env.FSDAX_PMEM}}" - touch ${{env.UMF_TESTS_FSDAX_PATH}} - rm -f ${{env.UMF_TESTS_FSDAX_PATH}} + touch ${{env.UMF_TESTS_FSDAX_PATH}} ${{env.UMF_TESTS_FSDAX_PATH_2}} + rm -f ${{env.UMF_TESTS_FSDAX_PATH}} ${{env.UMF_TESTS_FSDAX_PATH_2}} - name: Checkout uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 @@ -100,9 +102,9 @@ jobs: - name: Run the FSDAX tests working-directory: ${{env.BUILD_DIR}} run: | - UMF_TESTS_FSDAX_PATH=${{env.UMF_TESTS_FSDAX_PATH}} ctest -C ${{matrix.build_type}} -R umf-provider_file_memory -V - UMF_TESTS_FSDAX_PATH=${{env.UMF_TESTS_FSDAX_PATH}} ctest -C ${{matrix.build_type}} -R umf_example_dram_and_fsdax -V - UMF_TESTS_FSDAX_PATH=${{env.UMF_TESTS_FSDAX_PATH}} ctest -C ${{matrix.build_type}} -R umf-ipc_file_prov_fsdax -V + UMF_TESTS_FSDAX_PATH=${{env.UMF_TESTS_FSDAX_PATH}} UMF_TESTS_FSDAX_PATH_2=${{env.UMF_TESTS_FSDAX_PATH_2}} ctest -C ${{matrix.build_type}} -R umf-provider_file_memory -V + UMF_TESTS_FSDAX_PATH=${{env.UMF_TESTS_FSDAX_PATH}} UMF_TESTS_FSDAX_PATH_2=${{env.UMF_TESTS_FSDAX_PATH_2}} ctest -C ${{matrix.build_type}} -R umf_example_dram_and_fsdax -V + UMF_TESTS_FSDAX_PATH=${{env.UMF_TESTS_FSDAX_PATH}} UMF_TESTS_FSDAX_PATH_2=${{env.UMF_TESTS_FSDAX_PATH_2}} ctest -C ${{matrix.build_type}} -R umf-ipc_file_prov_fsdax -V - name: Check coverage if: ${{ matrix.build_type == 'Debug' }} From a4080b4c7bf475cafe5a2cfaf8daa182792ca1a8 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 23 Oct 2024 14:00:17 +0200 Subject: [PATCH 215/352] Use std::vector instead of std::unique_ptr Use std::vector instead of std::unique_ptr because we do not need to use memset(0) in this case. Signed-off-by: Lukasz Dorau --- test/disjointCoarseMallocPool.cpp | 7 +++---- test/provider_coarse.cpp | 35 +++++++++++++------------------ 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/test/disjointCoarseMallocPool.cpp b/test/disjointCoarseMallocPool.cpp index d650815df..0ff38bb1c 100644 --- a/test/disjointCoarseMallocPool.cpp +++ b/test/disjointCoarseMallocPool.cpp @@ -395,11 +395,10 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMMapPool_random) { const size_t init_buffer_size = 200 * MB; - // Preallocate some memory - std::unique_ptr buffer(new char[init_buffer_size]); - void *buf = buffer.get(); + // 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); - memset(buf, 0, init_buffer_size); const unsigned char alloc_check_val = 11; diff --git a/test/provider_coarse.cpp b/test/provider_coarse.cpp index 7d5c06c09..6995f6aba 100644 --- a/test/provider_coarse.cpp +++ b/test/provider_coarse.cpp @@ -85,11 +85,10 @@ TEST_F(test, coarseProvider_name_no_upstream) { const size_t init_buffer_size = 20 * MB; - // Preallocate some memory - std::unique_ptr buffer(new char[init_buffer_size]); - void *buf = buffer.get(); + // 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); - memset(buf, 0, init_buffer_size); coarse_memory_provider_params_t coarse_memory_provider_params; // make sure there are no undefined members - prevent a UB @@ -159,11 +158,10 @@ TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_wrong_params_1) { const size_t init_buffer_size = 20 * MB; - // Preallocate some memory - std::unique_ptr buffer(new char[init_buffer_size]); - void *buf = buffer.get(); + // 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); - memset(buf, 0, init_buffer_size); coarse_memory_provider_params_t coarse_memory_provider_params; // make sure there are no undefined members - prevent a UB @@ -223,11 +221,10 @@ TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_wrong_params_3) { const size_t init_buffer_size = 20 * MB; - // Preallocate some memory - std::unique_ptr buffer(new char[init_buffer_size]); - void *buf = buffer.get(); + // 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); - memset(buf, 0, init_buffer_size); coarse_memory_provider_params_t coarse_memory_provider_params; // make sure there are no undefined members - prevent a UB @@ -284,11 +281,10 @@ TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_wrong_params_5) { const size_t init_buffer_size = 20 * MB; - // Preallocate some memory - std::unique_ptr buffer(new char[init_buffer_size]); - void *buf = buffer.get(); + // 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); - memset(buf, 0, init_buffer_size); coarse_memory_provider_params_t coarse_memory_provider_params; // make sure there are no undefined members - prevent a UB @@ -521,11 +517,10 @@ TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_purge_no_upstream) { const size_t init_buffer_size = 20 * MB; - // Preallocate some memory - std::unique_ptr buffer(new char[init_buffer_size]); - void *buf = buffer.get(); + // 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); - memset(buf, 0, init_buffer_size); coarse_memory_provider_params_t coarse_memory_provider_params; // make sure there are no undefined members - prevent a UB From 0e3d87cb0c72dc90552d30ae6476e3afd81ea04b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Tue, 22 Oct 2024 17:56:21 +0200 Subject: [PATCH 216/352] Add badge with coverage number to Readme --- .github/workflows/pr_push.yml | 3 +++ .github/workflows/reusable_coverage.yml | 24 +++++++++++++++++++++++- README.md | 1 + 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pr_push.yml b/.github/workflows/pr_push.yml index 86fa50fd2..8b78ce3d0 100644 --- a/.github/workflows/pr_push.yml +++ b/.github/workflows/pr_push.yml @@ -57,6 +57,9 @@ jobs: if: github.repository == 'oneapi-src/unified-memory-framework' needs: [Build, DevDax, GPU, MultiNuma, Qemu, ProxyLib] uses: ./.github/workflows/reusable_coverage.yml + secrets: inherit + with: + trigger: "${{github.event_name}}" Coverage_partial: # partial coverage (on forks) if: github.repository != 'oneapi-src/unified-memory-framework' diff --git a/.github/workflows/reusable_coverage.yml b/.github/workflows/reusable_coverage.yml index b71836fa6..c8dde20ec 100644 --- a/.github/workflows/reusable_coverage.yml +++ b/.github/workflows/reusable_coverage.yml @@ -1,7 +1,13 @@ # Coverage build - gather artifacts from other builds and merge them into a single report name: Coverage -on: workflow_call +on: + workflow_call: + inputs: + trigger: + description: Type of workflow trigger + type: string + required: false permissions: contents: read @@ -34,6 +40,7 @@ jobs: - name: Compute coverage working-directory: ${{env.COVERAGE_DIR}} + id: coverage run: | echo "DIR: $(pwd)" && ls -al ../scripts/coverage/merge_coverage_files.sh exports-coverage total_coverage @@ -41,9 +48,24 @@ jobs: mkdir coverage_report mv html_report ./coverage_report/ tail -n2 output.txt >> $GITHUB_STEP_SUMMARY + echo "COV_OUT=$(tail -n1 output.txt | grep -oP "lines[.]+: [\d.]+%" | cut -d ' ' -f2 | tr -d '%')" >> $GITHUB_OUTPUT - name: Upload coverage report uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 with: name: coverage_html_report path: coverage/coverage_report + + # Only update the badge on push (event is passed only for total coverage) + - name: Update coverity badge + if: ${{ success() && inputs.trigger == 'push' }} + uses: Schneegans/dynamic-badges-action@e9a478b16159b4d31420099ba146cdc50f134483 # v1.7.0 + with: + auth: ${{ secrets.BB_GIST_TOKEN }} + gistID: 3f66c77d7035df39aa75dda8a2ac75b3 + filename: umf_coverage_badge.svg + label: Coverage + message: ${{ steps.coverage.outputs.COV_OUT }}% + valColorRange: ${{ steps.coverage.outputs.COV_OUT }} + minColorRange: 50 # <= this value = color: red + maxColorRange: 90 # >= this value = color: green diff --git a/README.md b/README.md index 2c4146dc6..029166e51 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Unified Memory Framework [![PR/push](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/pr_push.yml/badge.svg?branch=main)](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/pr_push.yml) +[![Coverage](https://gist.githubusercontent.com/bb-ur/3f66c77d7035df39aa75dda8a2ac75b3/raw/umf_coverage_badge.svg)](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/pr_push.yml?query=branch%3Amain) [![GitHubPages](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/docs.yml/badge.svg?branch=main)](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/docs.yml) [![Nightly](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/nightly.yml/badge.svg?branch=main)](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/nightly.yml) [![Bandit](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/bandit.yml/badge.svg?branch=main)](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/bandit.yml) From b32976010cef8b00331e8f05d64cb197a20291f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Wed, 23 Oct 2024 14:23:00 +0200 Subject: [PATCH 217/352] Cleanup badges - use PR/push status only from 'push' event (fails on PRs are not significant), - remove badges that do not have their own workflows now. --- README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/README.md b/README.md index 029166e51..f759f8636 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,11 @@ # Unified Memory Framework -[![PR/push](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/pr_push.yml/badge.svg?branch=main)](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/pr_push.yml) +[![PR/push](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/pr_push.yml/badge.svg?branch=main&event=push)](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/pr_push.yml) [![Coverage](https://gist.githubusercontent.com/bb-ur/3f66c77d7035df39aa75dda8a2ac75b3/raw/umf_coverage_badge.svg)](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/pr_push.yml?query=branch%3Amain) [![GitHubPages](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/docs.yml/badge.svg?branch=main)](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/docs.yml) [![Nightly](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/nightly.yml/badge.svg?branch=main)](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/nightly.yml) -[![Bandit](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/bandit.yml/badge.svg?branch=main)](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/bandit.yml) -[![CodeQL](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/codeql.yml/badge.svg?branch=main)](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/codeql.yml) [![Coverity build](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/coverity.yml/badge.svg?branch=main)](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/coverity.yml) [![Coverity report](https://scan.coverity.com/projects/29761/badge.svg?flat=0)](https://scan.coverity.com/projects/oneapi-src-unified-memory-framework) -[![Trivy](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/trivy.yml/badge.svg)](https://github.com/oneapi-src/unified-memory-framework/actions/workflows/trivy.yml) [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/oneapi-src/unified-memory-framework/badge)](https://securityscorecards.dev/viewer/?uri=github.com/oneapi-src/unified-memory-framework) ## Introduction From 77c6b7255b6475c79e20ddb046ab6614f9f2491c Mon Sep 17 00:00:00 2001 From: Rafal Rudnicki Date: Thu, 24 Oct 2024 09:40:34 +0200 Subject: [PATCH 218/352] fix error handling in IPC common --- test/common/ipc_common.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/test/common/ipc_common.c b/test/common/ipc_common.c index fdc9643f3..9d78afc9c 100644 --- a/test/common/ipc_common.c +++ b/test/common/ipc_common.c @@ -147,7 +147,7 @@ int run_consumer(int port, umf_memory_pool_ops_t *pool_ops, void *pool_params, char *recv_buffer = calloc(1, MSG_SIZE); if (!recv_buffer) { fprintf(stderr, "[consumer] ERROR: out of memory\n"); - goto err_umfMemoryPoolDestroy; + goto err_close_producer_socket; } // get the size of the IPC handle from the producer @@ -155,14 +155,19 @@ int run_consumer(int port, umf_memory_pool_ops_t *pool_ops, void *pool_params, ssize_t recv_len = recv(producer_socket, recv_buffer, MSG_SIZE, 0); if (recv_len < 0) { fprintf(stderr, "[consumer] ERROR: recv() failed\n"); - goto err_close_producer_socket; + goto err_free_recv_buffer; } IPC_handle_size = *(size_t *)recv_buffer; fprintf(stderr, "[consumer] Got the size of the IPC handle: %zu\n", IPC_handle_size); // send confirmation to the producer (IPC handle size) - send(producer_socket, &IPC_handle_size, sizeof(IPC_handle_size), 0); + recv_len = + send(producer_socket, &IPC_handle_size, sizeof(IPC_handle_size), 0); + if (recv_len < 0) { + fprintf(stderr, "[consumer] ERROR: sending confirmation failed\n"); + goto err_free_recv_buffer; + } fprintf(stderr, "[consumer] Send the confirmation (IPC handle size) to producer\n"); @@ -170,7 +175,7 @@ int run_consumer(int port, umf_memory_pool_ops_t *pool_ops, void *pool_params, recv_len = recv(producer_socket, recv_buffer, MSG_SIZE, 0); if (recv_len < 0) { fprintf(stderr, "[consumer] ERROR: recv() failed\n"); - goto err_close_producer_socket; + goto err_free_recv_buffer; } size_t len = (size_t)recv_len; @@ -179,7 +184,7 @@ int run_consumer(int port, umf_memory_pool_ops_t *pool_ops, void *pool_params, "[consumer] ERROR: recv() received a wrong number of bytes " "(%zi != %zu expected)\n", len, IPC_handle_size); - goto err_close_producer_socket; + goto err_free_recv_buffer; } void *IPC_handle = recv_buffer; @@ -203,11 +208,11 @@ int run_consumer(int port, umf_memory_pool_ops_t *pool_ops, void *pool_params, send(producer_socket, consumer_message, strlen(consumer_message) + 1, 0); - goto err_close_producer_socket; + goto err_free_recv_buffer; } if (umf_result != UMF_RESULT_SUCCESS) { fprintf(stderr, "[consumer] ERROR: opening the IPC handle failed\n"); - goto err_close_producer_socket; + goto err_free_recv_buffer; } fprintf(stderr, @@ -255,6 +260,9 @@ int run_consumer(int port, umf_memory_pool_ops_t *pool_ops, void *pool_params, fprintf(stderr, "[consumer] Closed the IPC handle received from the producer\n"); +err_free_recv_buffer: + free(recv_buffer); + err_close_producer_socket: close(producer_socket); From 9fa2578cab76d34cefe2f6eb896292a1cfa05da7 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Tue, 22 Oct 2024 06:38:41 -0700 Subject: [PATCH 219/352] Fix cuda_copy function. --- test/providers/cuda_helpers.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/providers/cuda_helpers.cpp b/test/providers/cuda_helpers.cpp index 2b332dde1..734f287e0 100644 --- a/test/providers/cuda_helpers.cpp +++ b/test/providers/cuda_helpers.cpp @@ -33,6 +33,7 @@ struct libcu_ops { CUresult (*cuPointerGetAttributes)(unsigned int numAttributes, CUpointer_attribute *attributes, void **data, CUdeviceptr ptr); + CUresult (*cuStreamSynchronize)(CUstream hStream); } libcu_ops; #if USE_DLOPEN @@ -145,6 +146,13 @@ int InitCUDAOps() { lib_name); return -1; } + *(void **)&libcu_ops.cuStreamSynchronize = utils_get_symbol_addr( + cuDlHandle.get(), "cuStreamSynchronize", lib_name); + if (libcu_ops.cuStreamSynchronize == nullptr) { + fprintf(stderr, "cuStreamSynchronize symbol not found in %s\n", + lib_name); + return -1; + } return 0; } @@ -167,6 +175,7 @@ int InitCUDAOps() { libcu_ops.cuMemcpy = cuMemcpy; libcu_ops.cuPointerGetAttribute = cuPointerGetAttribute; libcu_ops.cuPointerGetAttributes = cuPointerGetAttributes; + libcu_ops.cuStreamSynchronize = cuStreamSynchronize; return 0; } @@ -218,6 +227,12 @@ int cuda_copy(CUcontext context, CUdevice device, void *dst_ptr, void *src_ptr, return -1; } + res = libcu_ops.cuStreamSynchronize(0); + if (res != CUDA_SUCCESS) { + fprintf(stderr, "cuStreamSynchronize() failed!\n"); + return -1; + } + return ret; } From fc04ff4d770171c69f6c146a2b714a9411eb5de5 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Thu, 17 Oct 2024 08:59:43 -0700 Subject: [PATCH 220/352] IPC API implementation for CUDA provider --- src/provider/provider_cuda.c | 109 ++++++++++++++++++++++++++++++++++- 1 file changed, 107 insertions(+), 2 deletions(-) diff --git a/src/provider/provider_cuda.c b/src/provider/provider_cuda.c index 4d7a26516..715e6e790 100644 --- a/src/provider/provider_cuda.c +++ b/src/provider/provider_cuda.c @@ -53,8 +53,14 @@ typedef struct cu_ops_t { CUresult (*cuGetErrorString)(CUresult error, const char **pStr); CUresult (*cuCtxGetCurrent)(CUcontext *pctx); CUresult (*cuCtxSetCurrent)(CUcontext ctx); + CUresult (*cuIpcGetMemHandle)(CUipcMemHandle *pHandle, CUdeviceptr dptr); + CUresult (*cuIpcOpenMemHandle)(CUdeviceptr *pdptr, CUipcMemHandle handle, + unsigned int Flags); + CUresult (*cuIpcCloseMemHandle)(CUdeviceptr dptr); } cu_ops_t; +typedef CUipcMemHandle cu_ipc_data_t; + static cu_ops_t g_cu_ops; static UTIL_ONCE_FLAG cu_is_initialized = UTIL_ONCE_FLAG_INIT; static bool Init_cu_global_state_failed; @@ -123,12 +129,20 @@ static void init_cu_global_state(void) { utils_get_symbol_addr(0, "cuCtxGetCurrent", lib_name); *(void **)&g_cu_ops.cuCtxSetCurrent = utils_get_symbol_addr(0, "cuCtxSetCurrent", lib_name); + *(void **)&g_cu_ops.cuIpcGetMemHandle = + utils_get_symbol_addr(0, "cuIpcGetMemHandle", lib_name); + *(void **)&g_cu_ops.cuIpcOpenMemHandle = + utils_get_symbol_addr(0, "cuIpcOpenMemHandle_v2", lib_name); + *(void **)&g_cu_ops.cuIpcCloseMemHandle = + utils_get_symbol_addr(0, "cuIpcCloseMemHandle", lib_name); if (!g_cu_ops.cuMemGetAllocationGranularity || !g_cu_ops.cuMemAlloc || !g_cu_ops.cuMemAllocHost || !g_cu_ops.cuMemAllocManaged || !g_cu_ops.cuMemFree || !g_cu_ops.cuMemFreeHost || !g_cu_ops.cuGetErrorName || !g_cu_ops.cuGetErrorString || - !g_cu_ops.cuCtxGetCurrent || !g_cu_ops.cuCtxSetCurrent) { + !g_cu_ops.cuCtxGetCurrent || !g_cu_ops.cuCtxSetCurrent || + !g_cu_ops.cuIpcGetMemHandle || !g_cu_ops.cuIpcOpenMemHandle || + !g_cu_ops.cuIpcCloseMemHandle) { LOG_ERR("Required CUDA symbols not found."); Init_cu_global_state_failed = true; } @@ -404,6 +418,97 @@ static const char *cu_memory_provider_get_name(void *provider) { return "CUDA"; } +static umf_result_t cu_memory_provider_get_ipc_handle_size(void *provider, + size_t *size) { + if (provider == NULL || size == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + *size = sizeof(cu_ipc_data_t); + return UMF_RESULT_SUCCESS; +} + +static umf_result_t cu_memory_provider_get_ipc_handle(void *provider, + const void *ptr, + size_t size, + void *providerIpcData) { + (void)size; + + if (provider == NULL || ptr == NULL || providerIpcData == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + CUresult cu_result; + cu_ipc_data_t *cu_ipc_data = (cu_ipc_data_t *)providerIpcData; + + cu_result = g_cu_ops.cuIpcGetMemHandle(cu_ipc_data, (CUdeviceptr)ptr); + if (cu_result != CUDA_SUCCESS) { + LOG_ERR("cuIpcGetMemHandle() failed."); + return cu2umf_result(cu_result); + } + + return UMF_RESULT_SUCCESS; +} + +static umf_result_t cu_memory_provider_put_ipc_handle(void *provider, + void *providerIpcData) { + if (provider == NULL || providerIpcData == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + return UMF_RESULT_SUCCESS; +} + +static umf_result_t cu_memory_provider_open_ipc_handle(void *provider, + void *providerIpcData, + void **ptr) { + if (provider == NULL || ptr == NULL || providerIpcData == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + cu_memory_provider_t *cu_provider = (cu_memory_provider_t *)provider; + + CUresult cu_result; + cu_ipc_data_t *cu_ipc_data = (cu_ipc_data_t *)providerIpcData; + + // Remember current context and set the one from the provider + CUcontext restore_ctx = NULL; + umf_result_t umf_result = set_context(cu_provider->context, &restore_ctx); + if (umf_result != UMF_RESULT_SUCCESS) { + return umf_result; + } + + cu_result = g_cu_ops.cuIpcOpenMemHandle((CUdeviceptr *)ptr, *cu_ipc_data, + CU_IPC_MEM_LAZY_ENABLE_PEER_ACCESS); + + if (cu_result != CUDA_SUCCESS) { + LOG_ERR("cuIpcOpenMemHandle() failed."); + } + + set_context(restore_ctx, &restore_ctx); + + return cu2umf_result(cu_result); +} + +static umf_result_t +cu_memory_provider_close_ipc_handle(void *provider, void *ptr, size_t size) { + (void)size; + + if (provider == NULL || ptr == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + CUresult cu_result; + + cu_result = g_cu_ops.cuIpcCloseMemHandle((CUdeviceptr)ptr); + if (cu_result != CUDA_SUCCESS) { + LOG_ERR("cuIpcCloseMemHandle() failed."); + return cu2umf_result(cu_result); + } + + return UMF_RESULT_SUCCESS; +} + static struct umf_memory_provider_ops_t UMF_CUDA_MEMORY_PROVIDER_OPS = { .version = UMF_VERSION_CURRENT, .initialize = cu_memory_provider_initialize, @@ -420,12 +525,12 @@ static struct umf_memory_provider_ops_t UMF_CUDA_MEMORY_PROVIDER_OPS = { .ext.purge_force = cu_memory_provider_purge_force, .ext.allocation_merge = cu_memory_provider_allocation_merge, .ext.allocation_split = cu_memory_provider_allocation_split, + */ .ipc.get_ipc_handle_size = cu_memory_provider_get_ipc_handle_size, .ipc.get_ipc_handle = cu_memory_provider_get_ipc_handle, .ipc.put_ipc_handle = cu_memory_provider_put_ipc_handle, .ipc.open_ipc_handle = cu_memory_provider_open_ipc_handle, .ipc.close_ipc_handle = cu_memory_provider_close_ipc_handle, - */ }; umf_memory_provider_ops_t *umfCUDAMemoryProviderOps(void) { From 738dc522c6ebc60eb050c3c7e5ac80d6b81f3414 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Fri, 18 Oct 2024 14:53:13 -0700 Subject: [PATCH 221/352] Add multiprocess IPC test for CUDA provider --- test/CMakeLists.txt | 34 +++++++++++++++++++++++++ test/providers/ipc_cuda_prov.sh | 24 +++++++++++++++++ test/providers/ipc_cuda_prov_common.c | 23 +++++++++++++++++ test/providers/ipc_cuda_prov_common.h | 15 +++++++++++ test/providers/ipc_cuda_prov_consumer.c | 34 +++++++++++++++++++++++++ test/providers/ipc_cuda_prov_producer.c | 34 +++++++++++++++++++++++++ 6 files changed, 164 insertions(+) create mode 100755 test/providers/ipc_cuda_prov.sh create mode 100644 test/providers/ipc_cuda_prov_common.c create mode 100644 test/providers/ipc_cuda_prov_common.h create mode 100644 test/providers/ipc_cuda_prov_consumer.c create mode 100644 test/providers/ipc_cuda_prov_producer.c diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8450f049f..6fefe90cb 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -500,6 +500,40 @@ if(LINUX) PRIVATE ${LEVEL_ZERO_INCLUDE_DIRS}) add_umf_ipc_test(TEST ipc_level_zero_prov SRC_DIR providers) endif() + + if(UMF_BUILD_GPU_TESTS + AND UMF_BUILD_CUDA_PROVIDER + AND UMF_BUILD_LIBUMF_POOL_DISJOINT) + build_umf_test( + NAME + ipc_cuda_prov_consumer + SRCS + providers/ipc_cuda_prov_consumer.c + common/ipc_common.c + providers/ipc_cuda_prov_common.c + providers/cuda_helpers.cpp + LIBS + cuda + disjoint_pool + ${UMF_UTILS_FOR_TEST}) + build_umf_test( + NAME + ipc_cuda_prov_producer + SRCS + providers/ipc_cuda_prov_producer.c + common/ipc_common.c + providers/ipc_cuda_prov_common.c + providers/cuda_helpers.cpp + LIBS + cuda + disjoint_pool + ${UMF_UTILS_FOR_TEST}) + target_include_directories(umf_test-ipc_cuda_prov_producer + PRIVATE ${CUDA_INCLUDE_DIRS}) + target_include_directories(umf_test-ipc_cuda_prov_consumer + PRIVATE ${CUDA_INCLUDE_DIRS}) + add_umf_ipc_test(TEST ipc_cuda_prov SRC_DIR providers) + endif() else() message(STATUS "IPC tests are supported on Linux only - skipping") endif() diff --git a/test/providers/ipc_cuda_prov.sh b/test/providers/ipc_cuda_prov.sh new file mode 100755 index 000000000..1e9b6b05d --- /dev/null +++ b/test/providers/ipc_cuda_prov.sh @@ -0,0 +1,24 @@ +# +# Copyright (C) 2024 Intel Corporation +# +# Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +#!/bin/bash + +set -e + +# port should be a number from the range <1024, 65535> +PORT=$(( 1024 + ( $$ % ( 65535 - 1024 )))) + +UMF_LOG_VAL="level:debug;flush:debug;output:stderr;pid:yes" + +echo "Starting ipc_cuda_prov CONSUMER on port $PORT ..." +UMF_LOG=$UMF_LOG_VAL ./umf_test-ipc_cuda_prov_consumer $PORT & + +echo "Waiting 1 sec ..." +sleep 1 + +echo "Starting ipc_cuda_prov PRODUCER on port $PORT ..." +UMF_LOG=$UMF_LOG_VAL ./umf_test-ipc_cuda_prov_producer $PORT diff --git a/test/providers/ipc_cuda_prov_common.c b/test/providers/ipc_cuda_prov_common.c new file mode 100644 index 000000000..fbcf8368d --- /dev/null +++ b/test/providers/ipc_cuda_prov_common.c @@ -0,0 +1,23 @@ +/* + * Copyright (C) 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 "cuda_helpers.h" +#include "ipc_cuda_prov_common.h" + +void memcopy(void *dst, const void *src, size_t size, void *context) { + cuda_memory_provider_params_t *cu_params = + (cuda_memory_provider_params_t *)context; + int ret = cuda_copy(cu_params->cuda_context_handle, + cu_params->cuda_device_handle, dst, src, size); + if (ret != 0) { + fprintf(stderr, "cuda_copy failed with error %d\n", ret); + } +} diff --git a/test/providers/ipc_cuda_prov_common.h b/test/providers/ipc_cuda_prov_common.h new file mode 100644 index 000000000..cecdc2bb8 --- /dev/null +++ b/test/providers/ipc_cuda_prov_common.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) 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_TEST_IPC_CUDA_PROV_COMMON_H +#define UMF_TEST_IPC_CUDA_PROV_COMMON_H + +#include + +void memcopy(void *dst, const void *src, size_t size, void *context); + +#endif // UMF_TEST_IPC_CUDA_PROV_COMMON_H diff --git a/test/providers/ipc_cuda_prov_consumer.c b/test/providers/ipc_cuda_prov_consumer.c new file mode 100644 index 000000000..5be6785a1 --- /dev/null +++ b/test/providers/ipc_cuda_prov_consumer.c @@ -0,0 +1,34 @@ +/* + * Copyright (C) 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 "cuda_helpers.h" +#include "ipc_common.h" +#include "ipc_cuda_prov_common.h" + +int main(int argc, char *argv[]) { + if (argc < 2) { + fprintf(stderr, "usage: %s \n", argv[0]); + return -1; + } + + int port = atoi(argv[1]); + + cuda_memory_provider_params_t cu_params = + create_cuda_prov_params(UMF_MEMORY_TYPE_DEVICE); + + umf_disjoint_pool_params_t pool_params = umfDisjointPoolParamsDefault(); + + return run_consumer(port, umfDisjointPoolOps(), &pool_params, + umfCUDAMemoryProviderOps(), &cu_params, memcopy, + &cu_params); +} diff --git a/test/providers/ipc_cuda_prov_producer.c b/test/providers/ipc_cuda_prov_producer.c new file mode 100644 index 000000000..bd4673ce7 --- /dev/null +++ b/test/providers/ipc_cuda_prov_producer.c @@ -0,0 +1,34 @@ +/* + * Copyright (C) 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 "cuda_helpers.h" +#include "ipc_common.h" +#include "ipc_cuda_prov_common.h" + +int main(int argc, char *argv[]) { + if (argc < 2) { + fprintf(stderr, "usage: %s \n", argv[0]); + return -1; + } + + int port = atoi(argv[1]); + + cuda_memory_provider_params_t cu_params = + create_cuda_prov_params(UMF_MEMORY_TYPE_DEVICE); + + umf_disjoint_pool_params_t pool_params = umfDisjointPoolParamsDefault(); + + return run_producer(port, umfDisjointPoolOps(), &pool_params, + umfCUDAMemoryProviderOps(), &cu_params, memcopy, + &cu_params); +} From 0da5844257499211e402684aa6f7ad577739bd55 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Thu, 24 Oct 2024 06:49:51 -0700 Subject: [PATCH 222/352] Fix help message in the ipc_level_zero_prov test --- test/providers/ipc_level_zero_prov_consumer.c | 2 +- test/providers/ipc_level_zero_prov_producer.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/providers/ipc_level_zero_prov_consumer.c b/test/providers/ipc_level_zero_prov_consumer.c index 009988b98..70b72a7fc 100644 --- a/test/providers/ipc_level_zero_prov_consumer.c +++ b/test/providers/ipc_level_zero_prov_consumer.c @@ -17,7 +17,7 @@ int main(int argc, char *argv[]) { if (argc < 2) { - fprintf(stderr, "usage: %s [shm_name]\n", argv[0]); + fprintf(stderr, "usage: %s \n", argv[0]); return -1; } diff --git a/test/providers/ipc_level_zero_prov_producer.c b/test/providers/ipc_level_zero_prov_producer.c index 11485c85e..8e758644f 100644 --- a/test/providers/ipc_level_zero_prov_producer.c +++ b/test/providers/ipc_level_zero_prov_producer.c @@ -17,7 +17,7 @@ int main(int argc, char *argv[]) { if (argc < 2) { - fprintf(stderr, "usage: %s [shm_name]\n", argv[0]); + fprintf(stderr, "usage: %s \n", argv[0]); return -1; } From e8cde28437c067e0c73a381147260206d45bdeba Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Fri, 25 Oct 2024 15:06:26 +0200 Subject: [PATCH 223/352] Disable temporarily failing CI job with ICX compiler Signed-off-by: Lukasz Dorau --- .github/workflows/reusable_basic.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/reusable_basic.yml b/.github/workflows/reusable_basic.yml index bfa21d40f..3b5fdbbf7 100644 --- a/.github/workflows/reusable_basic.yml +++ b/.github/workflows/reusable_basic.yml @@ -76,15 +76,15 @@ jobs: disable_hwloc: 'OFF' link_hwloc_statically: 'OFF' # test icx compiler - - os: 'ubuntu-22.04' - build_type: Release - compiler: {c: icx, cxx: icpx} - shared_library: 'ON' - level_zero_provider: 'ON' - cuda_provider: 'ON' - install_tbb: 'ON' - disable_hwloc: 'OFF' - link_hwloc_statically: 'OFF' + # - os: 'ubuntu-22.04' + # build_type: Release + # compiler: {c: icx, cxx: icpx} + # shared_library: 'ON' + # level_zero_provider: 'ON' + # cuda_provider: 'ON' + # install_tbb: 'ON' + # disable_hwloc: 'OFF' + # link_hwloc_statically: 'OFF' # test without installing TBB - os: 'ubuntu-22.04' build_type: Release From 89025a16f45fd8a5228234c5a3ba29e100ec1789 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Fri, 25 Oct 2024 15:40:31 +0200 Subject: [PATCH 224/352] Fix fetching L0 and CUDA headers and add UMF_CUDA_INCLUDE_DIR Fetch L0 loader only if needed i.e.: if building L0 provider is ON and L0 headers are not provided by the user (via setting UMF_LEVEL_ZERO_INCLUDE_DIR). Fetch CUDA only if needed i.e.: if building CUDA provider is ON and CUDA headers are not provided by the user (via setting UMF_CUDA_INCLUDE_DIR). Ref: #825 Fixes: #827 Signed-off-by: Lukasz Dorau --- src/CMakeLists.txt | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e2e1c6f55..f2d29294d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -6,17 +6,19 @@ include(${UMF_CMAKE_SOURCE_DIR}/cmake/helpers.cmake) set(UMF_LEVEL_ZERO_INCLUDE_DIR "" - CACHE PATH "Directory containing the Level Zero Headers") + CACHE PATH "Directory containing the Level Zero headers") +set(UMF_CUDA_INCLUDE_DIR + "" + CACHE PATH "Directory containing the CUDA headers") # Compile definitions for UMF library. # # TODO: Cleanup the compile definitions across all the CMake files set(UMF_COMMON_COMPILE_DEFINITIONS UMF_VERSION=${UMF_VERSION}) -# Only fetch L0 loader if needed (L0 provider and GPU tests are ON), and not -# already provided by the user (via setting UMF_LEVEL_ZERO_INCLUDE_DIR). -if(UMF_BUILD_LEVEL_ZERO_PROVIDER AND (UMF_BUILD_GPU_TESTS - OR (NOT UMF_LEVEL_ZERO_INCLUDE_DIR))) +# Fetch L0 loader only if needed i.e.: if building L0 provider is ON and L0 +# headers are not provided by the user (via setting UMF_LEVEL_ZERO_INCLUDE_DIR). +if(UMF_BUILD_LEVEL_ZERO_PROVIDER AND (NOT UMF_LEVEL_ZERO_INCLUDE_DIR)) include(FetchContent) set(LEVEL_ZERO_LOADER_REPO "https://github.com/oneapi-src/level-zero.git") @@ -44,7 +46,9 @@ elseif(UMF_BUILD_LEVEL_ZERO_PROVIDER) message(STATUS "Level Zero include directory: ${LEVEL_ZERO_INCLUDE_DIRS}") endif() -if(UMF_BUILD_CUDA_PROVIDER) +# Fetch CUDA only if needed i.e.: if building CUDA provider is ON and CUDA +# headers are not provided by the user (via setting UMF_CUDA_INCLUDE_DIR). +if(UMF_BUILD_CUDA_PROVIDER AND (NOT UMF_CUDA_INCLUDE_DIR)) include(FetchContent) set(CUDA_REPO @@ -64,6 +68,10 @@ if(UMF_BUILD_CUDA_PROVIDER) ${cuda-headers_SOURCE_DIR} CACHE PATH "Path to CUDA headers") message(STATUS "CUDA include directory: ${CUDA_INCLUDE_DIRS}") +elseif(UMF_BUILD_CUDA_PROVIDER) + # Only header is needed to build UMF + set(CUDA_INCLUDE_DIRS ${UMF_CUDA_INCLUDE_DIR}) + message(STATUS "CUDA include directory: ${CUDA_INCLUDE_DIRS}") endif() add_subdirectory(utils) From 65e988ad6c1d41d7a5a46dd315d1e7e0615d9e4d Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 30 Oct 2024 14:45:22 +0100 Subject: [PATCH 225/352] Add IPC tests for using an allocation after umfCloseIPCHandle() Add IPC tests for using an allocation after umfCloseIPCHandle(). Test if umfPoolMalloc() returns a usable pointer after umfCloseIPCHandle(). Signed-off-by: Lukasz Dorau --- test/ipcFixtures.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/ipcFixtures.hpp b/test/ipcFixtures.hpp index 78e085a19..8b99026ab 100644 --- a/test/ipcFixtures.hpp +++ b/test/ipcFixtures.hpp @@ -313,6 +313,10 @@ TEST_P(umfIpcTest, AllocFreeAllocTest) { ptr = umfPoolMalloc(pool.get(), SIZE); ASSERT_NE(ptr, nullptr); + // test if the allocated memory is usable - fill it with the 0xAB pattern. + const uint32_t pattern = 0xAB; + memAccessor->fill(ptr, SIZE, &pattern, sizeof(pattern)); + ret = umfGetIPCHandle(ptr, &ipcHandle, &handleSize); ASSERT_EQ(ret, UMF_RESULT_SUCCESS); From 6c828f6073498a28664bf49566115784034a0a5c Mon Sep 17 00:00:00 2001 From: Rafal Rudnicki Date: Tue, 29 Oct 2024 13:04:14 +0100 Subject: [PATCH 226/352] fix for the apply of the HWLOC security patch --- CMakeLists.txt | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e880418f5..927dee47a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -131,12 +131,6 @@ else() set(HWLOC_ENABLE_TESTING OFF) set(HWLOC_SKIP_LSTOPO ON) set(HWLOC_SKIP_TOOLS ON) - set(HWLOC_PATCH - git - apply - ${PROJECT_SOURCE_DIR}/cmake/fix_coverity_issues.patch - || - (exit 0)) message( STATUS @@ -147,8 +141,7 @@ else() hwloc_targ GIT_REPOSITORY ${UMF_HWLOC_REPO} GIT_TAG ${UMF_HWLOC_TAG} - PATCH_COMMAND ${HWLOC_PATCH} SOURCE_SUBDIR contrib/windows-cmake/ - FIND_PACKAGE_ARGS) + SOURCE_SUBDIR contrib/windows-cmake/ FIND_PACKAGE_ARGS) FetchContent_MakeAvailable(hwloc_targ) set(LIBHWLOC_INCLUDE_DIRS @@ -157,13 +150,6 @@ else() ${hwloc_targ_BINARY_DIR}/Release;${hwloc_targ_BINARY_DIR}/Debug) else() include(FetchContent) - set(HWLOC_PATCH - git - apply - ${PROJECT_SOURCE_DIR}/cmake/fix_coverity_issues.patch - || - (exit 0)) - message( STATUS "Will fetch hwloc from ${UMF_HWLOC_REPO} (tag: ${UMF_HWLOC_TAG})" @@ -172,8 +158,7 @@ else() FetchContent_Declare( hwloc_targ GIT_REPOSITORY ${UMF_HWLOC_REPO} - GIT_TAG ${UMF_HWLOC_TAG} - PATCH_COMMAND ${HWLOC_PATCH}) + GIT_TAG ${UMF_HWLOC_TAG}) FetchContent_MakeAvailable(hwloc_targ) add_custom_command( @@ -217,6 +202,22 @@ else() message(STATUS " LIBHWLOC_LIBRARY_DIRS = ${LIBHWLOC_LIBRARY_DIRS}") endif() +if(hwloc_targ_SOURCE_DIR) + # apply security patch for HWLOC + execute_process( + COMMAND git apply ${PROJECT_SOURCE_DIR}/cmake/fix_coverity_issues.patch + WORKING_DIRECTORY ${hwloc_targ_SOURCE_DIR} + OUTPUT_VARIABLE UMF_HWLOC_PATCH_OUTPUT + ERROR_VARIABLE UMF_HWLOC_PATCH_ERROR) + + if(UMF_HWLOC_PATCH_OUTPUT) + message(STATUS "HWLOC patch command output:\n${UMF_HWLOC_PATCH_OUTPUT}") + endif() + if(UMF_HWLOC_PATCH_ERROR) + message(WARNING "HWLOC patch command output:\n${UMF_HWLOC_PATCH_ERROR}") + endif() +endif() + # This build type check is not possible on Windows when CMAKE_BUILD_TYPE is not # set, because in this case the build type is determined after a CMake # configuration is done (at the build time) From 2034c4e8b51a8894a09de155293540b0a5d05e84 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Fri, 25 Oct 2024 09:46:25 +0200 Subject: [PATCH 227/352] Rename utils_align_ptr_size() to utils_align_ptr_up_size_down() Signed-off-by: Lukasz Dorau --- src/base_alloc/base_alloc.c | 6 ++++-- src/base_alloc/base_alloc_linear.c | 4 ++-- src/utils/utils_common.c | 4 ++-- src/utils/utils_common.h | 4 ++-- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/base_alloc/base_alloc.c b/src/base_alloc/base_alloc.c index 353e5058d..7a98684c6 100644 --- a/src/base_alloc/base_alloc.c +++ b/src/base_alloc/base_alloc.c @@ -168,7 +168,8 @@ umf_ba_pool_t *umf_ba_create(size_t size) { char *data_ptr = (char *)&pool->data; size_t size_left = pool_size - offsetof(umf_ba_pool_t, data); - utils_align_ptr_size((void **)&data_ptr, &size_left, MEMORY_ALIGNMENT); + utils_align_ptr_up_size_down((void **)&data_ptr, &size_left, + MEMORY_ALIGNMENT); // init free_lock utils_mutex_t *mutex = utils_mutex_init(&pool->metadata.free_lock); @@ -209,7 +210,8 @@ void *umf_ba_alloc(umf_ba_pool_t *pool) { size_t size_left = pool->metadata.pool_size - offsetof(umf_ba_next_pool_t, data); - utils_align_ptr_size((void **)&data_ptr, &size_left, MEMORY_ALIGNMENT); + utils_align_ptr_up_size_down((void **)&data_ptr, &size_left, + MEMORY_ALIGNMENT); ba_divide_memory_into_chunks(pool, data_ptr, size_left); } diff --git a/src/base_alloc/base_alloc_linear.c b/src/base_alloc/base_alloc_linear.c index de4ac0b1e..8773e5cab 100644 --- a/src/base_alloc/base_alloc_linear.c +++ b/src/base_alloc/base_alloc_linear.c @@ -98,7 +98,7 @@ umf_ba_linear_pool_t *umf_ba_linear_create(size_t pool_size) { void *data_ptr = &pool->data; size_t size_left = pool_size - offsetof(umf_ba_linear_pool_t, data); - utils_align_ptr_size(&data_ptr, &size_left, MEMORY_ALIGNMENT); + utils_align_ptr_up_size_down(&data_ptr, &size_left, MEMORY_ALIGNMENT); pool->metadata.pool_size = pool_size; pool->metadata.data_ptr = data_ptr; @@ -149,7 +149,7 @@ void *umf_ba_linear_alloc(umf_ba_linear_pool_t *pool, size_t size) { void *data_ptr = &new_pool->data; size_t size_left = new_pool->pool_size - offsetof(umf_ba_next_linear_pool_t, data); - utils_align_ptr_size(&data_ptr, &size_left, MEMORY_ALIGNMENT); + utils_align_ptr_up_size_down(&data_ptr, &size_left, MEMORY_ALIGNMENT); pool->metadata.data_ptr = data_ptr; pool->metadata.size_left = size_left; diff --git a/src/utils/utils_common.c b/src/utils/utils_common.c index cf1a953df..1c62dcba9 100644 --- a/src/utils/utils_common.c +++ b/src/utils/utils_common.c @@ -12,8 +12,8 @@ #include "utils_assert.h" #include "utils_common.h" -// align a pointer and a size -void utils_align_ptr_size(void **ptr, size_t *size, size_t alignment) { +// align a pointer up and a size down +void utils_align_ptr_up_size_down(void **ptr, size_t *size, size_t alignment) { uintptr_t p = (uintptr_t)*ptr; size_t s = *size; diff --git a/src/utils/utils_common.h b/src/utils/utils_common.h index e5fea27e7..924a0ec77 100644 --- a/src/utils/utils_common.h +++ b/src/utils/utils_common.h @@ -82,8 +82,8 @@ int utils_is_running_in_proxy_lib(void); size_t utils_get_page_size(void); -// align a pointer and a size -void utils_align_ptr_size(void **ptr, size_t *size, size_t alignment); +// align a pointer up and a size down +void utils_align_ptr_up_size_down(void **ptr, size_t *size, size_t alignment); // get the current process ID int utils_getpid(void); From d182403d01294541c33c78f377b5eafcf2e51e75 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Fri, 25 Oct 2024 10:01:23 +0200 Subject: [PATCH 228/352] Add utils_align_ptr_down_size_up() Add utils_align_ptr_down_size_up() to align a pointer down and a size up (for mmap()/munmap()). Signed-off-by: Lukasz Dorau --- src/utils/utils_common.c | 30 ++++++++++++++++++++++++++---- src/utils/utils_common.h | 3 +++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/utils/utils_common.c b/src/utils/utils_common.c index 1c62dcba9..25169f6cf 100644 --- a/src/utils/utils_common.c +++ b/src/utils/utils_common.c @@ -17,15 +17,37 @@ void utils_align_ptr_up_size_down(void **ptr, size_t *size, size_t alignment) { uintptr_t p = (uintptr_t)*ptr; size_t s = *size; - // align pointer to 'alignment' bytes and adjust the size + // align the pointer up to 'alignment' bytes and adjust the size down size_t rest = p & (alignment - 1); if (rest) { - p += alignment - rest; + p = ALIGN_UP(p, alignment); s -= alignment - rest; } - ASSERT((p & (alignment - 1)) == 0); - ASSERT((s & (alignment - 1)) == 0); + ASSERT(IS_ALIGNED(p, alignment)); + ASSERT(IS_ALIGNED(s, alignment)); + + *ptr = (void *)p; + *size = s; +} + +// align a pointer down and a size up (for mmap()/munmap()) +void utils_align_ptr_down_size_up(void **ptr, size_t *size, size_t alignment) { + uintptr_t p = (uintptr_t)*ptr; + size_t s = *size; + + // align the pointer down to 'alignment' bytes and adjust the size up + size_t rest = p & (alignment - 1); + if (rest) { + p = ALIGN_DOWN(p, alignment); + s += rest; + } + + // align the size up to 'alignment' bytes + s = ALIGN_UP(s, alignment); + + ASSERT(IS_ALIGNED(p, alignment)); + ASSERT(IS_ALIGNED(s, alignment)); *ptr = (void *)p; *size = s; diff --git a/src/utils/utils_common.h b/src/utils/utils_common.h index 924a0ec77..25a840d97 100644 --- a/src/utils/utils_common.h +++ b/src/utils/utils_common.h @@ -85,6 +85,9 @@ size_t utils_get_page_size(void); // align a pointer up and a size down void utils_align_ptr_up_size_down(void **ptr, size_t *size, size_t alignment); +// align a pointer down and a size up (for mmap()/munmap()) +void utils_align_ptr_down_size_up(void **ptr, size_t *size, size_t alignment); + // get the current process ID int utils_getpid(void); From 454fcd99e02df41a18c09d42bd3f36688f12bd7c Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 28 Oct 2024 17:06:40 +0100 Subject: [PATCH 229/352] The default page size for the devdax mode is 2 MB Signed-off-by: Lukasz Dorau --- src/provider/provider_devdax_memory.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/provider/provider_devdax_memory.c b/src/provider/provider_devdax_memory.c index 544960995..74ed05d1a 100644 --- a/src/provider/provider_devdax_memory.c +++ b/src/provider/provider_devdax_memory.c @@ -31,7 +31,7 @@ umf_memory_provider_ops_t *umfDevDaxMemoryProviderOps(void) { #include "utils_concurrency.h" #include "utils_log.h" -#define NODESET_STR_BUF_LEN 1024 +#define DEVDAX_PAGE_SIZE_2MB ((size_t)(2 * 1024 * 1024)) // == 2 MB #define TLS_MSG_BUF_LEN 1024 @@ -300,7 +300,7 @@ static umf_result_t devdax_get_recommended_page_size(void *provider, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - *page_size = utils_get_page_size(); + *page_size = DEVDAX_PAGE_SIZE_2MB; return UMF_RESULT_SUCCESS; } From a677109552f72d6325cdb6f433f0f5f3f312449c Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Tue, 29 Oct 2024 14:22:53 +0100 Subject: [PATCH 230/352] Fix handling arguments of devdax_alloc() Fix handling arguments of devdax_alloc(): - alignment has to be a power of 2 and a divider or a multiple of the page size (2MB), Signed-off-by: Lukasz Dorau --- src/provider/provider_devdax_memory.c | 17 +++++++++++------ test/provider_devdax_memory.cpp | 20 +++++++++++++------- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/provider/provider_devdax_memory.c b/src/provider/provider_devdax_memory.c index 74ed05d1a..0b21d66c8 100644 --- a/src/provider/provider_devdax_memory.c +++ b/src/provider/provider_devdax_memory.c @@ -228,15 +228,20 @@ static umf_result_t devdax_alloc(void *provider, size_t size, size_t alignment, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - // alignment must be a power of two and a multiple of sizeof(void *) - if (alignment && - ((alignment & (alignment - 1)) || (alignment % sizeof(void *)))) { - LOG_ERR("wrong alignment: %zu (not a power of 2 or a multiple of " - "sizeof(void *))", - alignment); + // alignment must be a power of two and a multiple or a divider of the page size + if (alignment && ((alignment & (alignment - 1)) || + ((alignment % DEVDAX_PAGE_SIZE_2MB) && + (DEVDAX_PAGE_SIZE_2MB % alignment)))) { + LOG_ERR("wrong alignment: %zu (not a power of 2 or a multiple or a " + "divider of the page size (%zu))", + alignment, DEVDAX_PAGE_SIZE_2MB); return UMF_RESULT_ERROR_INVALID_ARGUMENT; } + if (IS_NOT_ALIGNED(alignment, DEVDAX_PAGE_SIZE_2MB)) { + alignment = ALIGN_UP(alignment, DEVDAX_PAGE_SIZE_2MB); + } + devdax_memory_provider_t *devdax_provider = (devdax_memory_provider_t *)provider; diff --git a/test/provider_devdax_memory.cpp b/test/provider_devdax_memory.cpp index 6ed5f241e..091cda7d3 100644 --- a/test/provider_devdax_memory.cpp +++ b/test/provider_devdax_memory.cpp @@ -190,25 +190,30 @@ INSTANTIATE_TEST_SUITE_P(devdaxProviderTest, umfProviderTest, TEST_P(umfProviderTest, create_destroy) {} -TEST_P(umfProviderTest, alloc_page64_align_0) { - test_alloc_free_success(provider.get(), page_plus_64, 0, PURGE_NONE); +TEST_P(umfProviderTest, alloc_page_align_0) { + test_alloc_free_success(provider.get(), page_size, 0, PURGE_NONE); } -TEST_P(umfProviderTest, alloc_page64_align_page_div_2) { - test_alloc_free_success(provider.get(), page_plus_64, page_size / 2, +TEST_P(umfProviderTest, alloc_2page_align_page_size) { + test_alloc_free_success(provider.get(), 2 * page_size, page_size, PURGE_NONE); } TEST_P(umfProviderTest, purge_lazy) { - test_alloc_free_success(provider.get(), page_plus_64, 0, PURGE_LAZY); + test_alloc_free_success(provider.get(), page_size, 0, PURGE_LAZY); } TEST_P(umfProviderTest, purge_force) { - test_alloc_free_success(provider.get(), page_plus_64, 0, PURGE_FORCE); + test_alloc_free_success(provider.get(), page_size, 0, PURGE_FORCE); } // negative tests using test_alloc_failure +TEST_P(umfProviderTest, alloc_page64_align_page_div_2) { + test_alloc_failure(provider.get(), page_plus_64, page_size / 2, + UMF_RESULT_ERROR_INVALID_ARGUMENT, 0); +} + TEST_P(umfProviderTest, alloc_page64_align_page_minus_1_WRONG_ALIGNMENT_1) { test_alloc_failure(provider.get(), page_plus_64, page_size - 1, UMF_RESULT_ERROR_INVALID_ARGUMENT, 0); @@ -231,7 +236,8 @@ TEST_P(umfProviderTest, alloc_3_pages_WRONG_ALIGNMENT_3_pages) { } TEST_P(umfProviderTest, alloc_WRONG_SIZE) { - test_alloc_failure(provider.get(), -1, 0, + size_t size = (size_t)(-1) & ~(page_size - 1); + test_alloc_failure(provider.get(), size, 0, UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC, UMF_DEVDAX_RESULT_ERROR_ALLOC_FAILED); } From 74b91bb0ac5401a838e0ee92c831d70ebb3e00dc Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Thu, 31 Oct 2024 14:19:32 +0100 Subject: [PATCH 231/352] Fix devdax_open_ipc_handle() and devdax_close_ipc_handle() devdax_open_ipc_handle() has to use the path of the remote /dev/dax got from the IPC handle, not the local one. devdax_open_ipc_handle() has to use also the memory protection got from the IPC handle, so let's add the memory protection to the IPC handle. devdax_open_ipc_handle() should mmap only the required range of memory, not the whole /dev/dax device, so let's add the length of the allocation to the IPC handle. devdax_close_ipc_handle() should unmap only the required range of memory, not the whole /dev/dax device. Fixes: #846 Signed-off-by: Lukasz Dorau --- src/provider/provider_devdax_memory.c | 97 ++++++++++++--------------- test/provider_devdax_memory.cpp | 10 +-- 2 files changed, 48 insertions(+), 59 deletions(-) diff --git a/src/provider/provider_devdax_memory.c b/src/provider/provider_devdax_memory.c index 0b21d66c8..7751eb463 100644 --- a/src/provider/provider_devdax_memory.c +++ b/src/provider/provider_devdax_memory.c @@ -374,9 +374,11 @@ static umf_result_t devdax_allocation_merge(void *provider, void *lowPtr, } typedef struct devdax_ipc_data_t { - char dd_path[PATH_MAX]; // path to the /dev/dax - size_t dd_size; // size of the /dev/dax - size_t offset; // offset of the data + char path[PATH_MAX]; // path to the /dev/dax + unsigned protection; // combination of OS-specific memory protection flags + // offset of the data (from the beginning of the devdax mapping) - see devdax_get_ipc_handle() + size_t offset; + size_t length; // length of the data } devdax_ipc_data_t; static umf_result_t devdax_get_ipc_handle_size(void *provider, size_t *size) { @@ -391,8 +393,6 @@ static umf_result_t devdax_get_ipc_handle_size(void *provider, size_t *size) { static umf_result_t devdax_get_ipc_handle(void *provider, const void *ptr, size_t size, void *providerIpcData) { - (void)size; // unused - if (provider == NULL || ptr == NULL || providerIpcData == NULL) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; } @@ -401,11 +401,12 @@ static umf_result_t devdax_get_ipc_handle(void *provider, const void *ptr, (devdax_memory_provider_t *)provider; devdax_ipc_data_t *devdax_ipc_data = (devdax_ipc_data_t *)providerIpcData; + strncpy(devdax_ipc_data->path, devdax_provider->path, PATH_MAX - 1); + devdax_ipc_data->path[PATH_MAX - 1] = '\0'; + devdax_ipc_data->protection = devdax_provider->protection; devdax_ipc_data->offset = (size_t)((uintptr_t)ptr - (uintptr_t)devdax_provider->base); - strncpy(devdax_ipc_data->dd_path, devdax_provider->path, PATH_MAX - 1); - devdax_ipc_data->dd_path[PATH_MAX - 1] = '\0'; - devdax_ipc_data->dd_size = devdax_provider->size; + devdax_ipc_data->length = size; return UMF_RESULT_SUCCESS; } @@ -421,16 +422,9 @@ static umf_result_t devdax_put_ipc_handle(void *provider, devdax_ipc_data_t *devdax_ipc_data = (devdax_ipc_data_t *)providerIpcData; // verify the path of the /dev/dax - if (strncmp(devdax_ipc_data->dd_path, devdax_provider->path, PATH_MAX)) { + if (strncmp(devdax_ipc_data->path, devdax_provider->path, PATH_MAX)) { LOG_ERR("devdax path mismatch (local: %s, ipc: %s)", - devdax_provider->path, devdax_ipc_data->dd_path); - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - - // verify the size of the /dev/dax - if (devdax_ipc_data->dd_size != devdax_provider->size) { - LOG_ERR("devdax size mismatch (local: %zu, ipc: %zu)", - devdax_provider->size, devdax_ipc_data->dd_size); + devdax_provider->path, devdax_ipc_data->path); return UMF_RESULT_ERROR_INVALID_ARGUMENT; } @@ -443,58 +437,54 @@ static umf_result_t devdax_open_ipc_handle(void *provider, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - devdax_memory_provider_t *devdax_provider = - (devdax_memory_provider_t *)provider; devdax_ipc_data_t *devdax_ipc_data = (devdax_ipc_data_t *)providerIpcData; - // verify it is the same devdax - first verify the path - if (strncmp(devdax_ipc_data->dd_path, devdax_provider->path, PATH_MAX)) { - LOG_ERR("devdax path mismatch (local: %s, ipc: %s)", - devdax_provider->path, devdax_ipc_data->dd_path); - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - - // verify the size of the /dev/dax - if (devdax_ipc_data->dd_size != devdax_provider->size) { - LOG_ERR("devdax size mismatch (local: %zu, ipc: %zu)", - devdax_provider->size, devdax_ipc_data->dd_size); - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - - umf_result_t ret = UMF_RESULT_SUCCESS; - int fd = utils_devdax_open(devdax_provider->path); + int fd = utils_devdax_open(devdax_ipc_data->path); if (fd == -1) { - LOG_PERR("opening a devdax (%s) failed", devdax_provider->path); + LOG_PERR("opening the devdax (%s) failed", devdax_ipc_data->path); return UMF_RESULT_ERROR_INVALID_ARGUMENT; } unsigned map_sync_flag = 0; utils_translate_mem_visibility_flag(UMF_MEM_MAP_SYNC, &map_sync_flag); + // It is just a workaround for case when + // devdax_alloc() was called with the size argument + // that is not a multiplier of DEVDAX_PAGE_SIZE_2MB. + size_t offset_aligned = devdax_ipc_data->offset; + size_t length_aligned = devdax_ipc_data->length; + utils_align_ptr_down_size_up((void **)&offset_aligned, &length_aligned, + DEVDAX_PAGE_SIZE_2MB); + // mmap /dev/dax with the MAP_SYNC xor MAP_SHARED flag (if MAP_SYNC fails) - char *base = utils_mmap_file(NULL, devdax_provider->size, - devdax_provider->protection, map_sync_flag, fd, - 0 /* offset */); - if (base == NULL) { + char *addr = + utils_mmap_file(NULL, length_aligned, devdax_ipc_data->protection, + map_sync_flag, fd, offset_aligned); + if (addr == NULL) { devdax_store_last_native_error(UMF_DEVDAX_RESULT_ERROR_ALLOC_FAILED, errno); + LOG_PERR("devdax mapping failed (path: %s, size: %zu, protection: %i, " - "fd: %i)", - devdax_provider->path, devdax_provider->size, - devdax_provider->protection, fd); - ret = UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; + "fd: %i, offset: %zu)", + devdax_ipc_data->path, length_aligned, + devdax_ipc_data->protection, fd, offset_aligned); + + *ptr = NULL; + (void)utils_close_fd(fd); + + return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; } LOG_DEBUG("devdax mapped (path: %s, size: %zu, protection: %i, fd: %i, " - "offset: %zu)", - devdax_provider->path, devdax_provider->size, - devdax_provider->protection, fd, devdax_ipc_data->offset); + "offset: %zu) to address %p", + devdax_ipc_data->path, length_aligned, + devdax_ipc_data->protection, fd, offset_aligned, addr); - (void)utils_close_fd(fd); + *ptr = addr; - *ptr = base + devdax_ipc_data->offset; + (void)utils_close_fd(fd); - return ret; + return UMF_RESULT_SUCCESS; } static umf_result_t devdax_close_ipc_handle(void *provider, void *ptr, @@ -503,16 +493,15 @@ static umf_result_t devdax_close_ipc_handle(void *provider, void *ptr, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - devdax_memory_provider_t *devdax_provider = - (devdax_memory_provider_t *)provider; + size = ALIGN_UP(size, DEVDAX_PAGE_SIZE_2MB); errno = 0; - int ret = utils_munmap(devdax_provider->base, devdax_provider->size); + int ret = utils_munmap(ptr, size); // ignore error when size == 0 if (ret && (size > 0)) { devdax_store_last_native_error(UMF_DEVDAX_RESULT_ERROR_FREE_FAILED, errno); - LOG_PERR("memory unmapping failed"); + LOG_PERR("memory unmapping failed (ptr: %p, size: %zu)", ptr, size); return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; } diff --git a/test/provider_devdax_memory.cpp b/test/provider_devdax_memory.cpp index 091cda7d3..bec11ffb7 100644 --- a/test/provider_devdax_memory.cpp +++ b/test/provider_devdax_memory.cpp @@ -199,6 +199,11 @@ TEST_P(umfProviderTest, alloc_2page_align_page_size) { PURGE_NONE); } +TEST_P(umfProviderTest, alloc_page64_align_page_div_2) { + test_alloc_free_success(provider.get(), page_plus_64, page_size / 2, + PURGE_NONE); +} + TEST_P(umfProviderTest, purge_lazy) { test_alloc_free_success(provider.get(), page_size, 0, PURGE_LAZY); } @@ -209,11 +214,6 @@ TEST_P(umfProviderTest, purge_force) { // negative tests using test_alloc_failure -TEST_P(umfProviderTest, alloc_page64_align_page_div_2) { - test_alloc_failure(provider.get(), page_plus_64, page_size / 2, - UMF_RESULT_ERROR_INVALID_ARGUMENT, 0); -} - TEST_P(umfProviderTest, alloc_page64_align_page_minus_1_WRONG_ALIGNMENT_1) { test_alloc_failure(provider.get(), page_plus_64, page_size - 1, UMF_RESULT_ERROR_INVALID_ARGUMENT, 0); From ff242b7746421f6979074fbb2894ef7e9f2724e6 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 28 Oct 2024 12:09:21 +0100 Subject: [PATCH 232/352] Make error messages in utils_mmap_file() more verbose Signed-off-by: Lukasz Dorau --- src/utils/utils_linux_common.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/utils/utils_linux_common.c b/src/utils/utils_linux_common.c index 7f7d55c6f..1a44a2b64 100644 --- a/src/utils/utils_linux_common.c +++ b/src/utils/utils_linux_common.c @@ -56,7 +56,9 @@ void *utils_mmap_file(void *hint_addr, size_t length, int prot, int flags, if (flags & MAP_PRIVATE) { addr = utils_mmap(hint_addr, length, prot, flags, fd, fd_offset); if (addr == MAP_FAILED) { - LOG_PERR("mapping file with the MAP_PRIVATE flag failed"); + LOG_PERR("mapping file with the MAP_PRIVATE flag failed (fd=%i, " + "offset=%zu, length=%zu)", + fd, fd_offset, length); return NULL; } @@ -81,7 +83,9 @@ void *utils_mmap_file(void *hint_addr, size_t length, int prot, int flags, return addr; } - LOG_PERR("mapping file with the MAP_SYNC flag failed"); + LOG_PERR("mapping file with the MAP_SYNC flag failed (fd=%i, " + "offset=%zu, length=%zu)", + fd, fd_offset, length); } if ((!(flags & MAP_SYNC)) || errno == EINVAL || errno == ENOTSUP || @@ -96,7 +100,9 @@ void *utils_mmap_file(void *hint_addr, size_t length, int prot, int flags, return addr; } - LOG_PERR("mapping file with the MAP_SHARED flag failed"); + LOG_PERR("mapping file with the MAP_SHARED flag failed (fd=%i, " + "offset=%zu, length=%zu)", + fd, fd_offset, length); } return NULL; From 32df3128a6a33dd008182c807c426b15800d5a9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Staniewski?= Date: Thu, 31 Oct 2024 15:35:27 +0000 Subject: [PATCH 233/352] Add tests for utils_common_linux --- test/CMakeLists.txt | 7 +++++ test/utils/utils_linux.cpp | 53 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 test/utils/utils_linux.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8450f049f..a48c88c32 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -152,6 +152,13 @@ add_umf_test( SRCS utils/utils.cpp LIBS ${UMF_UTILS_FOR_TEST}) +if(LINUX) + add_umf_test( + NAME utils_linux_common + SRCS utils/utils_linux.cpp + LIBS ${UMF_UTILS_FOR_TEST}) +endif() + add_umf_test(NAME provider_coarse SRCS provider_coarse.cpp) if(UMF_BUILD_LIBUMF_POOL_DISJOINT) diff --git a/test/utils/utils_linux.cpp b/test/utils/utils_linux.cpp new file mode 100644 index 000000000..f88e9daf2 --- /dev/null +++ b/test/utils/utils_linux.cpp @@ -0,0 +1,53 @@ +// Copyright (C) 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 "base.hpp" +#include "utils/utils_common.h" + +using umf_test::test; +TEST_F(test, utils_translate_mem_visibility_flag) { + umf_memory_visibility_t in_flag = static_cast(0); + unsigned out_flag; + auto ret = utils_translate_mem_visibility_flag(in_flag, &out_flag); + EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} + +TEST_F(test, utils_shm_open_invalid_args) { + auto ret = utils_shm_open(NULL); + EXPECT_EQ(ret, -1); + + ret = utils_shm_open("invalid_path"); + EXPECT_EQ(ret, -1); +} + +TEST_F(test, utils_get_file_size_invalid_args) { + size_t size; + auto ret = utils_get_file_size(-1, &size); + EXPECT_EQ(ret, -1); + + int fd = utils_create_anonymous_fd(); + ret = utils_get_file_size(fd, &size); + EXPECT_EQ(ret, 0); + EXPECT_EQ(size, 0); +} + +TEST_F(test, utils_set_file_size_invalid_args) { + auto ret = utils_set_file_size(-1, 256); + EXPECT_EQ(ret, -1); +} + +TEST_F(test, utils_shm_create_invalid_args) { + auto ret = utils_shm_create(NULL, 0); + EXPECT_EQ(ret, -1); + + ret = utils_shm_create("", 256); + EXPECT_EQ(ret, -1); + + // Ensure that a valid size results in a success + ret = utils_shm_create("/abc", 256); + EXPECT_GE(ret, 0); + + ret = utils_shm_create("/abc", -1); + EXPECT_EQ(ret, -1); +} From fa08100d69407811ce2f52ea571a8baed6aef5b8 Mon Sep 17 00:00:00 2001 From: Rafal Rudnicki Date: Sat, 19 Oct 2024 16:47:56 +0200 Subject: [PATCH 234/352] add logging in utils_get_symbol_addr --- src/utils/utils_load_library.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/utils/utils_load_library.c b/src/utils/utils_load_library.c index 2c13acc8d..cbe7be445 100644 --- a/src/utils/utils_load_library.c +++ b/src/utils/utils_load_library.c @@ -16,15 +16,18 @@ #include // clang-format on -#else +#else // _WIN32 #define _GNU_SOURCE 1 #include // forces linking with libdl on Linux -#endif +#endif // !_WIN32 + +#include #include "utils_load_library.h" +#include "utils_log.h" #ifdef _WIN32 @@ -47,7 +50,13 @@ void *utils_get_symbol_addr(void *handle, const char *symbol, } handle = GetModuleHandle(libname); } - return (void *)GetProcAddress((HMODULE)handle, symbol); + + void *addr = (void *)GetProcAddress((HMODULE)handle, symbol); + if (addr == NULL) { + LOG_ERR("Required symbol not found: %s", symbol); + } + + return addr; } #else /* Linux */ @@ -68,7 +77,13 @@ void *utils_get_symbol_addr(void *handle, const char *symbol, if (!handle) { handle = RTLD_DEFAULT; } - return dlsym(handle, symbol); + + void *addr = dlsym(handle, symbol); + if (addr == NULL) { + LOG_ERR("Required symbol not found: %s", symbol); + } + + return addr; } #endif From ed0332a66cc1b844a9d3297c47187906d9cafe8f Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 28 Oct 2024 11:01:00 +0100 Subject: [PATCH 235/352] Enable running umfIpcTest tests when free() is not supported Some memory providers (currently the devdax and the file providers) do not support the free() operation (free() always returns the UMF_RESULT_ERROR_NOT_SUPPORTED error). Add the `free_not_supp` parameter to `ipcTestParams` in ipcFixtures.hpp that says if the provider does not support the free() op to enable running umfIpcTest tests when free() is not supported. Signed-off-by: Lukasz Dorau --- test/ipcAPI.cpp | 2 +- test/ipcFixtures.hpp | 44 +++++++++++++++++++++++++++---------- test/provider_os_memory.cpp | 2 +- 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/test/ipcAPI.cpp b/test/ipcAPI.cpp index 8f8448b62..8455af15b 100644 --- a/test/ipcAPI.cpp +++ b/test/ipcAPI.cpp @@ -116,4 +116,4 @@ HostMemoryAccessor hostMemoryAccessor; INSTANTIATE_TEST_SUITE_P(umfIpcTestSuite, umfIpcTest, ::testing::Values(ipcTestParams{ umfProxyPoolOps(), nullptr, &IPC_MOCK_PROVIDER_OPS, - nullptr, &hostMemoryAccessor})); + nullptr, &hostMemoryAccessor, false})); diff --git a/test/ipcFixtures.hpp b/test/ipcFixtures.hpp index 8b99026ab..987596b1b 100644 --- a/test/ipcFixtures.hpp +++ b/test/ipcFixtures.hpp @@ -46,22 +46,26 @@ class HostMemoryAccessor : public MemoryAccessor { } }; +// ipcTestParams: +// pool_ops, pool_params, provider_ops, provider_params, memoryAccessor, free_not_supp +// free_not_supp (bool) - provider does not support the free() op using ipcTestParams = std::tuple; + void *, MemoryAccessor *, bool>; struct umfIpcTest : umf_test::test, ::testing::WithParamInterface { umfIpcTest() {} void SetUp() override { test::SetUp(); - auto [pool_ops, pool_params, provider_ops, provider_params, accessor] = - this->GetParam(); + auto [pool_ops, pool_params, provider_ops, provider_params, accessor, + free_not_supp] = this->GetParam(); poolOps = pool_ops; poolParams = pool_params; providerOps = provider_ops; providerParams = provider_params; memAccessor = accessor; + freeNotSupported = free_not_supp; } void TearDown() override { test::TearDown(); } @@ -120,8 +124,18 @@ struct umfIpcTest : umf_test::test, void *poolParams = nullptr; umf_memory_provider_ops_t *providerOps = nullptr; void *providerParams = nullptr; + bool freeNotSupported = false; }; +static inline umf_result_t +get_umf_result_of_free(bool freeNotSupported, umf_result_t expected_result) { + if (freeNotSupported) { + return UMF_RESULT_ERROR_NOT_SUPPORTED; + } + + return expected_result; +} + TEST_P(umfIpcTest, GetIPCHandleSize) { size_t size = 0; umf::pool_unique_handle_t pool = makePool(); @@ -163,7 +177,8 @@ TEST_P(umfIpcTest, GetIPCHandleInvalidArgs) { EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); ret = umfFree(ptr); - EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + EXPECT_EQ(ret, + get_umf_result_of_free(freeNotSupported, UMF_RESULT_SUCCESS)); } TEST_P(umfIpcTest, BasicFlow) { @@ -218,7 +233,8 @@ TEST_P(umfIpcTest, BasicFlow) { EXPECT_EQ(ret, UMF_RESULT_SUCCESS); ret = umfPoolFree(pool.get(), ptr); - EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + EXPECT_EQ(ret, + get_umf_result_of_free(freeNotSupported, UMF_RESULT_SUCCESS)); pool.reset(nullptr); EXPECT_EQ(stat.getCount, 1); @@ -282,7 +298,8 @@ TEST_P(umfIpcTest, GetPoolByOpenedHandle) { for (size_t i = 0; i < NUM_ALLOCS; ++i) { umf_result_t ret = umfFree(ptrs[i]); - EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + EXPECT_EQ(ret, + get_umf_result_of_free(freeNotSupported, UMF_RESULT_SUCCESS)); } } @@ -308,7 +325,8 @@ TEST_P(umfIpcTest, AllocFreeAllocTest) { EXPECT_EQ(ret, UMF_RESULT_SUCCESS); ret = umfPoolFree(pool.get(), ptr); - EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + EXPECT_EQ(ret, + get_umf_result_of_free(freeNotSupported, UMF_RESULT_SUCCESS)); ptr = umfPoolMalloc(pool.get(), SIZE); ASSERT_NE(ptr, nullptr); @@ -330,7 +348,8 @@ TEST_P(umfIpcTest, AllocFreeAllocTest) { EXPECT_EQ(ret, UMF_RESULT_SUCCESS); ret = umfPoolFree(pool.get(), ptr); - EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + EXPECT_EQ(ret, + get_umf_result_of_free(freeNotSupported, UMF_RESULT_SUCCESS)); pool.reset(nullptr); EXPECT_EQ(stat.allocCount, stat.getCount); @@ -382,7 +401,8 @@ TEST_P(umfIpcTest, openInTwoPools) { EXPECT_EQ(ret, UMF_RESULT_SUCCESS); ret = umfPoolFree(pool1.get(), ptr); - EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + EXPECT_EQ(ret, + get_umf_result_of_free(freeNotSupported, UMF_RESULT_SUCCESS)); pool1.reset(nullptr); pool2.reset(nullptr); @@ -433,7 +453,8 @@ TEST_P(umfIpcTest, ConcurrentGetPutHandles) { for (void *ptr : ptrs) { umf_result_t ret = umfPoolFree(pool.get(), ptr); - EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + EXPECT_EQ(ret, + get_umf_result_of_free(freeNotSupported, UMF_RESULT_SUCCESS)); } pool.reset(nullptr); @@ -495,7 +516,8 @@ TEST_P(umfIpcTest, ConcurrentOpenCloseHandles) { for (void *ptr : ptrs) { umf_result_t ret = umfPoolFree(pool.get(), ptr); - EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + EXPECT_EQ(ret, + get_umf_result_of_free(freeNotSupported, UMF_RESULT_SUCCESS)); } pool.reset(nullptr); diff --git a/test/provider_os_memory.cpp b/test/provider_os_memory.cpp index a14f50f57..734ebeec9 100644 --- a/test/provider_os_memory.cpp +++ b/test/provider_os_memory.cpp @@ -387,7 +387,7 @@ umf_disjoint_pool_params_t disjointParams = disjointPoolParams(); static std::vector ipcTestParamsList = { #if (defined UMF_POOL_DISJOINT_ENABLED) {umfDisjointPoolOps(), &disjointParams, umfOsMemoryProviderOps(), - &os_params, &hostAccessor}, + &os_params, &hostAccessor, false}, #endif }; From 486b3e40d413d09fc0c4d2b400f9a3004c84402d Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 4 Nov 2024 15:47:01 +0100 Subject: [PATCH 236/352] Add IPC tests (umfIpcTest) to the devdax provider Signed-off-by: Lukasz Dorau --- test/CMakeLists.txt | 16 ++++++++- test/ipcFixtures.hpp | 6 ++-- test/provider_devdax_memory.cpp | 50 ++++++++++++++++++++++++-- test/providers/provider_level_zero.cpp | 2 +- 4 files changed, 68 insertions(+), 6 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6fefe90cb..2817651f7 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -56,6 +56,16 @@ function(build_umf_test) SRCS ${ARG_SRCS} LIBS ${TEST_LIBS}) + if(UMF_POOL_JEMALLOC_ENABLED) + target_compile_definitions(${TEST_TARGET_NAME} + PRIVATE UMF_POOL_JEMALLOC_ENABLED=1) + endif() + + if(UMF_POOL_SCALABLE_ENABLED) + target_compile_definitions(${TEST_TARGET_NAME} + PRIVATE UMF_POOL_SCALABLE_ENABLED=1) + endif() + if(NOT MSVC) # Suppress 'cast discards const qualifier' warnings. Parametrized GTEST # tests retrieve arguments using 'GetParam()', which applies a 'const' @@ -136,6 +146,10 @@ if(UMF_BUILD_SHARED_LIBRARY) endif() endif() +if(UMF_POOL_JEMALLOC_ENABLED) + set(LIB_JEMALLOC_POOL jemalloc_pool) +endif() + add_umf_test(NAME base SRCS base.cpp) add_umf_test( NAME memoryPool @@ -253,7 +267,7 @@ if(LINUX AND (NOT UMF_DISABLE_HWLOC)) # OS-specific functions are implemented add_umf_test( NAME provider_devdax_memory SRCS provider_devdax_memory.cpp - LIBS ${UMF_UTILS_FOR_TEST}) + LIBS ${UMF_UTILS_FOR_TEST} ${LIB_JEMALLOC_POOL}) add_umf_test( NAME provider_file_memory SRCS provider_file_memory.cpp diff --git a/test/ipcFixtures.hpp b/test/ipcFixtures.hpp index 987596b1b..2def86787 100644 --- a/test/ipcFixtures.hpp +++ b/test/ipcFixtures.hpp @@ -352,9 +352,11 @@ TEST_P(umfIpcTest, AllocFreeAllocTest) { get_umf_result_of_free(freeNotSupported, UMF_RESULT_SUCCESS)); pool.reset(nullptr); - EXPECT_EQ(stat.allocCount, stat.getCount); + // TODO fix it - it does not work in case of IPC cache hit + // EXPECT_EQ(stat.allocCount, stat.getCount); EXPECT_EQ(stat.getCount, stat.putCount); - EXPECT_EQ(stat.openCount, stat.getCount); + // TODO fix it - it does not work in case of IPC cache hit + // EXPECT_EQ(stat.openCount, stat.getCount); EXPECT_EQ(stat.openCount, stat.closeCount); } diff --git a/test/provider_devdax_memory.cpp b/test/provider_devdax_memory.cpp index bec11ffb7..dba8efff7 100644 --- a/test/provider_devdax_memory.cpp +++ b/test/provider_devdax_memory.cpp @@ -12,10 +12,17 @@ #include "base.hpp" #include "cpp_helpers.hpp" +#include "ipcFixtures.hpp" #include "test_helpers.h" #include #include +#ifdef UMF_POOL_JEMALLOC_ENABLED +#include +#endif +#ifdef UMF_POOL_SCALABLE_ENABLED +#include +#endif using umf_test::test; @@ -179,14 +186,15 @@ TEST_F(test, test_if_mapped_with_MAP_SYNC) { // positive tests using test_alloc_free_success -auto defaultParams = umfDevDaxMemoryProviderParamsDefault( +auto defaultDevDaxParams = umfDevDaxMemoryProviderParamsDefault( getenv("UMF_TESTS_DEVDAX_PATH"), atol(getenv("UMF_TESTS_DEVDAX_SIZE") ? getenv("UMF_TESTS_DEVDAX_SIZE") : "0")); INSTANTIATE_TEST_SUITE_P(devdaxProviderTest, umfProviderTest, ::testing::Values(providerCreateExtParams{ - umfDevDaxMemoryProviderOps(), &defaultParams})); + umfDevDaxMemoryProviderOps(), + &defaultDevDaxParams})); TEST_P(umfProviderTest, create_destroy) {} @@ -349,3 +357,41 @@ TEST_F(test, create_wrong_size_0) { EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); EXPECT_EQ(hProvider, nullptr); } + +HostMemoryAccessor hostAccessor; + +static std::vector getIpcProxyPoolTestParamsList(void) { + std::vector ipcProxyPoolTestParamsList = {}; + + char *path = getenv("UMF_TESTS_DEVDAX_PATH"); + if (path == nullptr || path[0] == 0) { + // Test skipped, UMF_TESTS_DEVDAX_PATH is not set + return ipcProxyPoolTestParamsList; + } + + char *size = getenv("UMF_TESTS_DEVDAX_SIZE"); + if (size == nullptr || size[0] == 0) { + // Test skipped, UMF_TESTS_DEVDAX_PATH is not set + return ipcProxyPoolTestParamsList; + } + + ipcProxyPoolTestParamsList = { + {umfProxyPoolOps(), nullptr, umfDevDaxMemoryProviderOps(), + &defaultDevDaxParams, &hostAccessor, true}, +#ifdef UMF_POOL_JEMALLOC_ENABLED + {umfJemallocPoolOps(), nullptr, umfDevDaxMemoryProviderOps(), + &defaultDevDaxParams, &hostAccessor, false}, +#endif +#ifdef UMF_POOL_SCALABLE_ENABLED + {umfScalablePoolOps(), nullptr, umfDevDaxMemoryProviderOps(), + &defaultDevDaxParams, &hostAccessor, false}, +#endif + }; + + return ipcProxyPoolTestParamsList; +} + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(umfIpcTest); + +INSTANTIATE_TEST_SUITE_P(DevDaxProviderDifferentPoolsTest, umfIpcTest, + ::testing::ValuesIn(getIpcProxyPoolTestParamsList())); diff --git a/test/providers/provider_level_zero.cpp b/test/providers/provider_level_zero.cpp index 4403af46e..9aed3ca14 100644 --- a/test/providers/provider_level_zero.cpp +++ b/test/providers/provider_level_zero.cpp @@ -332,5 +332,5 @@ INSTANTIATE_TEST_SUITE_P(umfLevelZeroProviderTestSuite, umfIpcTest, ::testing::Values(ipcTestParams{ umfProxyPoolOps(), nullptr, umfLevelZeroMemoryProviderOps(), - &l0Params_device_memory, &l0Accessor})); + &l0Params_device_memory, &l0Accessor, false})); #endif From 82b7184477362ced35ad87d77dbc31b77114ff39 Mon Sep 17 00:00:00 2001 From: Agata Momot Date: Wed, 23 Oct 2024 13:52:35 +0000 Subject: [PATCH 237/352] UT_ASSERTs moved to test/c_api --- test/c_api/disjoint_pool.c | 1 + test/c_api/multi_pool.c | 1 + test/c_api/test_ut_asserts.h | 75 ++++++++++++++++++++++++++++++++++++ test/common/test_helpers.h | 53 ------------------------- 4 files changed, 77 insertions(+), 53 deletions(-) create mode 100644 test/c_api/test_ut_asserts.h diff --git a/test/c_api/disjoint_pool.c b/test/c_api/disjoint_pool.c index f63b28355..13cd65ab0 100644 --- a/test/c_api/disjoint_pool.c +++ b/test/c_api/disjoint_pool.c @@ -7,6 +7,7 @@ #include "pool_disjoint.h" #include "provider_null.h" #include "test_helpers.h" +#include "test_ut_asserts.h" void test_disjoint_pool_default_params(void) { umf_memory_provider_handle_t provider = nullProviderCreate(); diff --git a/test/c_api/multi_pool.c b/test/c_api/multi_pool.c index 9d4ee5d4c..9b5f73e77 100644 --- a/test/c_api/multi_pool.c +++ b/test/c_api/multi_pool.c @@ -12,6 +12,7 @@ #include #include "test_helpers.h" +#include "test_ut_asserts.h" umf_memory_pool_handle_t createDisjointPool(umf_memory_provider_handle_t provider) { diff --git a/test/c_api/test_ut_asserts.h b/test/c_api/test_ut_asserts.h new file mode 100644 index 000000000..834d39bda --- /dev/null +++ b/test/c_api/test_ut_asserts.h @@ -0,0 +1,75 @@ +/* + * + * 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 + * + */ + +/* + The project uses GTEST framework for testing, which is not supported in C + These asserts should NOT be used in other purposes than for testing C API + */ + +#ifndef UMF_TEST_UT_ASSERTS_H +#define UMF_TEST_UT_ASSERTS_H 1 + +#include +#include +#include + +static inline void UT_FATAL(const char *format, ...) { + va_list args_list; + va_start(args_list, format); + vfprintf(stderr, format, args_list); + va_end(args_list); + + fprintf(stderr, "\n"); + + abort(); +} + +static inline void UT_OUT(const char *format, ...) { + va_list args_list; + va_start(args_list, format); + vfprintf(stdout, format, args_list); + va_end(args_list); + + fprintf(stdout, "\n"); +} + +// Assert a condition is true at runtime +#define UT_ASSERT(cnd) \ + ((void)((cnd) || (UT_FATAL("%s:%d %s - assertion failure: %s", __FILE__, \ + __LINE__, __func__, #cnd), \ + 0))) + +// Assertion with extra info printed if assertion fails at runtime +#define UT_ASSERTinfo(cnd, info) \ + ((void)((cnd) || \ + (UT_FATAL("%s:%d %s - assertion failure: %s (%s = %s)", __FILE__, \ + __LINE__, __func__, #cnd, #info, info), \ + 0))) + +// Assert two integer values are equal at runtime +#define UT_ASSERTeq(lhs, rhs) \ + ((void)(((lhs) == (rhs)) || \ + (UT_FATAL("%s:%d %s - assertion failure: %s (0x%llx) == %s " \ + "(0x%llx)", \ + __FILE__, __LINE__, __func__, #lhs, \ + (unsigned long long)(lhs), #rhs, \ + (unsigned long long)(rhs)), \ + 0))) + +// Assert two integer values are not equal at runtime +#define UT_ASSERTne(lhs, rhs) \ + ((void)(((lhs) != (rhs)) || \ + (UT_FATAL("%s:%d %s - assertion failure: %s (0x%llx) != %s " \ + "(0x%llx)", \ + __FILE__, __LINE__, __func__, #lhs, \ + (unsigned long long)(lhs), #rhs, \ + (unsigned long long)(rhs)), \ + 0))) + +#endif /* UMF_TEST_UT_ASSERTS_H */ diff --git a/test/common/test_helpers.h b/test/common/test_helpers.h index df4c3c235..4a581bc4d 100644 --- a/test/common/test_helpers.h +++ b/test/common/test_helpers.h @@ -22,59 +22,6 @@ extern "C" { // Needed for CI #define TEST_SKIP_ERROR_CODE 125 -static inline void UT_FATAL(const char *format, ...) { - va_list args_list; - va_start(args_list, format); - vfprintf(stderr, format, args_list); - va_end(args_list); - - fprintf(stderr, "\n"); - - abort(); -} - -static inline void UT_OUT(const char *format, ...) { - va_list args_list; - va_start(args_list, format); - vfprintf(stdout, format, args_list); - va_end(args_list); - - fprintf(stdout, "\n"); -} - -// Assert a condition is true at runtime -#define UT_ASSERT(cnd) \ - ((void)((cnd) || (UT_FATAL("%s:%d %s - assertion failure: %s", __FILE__, \ - __LINE__, __func__, #cnd), \ - 0))) - -// Assertion with extra info printed if assertion fails at runtime -#define UT_ASSERTinfo(cnd, info) \ - ((void)((cnd) || \ - (UT_FATAL("%s:%d %s - assertion failure: %s (%s = %s)", __FILE__, \ - __LINE__, __func__, #cnd, #info, info), \ - 0))) - -// Assert two integer values are equal at runtime -#define UT_ASSERTeq(lhs, rhs) \ - ((void)(((lhs) == (rhs)) || \ - (UT_FATAL("%s:%d %s - assertion failure: %s (0x%llx) == %s " \ - "(0x%llx)", \ - __FILE__, __LINE__, __func__, #lhs, \ - (unsigned long long)(lhs), #rhs, \ - (unsigned long long)(rhs)), \ - 0))) - -// Assert two integer values are not equal at runtime -#define UT_ASSERTne(lhs, rhs) \ - ((void)(((lhs) != (rhs)) || \ - (UT_FATAL("%s:%d %s - assertion failure: %s (0x%llx) != %s " \ - "(0x%llx)", \ - __FILE__, __LINE__, __func__, #lhs, \ - (unsigned long long)(lhs), #rhs, \ - (unsigned long long)(rhs)), \ - 0))) - #ifndef ALIGN_UP #define ALIGN_UP(value, align) (((value) + (align)-1) & ~((align)-1)) #endif From 2732eb4636d2cef61d3a61572edcd8a8eedb2f85 Mon Sep 17 00:00:00 2001 From: Patryk Kaminski Date: Thu, 3 Oct 2024 16:11:36 +0200 Subject: [PATCH 238/352] Fix disabling of pci support in hwloc The flag that hwloc recognize is --disable-pci, not --disable-pciaccess. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 927dee47a..094f5cb20 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -169,7 +169,7 @@ else() COMMAND ./configure --prefix=${hwloc_targ_BINARY_DIR} --enable-static=yes --enable-shared=no --disable-libxml2 - --disable-pciaccess --disable-levelzero --disable-opencl + --disable-pci --disable-levelzero --disable-opencl --disable-cuda --disable-nvml CFLAGS=-fPIC CXXFLAGS=-fPIC WORKING_DIRECTORY ${hwloc_targ_SOURCE_DIR} OUTPUT ${hwloc_targ_SOURCE_DIR}/Makefile From b458c19008147f87037d0753a269979341ed937f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Staniewski?= Date: Thu, 31 Oct 2024 14:47:42 +0000 Subject: [PATCH 239/352] Simple IPC not supported tests --- test/CMakeLists.txt | 2 ++ test/ipcFixtures.hpp | 6 +++++ test/ipc_negative.cpp | 53 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 test/ipc_negative.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8450f049f..4b1cf2242 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -379,6 +379,8 @@ endif() add_umf_test(NAME ipc SRCS ipcAPI.cpp) +add_umf_test(NAME ipc_negative SRCS ipc_negative.cpp) + function(add_umf_ipc_test) # Parameters: * TEST - a name of the test * SRC_DIR - source files directory # path diff --git a/test/ipcFixtures.hpp b/test/ipcFixtures.hpp index 776ea7aab..79cea3864 100644 --- a/test/ipcFixtures.hpp +++ b/test/ipcFixtures.hpp @@ -166,6 +166,12 @@ TEST_P(umfIpcTest, GetIPCHandleInvalidArgs) { EXPECT_EQ(ret, UMF_RESULT_SUCCESS); } +TEST_P(umfIpcTest, CloseIPCHandleInvalidPtr) { + int local_var; + auto ret = umfCloseIPCHandle(&local_var); + EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} + TEST_P(umfIpcTest, BasicFlow) { constexpr size_t SIZE = 100; std::vector expected_data(SIZE); diff --git a/test/ipc_negative.cpp b/test/ipc_negative.cpp new file mode 100644 index 000000000..5407422ea --- /dev/null +++ b/test/ipc_negative.cpp @@ -0,0 +1,53 @@ +// Copyright (C) 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 "base.hpp" +#include "pool_null.h" +#include "provider_null.h" + +#include +#include +#include + +#include + +struct IpcNotSupported : umf_test::test { + protected: + void SetUp() override { + umf_memory_provider_ops_t provider_ops = UMF_NULL_PROVIDER_OPS; + provider_ops.ipc.get_ipc_handle_size = nullptr; + provider_ops.ipc.get_ipc_handle = nullptr; + provider_ops.ipc.open_ipc_handle = nullptr; + provider_ops.ipc.put_ipc_handle = nullptr; + provider_ops.ipc.close_ipc_handle = nullptr; + + umf_result_t ret; + ret = umfMemoryProviderCreate(&provider_ops, nullptr, &provider); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + ret = umfPoolCreate(&UMF_NULL_POOL_OPS, provider, nullptr, + UMF_POOL_CREATE_FLAG_OWN_PROVIDER, &pool); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + } + + void TearDown() override { umfPoolDestroy(pool); } + + umf_memory_provider_handle_t provider; + umf_memory_pool_handle_t pool; +}; + +TEST_F(IpcNotSupported, GetIPCHandleSizeNotSupported) { + size_t size; + auto ret = umfPoolGetIPCHandleSize(pool, &size); + EXPECT_EQ(ret, UMF_RESULT_ERROR_NOT_SUPPORTED); +} + +TEST_F(IpcNotSupported, OpenIPCHandleNotSupported) { + // This data doesn't matter, as the ipc call is no-op + std::array ipc_data = {}; + void *ptr; + auto ret = umfOpenIPCHandle( + pool, reinterpret_cast(&ipc_data), &ptr); + EXPECT_EQ(ret, UMF_RESULT_ERROR_NOT_SUPPORTED); +} From aada87384d66f8e599536ca79e0079ebe4e44d14 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Tue, 5 Nov 2024 14:20:08 +0100 Subject: [PATCH 240/352] Fix file_alloc() and file_open/close_ipc_handle() Alignment passed to `file_alloc()` must be a power of two and a multiple or a divider of the page size. Align up the alignment in `file_alloc()` to the page size. file_open_ipc_handle() has to use the memory protection and visibility got from the IPC handle, so let's add the memory protection and visibility to the IPC handle. Ref: #838 Fixes: #848 Signed-off-by: Lukasz Dorau --- src/provider/provider_file_memory.c | 45 ++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/src/provider/provider_file_memory.c b/src/provider/provider_file_memory.c index 73f78186e..7086fe45c 100644 --- a/src/provider/provider_file_memory.c +++ b/src/provider/provider_file_memory.c @@ -397,16 +397,21 @@ static umf_result_t file_alloc(void *provider, size_t size, size_t alignment, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - // alignment must be a power of two and a multiple of sizeof(void *) - if (alignment && - ((alignment & (alignment - 1)) || (alignment % sizeof(void *)))) { - LOG_ERR("wrong alignment: %zu (not a power of 2 or a multiple of " - "sizeof(void *))", - alignment); + file_memory_provider_t *file_provider = (file_memory_provider_t *)provider; + + // alignment must be a power of two and a multiple or a divider of the page size + if (alignment && ((alignment & (alignment - 1)) || + ((alignment % file_provider->page_size) && + (file_provider->page_size % alignment)))) { + LOG_ERR("wrong alignment: %zu (not a power of 2 or a multiple or a " + "divider of the page size (%zu))", + alignment, file_provider->page_size); return UMF_RESULT_ERROR_INVALID_ALIGNMENT; } - file_memory_provider_t *file_provider = (file_memory_provider_t *)provider; + if (IS_NOT_ALIGNED(alignment, file_provider->page_size)) { + alignment = ALIGN_UP(alignment, file_provider->page_size); + } void *addr = NULL; size_t alloc_offset_fd; // needed for critnib_insert() @@ -578,6 +583,8 @@ typedef struct file_ipc_data_t { char path[PATH_MAX]; size_t offset_fd; size_t size; + unsigned protection; // combination of OS-specific protection flags + unsigned visibility; // memory visibility mode } file_ipc_data_t; static umf_result_t file_get_ipc_handle_size(void *provider, size_t *size) { @@ -623,6 +630,8 @@ static umf_result_t file_get_ipc_handle(void *provider, const void *ptr, file_ipc_data->size = size; strncpy(file_ipc_data->path, file_provider->path, PATH_MAX - 1); file_ipc_data->path[PATH_MAX - 1] = '\0'; + file_ipc_data->protection = file_provider->protection; + file_ipc_data->visibility = file_provider->visibility; return UMF_RESULT_SUCCESS; } @@ -672,16 +681,26 @@ static umf_result_t file_open_ipc_handle(void *provider, void *providerIpcData, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - *ptr = utils_mmap_file(NULL, file_ipc_data->size, file_provider->protection, - file_provider->visibility, fd, - file_ipc_data->offset_fd); + char *addr = utils_mmap_file( + NULL, file_ipc_data->size, file_ipc_data->protection, + file_ipc_data->visibility, fd, file_ipc_data->offset_fd); (void)utils_close_fd(fd); - if (*ptr == NULL) { + if (addr == NULL) { file_store_last_native_error(UMF_FILE_RESULT_ERROR_ALLOC_FAILED, errno); - LOG_PERR("memory mapping failed"); - ret = UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; + LOG_PERR("file mapping failed (path: %s, size: %zu, protection: %i, " + "fd: %i, offset: %zu)", + file_ipc_data->path, file_ipc_data->size, + file_ipc_data->protection, fd, file_ipc_data->offset_fd); + return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; } + LOG_DEBUG("file mapped (path: %s, size: %zu, protection: %i, fd: %i, " + "offset: %zu) at address %p", + file_ipc_data->path, file_ipc_data->size, + file_ipc_data->protection, fd, file_ipc_data->offset_fd, addr); + + *ptr = addr; + return ret; } From f1a0ede4d5f57c9612a42d7424a8d7229e5be6b7 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Tue, 5 Nov 2024 08:18:00 +0100 Subject: [PATCH 241/352] Extract IPC tests from devdax tests Extract the IPC tests from the devdax tests to a separate file, because the IPC tests do not work with the proxy library yet and they should be run separately. Signed-off-by: Lukasz Dorau --- test/CMakeLists.txt | 4 ++ test/provider_devdax_memory.cpp | 45 ---------------------- test/provider_devdax_memory_ipc.cpp | 59 +++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 45 deletions(-) create mode 100644 test/provider_devdax_memory_ipc.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2d5eca255..475e2b19f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -274,6 +274,10 @@ if(LINUX AND (NOT UMF_DISABLE_HWLOC)) # OS-specific functions are implemented add_umf_test( NAME provider_devdax_memory SRCS provider_devdax_memory.cpp + LIBS ${UMF_UTILS_FOR_TEST}) + add_umf_test( + NAME provider_devdax_memory_ipc + SRCS provider_devdax_memory_ipc.cpp LIBS ${UMF_UTILS_FOR_TEST} ${LIB_JEMALLOC_POOL}) add_umf_test( NAME provider_file_memory diff --git a/test/provider_devdax_memory.cpp b/test/provider_devdax_memory.cpp index dba8efff7..c41fb8769 100644 --- a/test/provider_devdax_memory.cpp +++ b/test/provider_devdax_memory.cpp @@ -12,17 +12,10 @@ #include "base.hpp" #include "cpp_helpers.hpp" -#include "ipcFixtures.hpp" #include "test_helpers.h" #include #include -#ifdef UMF_POOL_JEMALLOC_ENABLED -#include -#endif -#ifdef UMF_POOL_SCALABLE_ENABLED -#include -#endif using umf_test::test; @@ -357,41 +350,3 @@ TEST_F(test, create_wrong_size_0) { EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); EXPECT_EQ(hProvider, nullptr); } - -HostMemoryAccessor hostAccessor; - -static std::vector getIpcProxyPoolTestParamsList(void) { - std::vector ipcProxyPoolTestParamsList = {}; - - char *path = getenv("UMF_TESTS_DEVDAX_PATH"); - if (path == nullptr || path[0] == 0) { - // Test skipped, UMF_TESTS_DEVDAX_PATH is not set - return ipcProxyPoolTestParamsList; - } - - char *size = getenv("UMF_TESTS_DEVDAX_SIZE"); - if (size == nullptr || size[0] == 0) { - // Test skipped, UMF_TESTS_DEVDAX_PATH is not set - return ipcProxyPoolTestParamsList; - } - - ipcProxyPoolTestParamsList = { - {umfProxyPoolOps(), nullptr, umfDevDaxMemoryProviderOps(), - &defaultDevDaxParams, &hostAccessor, true}, -#ifdef UMF_POOL_JEMALLOC_ENABLED - {umfJemallocPoolOps(), nullptr, umfDevDaxMemoryProviderOps(), - &defaultDevDaxParams, &hostAccessor, false}, -#endif -#ifdef UMF_POOL_SCALABLE_ENABLED - {umfScalablePoolOps(), nullptr, umfDevDaxMemoryProviderOps(), - &defaultDevDaxParams, &hostAccessor, false}, -#endif - }; - - return ipcProxyPoolTestParamsList; -} - -GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(umfIpcTest); - -INSTANTIATE_TEST_SUITE_P(DevDaxProviderDifferentPoolsTest, umfIpcTest, - ::testing::ValuesIn(getIpcProxyPoolTestParamsList())); diff --git a/test/provider_devdax_memory_ipc.cpp b/test/provider_devdax_memory_ipc.cpp new file mode 100644 index 000000000..071196c94 --- /dev/null +++ b/test/provider_devdax_memory_ipc.cpp @@ -0,0 +1,59 @@ +// Copyright (C) 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 +#ifdef UMF_POOL_JEMALLOC_ENABLED +#include +#endif +#ifdef UMF_POOL_SCALABLE_ENABLED +#include +#endif + +#include "ipcFixtures.hpp" + +using umf_test::test; + +auto defaultDevDaxParams = umfDevDaxMemoryProviderParamsDefault( + getenv("UMF_TESTS_DEVDAX_PATH"), + atol(getenv("UMF_TESTS_DEVDAX_SIZE") ? getenv("UMF_TESTS_DEVDAX_SIZE") + : "0")); + +HostMemoryAccessor hostAccessor; + +static std::vector getIpcProxyPoolTestParamsList(void) { + std::vector ipcProxyPoolTestParamsList = {}; + + char *path = getenv("UMF_TESTS_DEVDAX_PATH"); + if (path == nullptr || path[0] == 0) { + // skipping the test, UMF_TESTS_DEVDAX_PATH is not set + return ipcProxyPoolTestParamsList; + } + + char *size = getenv("UMF_TESTS_DEVDAX_SIZE"); + if (size == nullptr || size[0] == 0) { + // skipping the test, UMF_TESTS_DEVDAX_SIZE is not set + return ipcProxyPoolTestParamsList; + } + + ipcProxyPoolTestParamsList = { + {umfProxyPoolOps(), nullptr, umfDevDaxMemoryProviderOps(), + &defaultDevDaxParams, &hostAccessor, true}, +#ifdef UMF_POOL_JEMALLOC_ENABLED + {umfJemallocPoolOps(), nullptr, umfDevDaxMemoryProviderOps(), + &defaultDevDaxParams, &hostAccessor, false}, +#endif +#ifdef UMF_POOL_SCALABLE_ENABLED + {umfScalablePoolOps(), nullptr, umfDevDaxMemoryProviderOps(), + &defaultDevDaxParams, &hostAccessor, false}, +#endif + }; + + return ipcProxyPoolTestParamsList; +} + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(umfIpcTest); + +INSTANTIATE_TEST_SUITE_P(DevDaxProviderDifferentPoolsTest, umfIpcTest, + ::testing::ValuesIn(getIpcProxyPoolTestParamsList())); From edc1ca88f2c06606716fb3c4ed4d0dbe527733ca Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Tue, 5 Nov 2024 14:52:57 +0100 Subject: [PATCH 242/352] Add DEVDAX and FSDAX tests with the proxy library Signed-off-by: Lukasz Dorau --- .github/workflows/reusable_dax.yml | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/.github/workflows/reusable_dax.yml b/.github/workflows/reusable_dax.yml index 24e5a1bdb..787fe5360 100644 --- a/.github/workflows/reusable_dax.yml +++ b/.github/workflows/reusable_dax.yml @@ -101,10 +101,28 @@ jobs: - name: Run the FSDAX tests working-directory: ${{env.BUILD_DIR}} - run: | - UMF_TESTS_FSDAX_PATH=${{env.UMF_TESTS_FSDAX_PATH}} UMF_TESTS_FSDAX_PATH_2=${{env.UMF_TESTS_FSDAX_PATH_2}} ctest -C ${{matrix.build_type}} -R umf-provider_file_memory -V - UMF_TESTS_FSDAX_PATH=${{env.UMF_TESTS_FSDAX_PATH}} UMF_TESTS_FSDAX_PATH_2=${{env.UMF_TESTS_FSDAX_PATH_2}} ctest -C ${{matrix.build_type}} -R umf_example_dram_and_fsdax -V - UMF_TESTS_FSDAX_PATH=${{env.UMF_TESTS_FSDAX_PATH}} UMF_TESTS_FSDAX_PATH_2=${{env.UMF_TESTS_FSDAX_PATH_2}} ctest -C ${{matrix.build_type}} -R umf-ipc_file_prov_fsdax -V + run: > + UMF_TESTS_FSDAX_PATH=${{env.UMF_TESTS_FSDAX_PATH}} + UMF_TESTS_FSDAX_PATH_2=${{env.UMF_TESTS_FSDAX_PATH_2}} + ctest -C ${{matrix.build_type}} -V -R "umf-provider_file_memory|umf_example_dram_and_fsdax|umf-ipc_file_prov_fsdax" + + # TODO: enable the provider_devdax_memory_ipc test when the IPC tests with the proxy library are fixed + # see the issue: https://github.com/oneapi-src/unified-memory-framework/issues/864 + - name: Run the DEVDAX tests with the proxy library + working-directory: ${{env.BUILD_DIR}} + run: > + LD_PRELOAD=./lib/libumf_proxy.so + UMF_TESTS_DEVDAX_PATH="/dev/dax${{env.DEVDAX_NAMESPACE}}" + UMF_TESTS_DEVDAX_SIZE="$(ndctl list --namespace=namespace${{env.DEVDAX_NAMESPACE}} | grep size | cut -d':' -f2 | cut -d',' -f1)" + ctest -C ${{matrix.build_type}} -R devdax -E provider_devdax_memory_ipc -V + + - name: Run the FSDAX tests with the proxy library + working-directory: ${{env.BUILD_DIR}} + run: > + LD_PRELOAD=./lib/libumf_proxy.so + UMF_TESTS_FSDAX_PATH=${{env.UMF_TESTS_FSDAX_PATH}} + UMF_TESTS_FSDAX_PATH_2=${{env.UMF_TESTS_FSDAX_PATH_2}} + ctest -C ${{matrix.build_type}} -V -R "umf-provider_file_memory|umf_example_dram_and_fsdax|umf-ipc_file_prov_fsdax" - name: Check coverage if: ${{ matrix.build_type == 'Debug' }} From b7cf6f059440ba57dab74383c6178a66700fd279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Staniewski?= Date: Tue, 5 Nov 2024 15:28:44 +0000 Subject: [PATCH 243/352] Fix `utils_linux.cpp` coverity defects --- test/utils/utils_linux.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/utils/utils_linux.cpp b/test/utils/utils_linux.cpp index f88e9daf2..aceefd4c6 100644 --- a/test/utils/utils_linux.cpp +++ b/test/utils/utils_linux.cpp @@ -23,17 +23,19 @@ TEST_F(test, utils_shm_open_invalid_args) { TEST_F(test, utils_get_file_size_invalid_args) { size_t size; - auto ret = utils_get_file_size(-1, &size); + auto ret = utils_get_file_size(0xffffff, &size); EXPECT_EQ(ret, -1); int fd = utils_create_anonymous_fd(); + ASSERT_GE(fd, 0); + ret = utils_get_file_size(fd, &size); EXPECT_EQ(ret, 0); EXPECT_EQ(size, 0); } TEST_F(test, utils_set_file_size_invalid_args) { - auto ret = utils_set_file_size(-1, 256); + auto ret = utils_set_file_size(0xffffff, 256); EXPECT_EQ(ret, -1); } From 7bc9eba36116b6b6445001ed93a3baa18e81a0ef Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Tue, 5 Nov 2024 23:31:23 +0100 Subject: [PATCH 244/352] Fix issue with the UMF_LEVEL_ZERO_INCLUDE_DIR --- CMakeLists.txt | 58 ++++++++++++++++++++++++++++++++++++++++++++++ src/CMakeLists.txt | 58 ---------------------------------------------- 2 files changed, 58 insertions(+), 58 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 927dee47a..e3bdcc8e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -218,6 +218,64 @@ if(hwloc_targ_SOURCE_DIR) endif() endif() +# Fetch L0 loader only if needed i.e.: if building L0 provider is ON and L0 +# headers are not provided by the user (via setting UMF_LEVEL_ZERO_INCLUDE_DIR). +if(UMF_BUILD_LEVEL_ZERO_PROVIDER AND (NOT UMF_LEVEL_ZERO_INCLUDE_DIR)) + include(FetchContent) + + set(LEVEL_ZERO_LOADER_REPO "https://github.com/oneapi-src/level-zero.git") + set(LEVEL_ZERO_LOADER_TAG v1.17.39) + + message( + STATUS + "Fetching L0 loader (${LEVEL_ZERO_LOADER_TAG}) from ${LEVEL_ZERO_LOADER_REPO} ..." + ) + + FetchContent_Declare( + level-zero-loader + GIT_REPOSITORY ${LEVEL_ZERO_LOADER_REPO} + GIT_TAG ${LEVEL_ZERO_LOADER_TAG} + EXCLUDE_FROM_ALL) + FetchContent_MakeAvailable(level-zero-loader) + + set(LEVEL_ZERO_INCLUDE_DIRS + ${level-zero-loader_SOURCE_DIR}/include + CACHE PATH "Path to Level Zero Headers") + message(STATUS "Level Zero include directory: ${LEVEL_ZERO_INCLUDE_DIRS}") +elseif(UMF_BUILD_LEVEL_ZERO_PROVIDER) + # Only header is needed to build UMF + set(LEVEL_ZERO_INCLUDE_DIRS ${UMF_LEVEL_ZERO_INCLUDE_DIR}) + message(STATUS "Level Zero include directory: ${LEVEL_ZERO_INCLUDE_DIRS}") +endif() + +# Fetch CUDA only if needed i.e.: if building CUDA provider is ON and CUDA +# headers are not provided by the user (via setting UMF_CUDA_INCLUDE_DIR). +if(UMF_BUILD_CUDA_PROVIDER AND (NOT UMF_CUDA_INCLUDE_DIR)) + include(FetchContent) + + set(CUDA_REPO + "https://gitlab.com/nvidia/headers/cuda-individual/cudart.git") + set(CUDA_TAG cuda-12.5.1) + + message(STATUS "Fetching CUDA ${CUDA_TAG} from ${CUDA_REPO} ...") + + FetchContent_Declare( + cuda-headers + GIT_REPOSITORY ${CUDA_REPO} + GIT_TAG ${CUDA_TAG} + EXCLUDE_FROM_ALL) + FetchContent_MakeAvailable(cuda-headers) + + set(CUDA_INCLUDE_DIRS + ${cuda-headers_SOURCE_DIR} + CACHE PATH "Path to CUDA headers") + message(STATUS "CUDA include directory: ${CUDA_INCLUDE_DIRS}") +elseif(UMF_BUILD_CUDA_PROVIDER) + # Only header is needed to build UMF + set(CUDA_INCLUDE_DIRS ${UMF_CUDA_INCLUDE_DIR}) + message(STATUS "CUDA include directory: ${CUDA_INCLUDE_DIRS}") +endif() + # This build type check is not possible on Windows when CMAKE_BUILD_TYPE is not # set, because in this case the build type is determined after a CMake # configuration is done (at the build time) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f2d29294d..9fabe2a08 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -16,64 +16,6 @@ set(UMF_CUDA_INCLUDE_DIR # TODO: Cleanup the compile definitions across all the CMake files set(UMF_COMMON_COMPILE_DEFINITIONS UMF_VERSION=${UMF_VERSION}) -# Fetch L0 loader only if needed i.e.: if building L0 provider is ON and L0 -# headers are not provided by the user (via setting UMF_LEVEL_ZERO_INCLUDE_DIR). -if(UMF_BUILD_LEVEL_ZERO_PROVIDER AND (NOT UMF_LEVEL_ZERO_INCLUDE_DIR)) - include(FetchContent) - - set(LEVEL_ZERO_LOADER_REPO "https://github.com/oneapi-src/level-zero.git") - set(LEVEL_ZERO_LOADER_TAG v1.17.39) - - message( - STATUS - "Fetching L0 loader (${LEVEL_ZERO_LOADER_TAG}) from ${LEVEL_ZERO_LOADER_REPO} ..." - ) - - FetchContent_Declare( - level-zero-loader - GIT_REPOSITORY ${LEVEL_ZERO_LOADER_REPO} - GIT_TAG ${LEVEL_ZERO_LOADER_TAG} - EXCLUDE_FROM_ALL) - FetchContent_MakeAvailable(level-zero-loader) - - set(LEVEL_ZERO_INCLUDE_DIRS - ${level-zero-loader_SOURCE_DIR}/include - CACHE PATH "Path to Level Zero Headers") - message(STATUS "Level Zero include directory: ${LEVEL_ZERO_INCLUDE_DIRS}") -elseif(UMF_BUILD_LEVEL_ZERO_PROVIDER) - # Only header is needed to build UMF - set(LEVEL_ZERO_INCLUDE_DIRS ${UMF_LEVEL_ZERO_INCLUDE_DIR}) - message(STATUS "Level Zero include directory: ${LEVEL_ZERO_INCLUDE_DIRS}") -endif() - -# Fetch CUDA only if needed i.e.: if building CUDA provider is ON and CUDA -# headers are not provided by the user (via setting UMF_CUDA_INCLUDE_DIR). -if(UMF_BUILD_CUDA_PROVIDER AND (NOT UMF_CUDA_INCLUDE_DIR)) - include(FetchContent) - - set(CUDA_REPO - "https://gitlab.com/nvidia/headers/cuda-individual/cudart.git") - set(CUDA_TAG cuda-12.5.1) - - message(STATUS "Fetching CUDA ${CUDA_TAG} from ${CUDA_REPO} ...") - - FetchContent_Declare( - cuda-headers - GIT_REPOSITORY ${CUDA_REPO} - GIT_TAG ${CUDA_TAG} - EXCLUDE_FROM_ALL) - FetchContent_MakeAvailable(cuda-headers) - - set(CUDA_INCLUDE_DIRS - ${cuda-headers_SOURCE_DIR} - CACHE PATH "Path to CUDA headers") - message(STATUS "CUDA include directory: ${CUDA_INCLUDE_DIRS}") -elseif(UMF_BUILD_CUDA_PROVIDER) - # Only header is needed to build UMF - set(CUDA_INCLUDE_DIRS ${UMF_CUDA_INCLUDE_DIR}) - message(STATUS "CUDA include directory: ${CUDA_INCLUDE_DIRS}") -endif() - add_subdirectory(utils) set(UMF_LIBS $) From 17d76547248fbcfb15b55ba0224d3c6bcb69eb0d Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Tue, 5 Nov 2024 23:31:55 +0100 Subject: [PATCH 245/352] Remove incorrect L0 test --- test/providers/provider_level_zero.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/test/providers/provider_level_zero.cpp b/test/providers/provider_level_zero.cpp index 9aed3ca14..4041362f0 100644 --- a/test/providers/provider_level_zero.cpp +++ b/test/providers/provider_level_zero.cpp @@ -263,15 +263,6 @@ TEST_P(umfLevelZeroProviderTest, allocInvalidSize) { umfMemoryProviderGetLastNativeError(provider, &message, &error); ASSERT_EQ(error, ZE_RESULT_ERROR_UNSUPPORTED_SIZE); - // in case of size == 0 we should got INVALID_ARGUMENT error - // NOTE: this is invalid only for the DEVICE or SHARED allocations - if (params.memory_type != UMF_MEMORY_TYPE_HOST) { - umf_result = umfMemoryProviderAlloc(provider, 0, 0, &ptr); - ASSERT_EQ(umf_result, UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC); - umfMemoryProviderGetLastNativeError(provider, &message, &error); - ASSERT_EQ(error, ZE_RESULT_ERROR_UNSUPPORTED_SIZE); - } - umfMemoryProviderDestroy(provider); } From 162119384e8a98b34b59ea1d6bcbe067a9431740 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 6 Nov 2024 11:50:57 +0100 Subject: [PATCH 246/352] Fix os_get_ipc_handle() - add protection and visibility Add protection and visibility to the IPC handle. Fix `os_get_ipc_handle()` - get protection and visibility from the IPC handle instead of provider. Signed-off-by: Lukasz Dorau --- src/provider/provider_os_memory.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/provider/provider_os_memory.c b/src/provider/provider_os_memory.c index 3318beef0..87dd08cf7 100644 --- a/src/provider/provider_os_memory.c +++ b/src/provider/provider_os_memory.c @@ -1153,6 +1153,8 @@ typedef struct os_ipc_data_t { int fd; size_t fd_offset; size_t size; + unsigned protection; // combination of OS-specific protection flags + unsigned visibility; // memory visibility mode // shm_name is a Flexible Array Member because it is optional and its size // varies on the Shared Memory object name size_t shm_name_len; @@ -1200,6 +1202,8 @@ static umf_result_t os_get_ipc_handle(void *provider, const void *ptr, os_ipc_data->pid = utils_getpid(); os_ipc_data->fd_offset = (size_t)value - 1; os_ipc_data->size = size; + os_ipc_data->protection = os_provider->protection; + os_ipc_data->visibility = os_provider->visibility; os_ipc_data->shm_name_len = strlen(os_provider->shm_name); if (os_ipc_data->shm_name_len > 0) { strncpy(os_ipc_data->shm_name, os_provider->shm_name, @@ -1278,8 +1282,8 @@ static umf_result_t os_open_ipc_handle(void *provider, void *providerIpcData, } } - *ptr = utils_mmap(NULL, os_ipc_data->size, os_provider->protection, - os_provider->visibility, fd, os_ipc_data->fd_offset); + *ptr = utils_mmap(NULL, os_ipc_data->size, os_ipc_data->protection, + os_ipc_data->visibility, fd, os_ipc_data->fd_offset); if (*ptr == NULL) { os_store_last_native_error(UMF_OS_RESULT_ERROR_ALLOC_FAILED, errno); LOG_PERR("memory mapping failed"); From bf6dc3e82c9a9959d6b2bca5476510427d94a9df Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Tue, 5 Nov 2024 10:36:08 +0100 Subject: [PATCH 247/352] Disable the provider_file_memory_ipc test with the proxy library Disable the provider_file_memory_ipc test with the proxy library, because the IPC tests do not work with the proxy library. Ref: #864 Signed-off-by: Lukasz Dorau --- .github/workflows/reusable_dax.yml | 10 ++++++---- .github/workflows/reusable_proxy_lib.yml | 4 +++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/reusable_dax.yml b/.github/workflows/reusable_dax.yml index 787fe5360..b30cc0afc 100644 --- a/.github/workflows/reusable_dax.yml +++ b/.github/workflows/reusable_dax.yml @@ -97,14 +97,14 @@ jobs: run: > UMF_TESTS_DEVDAX_PATH="/dev/dax${{env.DEVDAX_NAMESPACE}}" UMF_TESTS_DEVDAX_SIZE="$(ndctl list --namespace=namespace${{env.DEVDAX_NAMESPACE}} | grep size | cut -d':' -f2 | cut -d',' -f1)" - ctest -C ${{matrix.build_type}} -R devdax -V + ctest -C ${{matrix.build_type}} -V -R devdax - name: Run the FSDAX tests working-directory: ${{env.BUILD_DIR}} run: > UMF_TESTS_FSDAX_PATH=${{env.UMF_TESTS_FSDAX_PATH}} UMF_TESTS_FSDAX_PATH_2=${{env.UMF_TESTS_FSDAX_PATH_2}} - ctest -C ${{matrix.build_type}} -V -R "umf-provider_file_memory|umf_example_dram_and_fsdax|umf-ipc_file_prov_fsdax" + ctest -C ${{matrix.build_type}} -V -R "file|fsdax" # TODO: enable the provider_devdax_memory_ipc test when the IPC tests with the proxy library are fixed # see the issue: https://github.com/oneapi-src/unified-memory-framework/issues/864 @@ -114,15 +114,17 @@ jobs: LD_PRELOAD=./lib/libumf_proxy.so UMF_TESTS_DEVDAX_PATH="/dev/dax${{env.DEVDAX_NAMESPACE}}" UMF_TESTS_DEVDAX_SIZE="$(ndctl list --namespace=namespace${{env.DEVDAX_NAMESPACE}} | grep size | cut -d':' -f2 | cut -d',' -f1)" - ctest -C ${{matrix.build_type}} -R devdax -E provider_devdax_memory_ipc -V + ctest -C ${{matrix.build_type}} -V -R devdax -E provider_devdax_memory_ipc + # TODO: enable the provider_file_memory_ipc test when the IPC tests with the proxy library are fixed + # see the issue: https://github.com/oneapi-src/unified-memory-framework/issues/864 - name: Run the FSDAX tests with the proxy library working-directory: ${{env.BUILD_DIR}} run: > LD_PRELOAD=./lib/libumf_proxy.so UMF_TESTS_FSDAX_PATH=${{env.UMF_TESTS_FSDAX_PATH}} UMF_TESTS_FSDAX_PATH_2=${{env.UMF_TESTS_FSDAX_PATH_2}} - ctest -C ${{matrix.build_type}} -V -R "umf-provider_file_memory|umf_example_dram_and_fsdax|umf-ipc_file_prov_fsdax" + ctest -C ${{matrix.build_type}} -V -R "file|fsdax" -E provider_file_memory_ipc - name: Check coverage if: ${{ matrix.build_type == 'Debug' }} diff --git a/.github/workflows/reusable_proxy_lib.yml b/.github/workflows/reusable_proxy_lib.yml index 3babd205e..56211b97d 100644 --- a/.github/workflows/reusable_proxy_lib.yml +++ b/.github/workflows/reusable_proxy_lib.yml @@ -59,9 +59,11 @@ jobs: - name: Build UMF run: cmake --build ${{env.BUILD_DIR}} -j $(nproc) + # TODO enable the provider_file_memory_ipc test when the IPC tests with the proxy library are fixed + # see the issue: https://github.com/oneapi-src/unified-memory-framework/issues/864 - name: Run "ctest --output-on-failure" with proxy library working-directory: ${{env.BUILD_DIR}} - run: LD_PRELOAD=./lib/libumf_proxy.so ctest --output-on-failure + run: LD_PRELOAD=./lib/libumf_proxy.so ctest --output-on-failure -E provider_file_memory_ipc - name: Run "./test/umf_test-memoryPool" with proxy library working-directory: ${{env.BUILD_DIR}} From dee91d1d4e5264c9e44e045a34cee3c6d01fe564 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 6 Nov 2024 14:26:32 +0100 Subject: [PATCH 248/352] Add IPC tests (umfIpcTest) to the file provider Signed-off-by: Lukasz Dorau --- test/CMakeLists.txt | 4 ++ test/provider_file_memory_ipc.cpp | 49 +++++++++++++++++++ ...drd-umf_test-provider_file_memory_ipc.supp | 7 +++ 3 files changed, 60 insertions(+) create mode 100644 test/provider_file_memory_ipc.cpp create mode 100644 test/supp/drd-umf_test-provider_file_memory_ipc.supp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 475e2b19f..a4d7c1418 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -283,6 +283,10 @@ if(LINUX AND (NOT UMF_DISABLE_HWLOC)) # OS-specific functions are implemented NAME provider_file_memory SRCS provider_file_memory.cpp LIBS ${UMF_UTILS_FOR_TEST}) + add_umf_test( + NAME provider_file_memory_ipc + SRCS provider_file_memory_ipc.cpp + LIBS ${UMF_UTILS_FOR_TEST} ${LIB_JEMALLOC_POOL}) # This test requires Linux-only file memory provider if(UMF_POOL_JEMALLOC_ENABLED) diff --git a/test/provider_file_memory_ipc.cpp b/test/provider_file_memory_ipc.cpp new file mode 100644 index 000000000..619c13b05 --- /dev/null +++ b/test/provider_file_memory_ipc.cpp @@ -0,0 +1,49 @@ +// Copyright (C) 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 +#ifdef UMF_POOL_JEMALLOC_ENABLED +#include +#endif +#ifdef UMF_POOL_SCALABLE_ENABLED +#include +#endif + +#include "ipcFixtures.hpp" + +using umf_test::test; + +#define FILE_PATH ((char *)"tmp_file") + +umf_file_memory_provider_params_t get_file_params_shared(char *path) { + umf_file_memory_provider_params_t file_params = + umfFileMemoryProviderParamsDefault(path); + file_params.visibility = UMF_MEM_MAP_SHARED; + return file_params; +} + +umf_file_memory_provider_params_t file_params_shared = + get_file_params_shared(FILE_PATH); + +HostMemoryAccessor hostAccessor; + +static std::vector ipcManyPoolsTestParamsList = { +// TODO: enable it when sizes of allocations in ipcFixtures.hpp are fixed +// {umfProxyPoolOps(), nullptr, umfFileMemoryProviderOps(), +// &file_params_shared, &hostAccessor, true}, +#ifdef UMF_POOL_JEMALLOC_ENABLED + {umfJemallocPoolOps(), nullptr, umfFileMemoryProviderOps(), + &file_params_shared, &hostAccessor, false}, +#endif +#ifdef UMF_POOL_SCALABLE_ENABLED + {umfScalablePoolOps(), nullptr, umfFileMemoryProviderOps(), + &file_params_shared, &hostAccessor, false}, +#endif +}; + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(umfIpcTest); + +INSTANTIATE_TEST_SUITE_P(FileProviderDifferentPoolsTest, umfIpcTest, + ::testing::ValuesIn(ipcManyPoolsTestParamsList)); diff --git a/test/supp/drd-umf_test-provider_file_memory_ipc.supp b/test/supp/drd-umf_test-provider_file_memory_ipc.supp new file mode 100644 index 000000000..76844585d --- /dev/null +++ b/test/supp/drd-umf_test-provider_file_memory_ipc.supp @@ -0,0 +1,7 @@ +{ + Conditional variable destruction false-positive + drd:CondErr + ... + fun:pthread_cond_destroy@* + ... +} From 86c18c82d96596f279714aa7f3c59f6abee56afc Mon Sep 17 00:00:00 2001 From: Patryk Kaminski Date: Wed, 6 Nov 2024 12:58:17 +0100 Subject: [PATCH 249/352] Simplify build steps example - do not mix usage of make and cmake, cmake handles all that is needed - cmake handles build dir creation --- README.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index f759f8636..923db6f2c 100644 --- a/README.md +++ b/README.md @@ -46,23 +46,22 @@ For Level Zero memory provider tests: ### Linux -Executable and binaries will be in **build/bin** +Executable and binaries will be in **build/bin**. +The `{build_config}` can be either `Debug` or `Release`. ```bash -$ mkdir build -$ cd build -$ cmake {path_to_source_dir} -$ make +$ cmake -B build -DCMAKE_BUILD_TYPE={build_config} +$ cmake --build build -j $(nproc) ``` ### Windows -Generating Visual Studio Project. EXE and binaries will be in **build/bin/{build_config}** +Generating Visual Studio Project. EXE and binaries will be in **build/bin/{build_config}**. +The `{build_config}` can be either `Debug` or `Release`. ```bash -$ mkdir build -$ cd build -$ cmake {path_to_source_dir} -G "Visual Studio 15 2017 Win64" +$ cmake -B build -G "Visual Studio 15 2017 Win64" +$ cmake --build build --config {build_config} -j $Env:NUMBER_OF_PROCESSORS ``` ### Benchmark From baafe409634a1dd383d307369d657e6b05ca917e Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 6 Nov 2024 15:42:11 +0100 Subject: [PATCH 250/352] Fix linking tests with libcuda Signed-off-by: Lukasz Dorau --- test/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 475e2b19f..afffd6b91 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -44,6 +44,10 @@ function(build_umf_test) set(LIB_DIRS ${LIB_DIRS} ${JEMALLOC_LIBRARY_DIRS}) endif() + if(UMF_BUILD_CUDA_PROVIDER) + set(LIB_DIRS ${LIB_DIRS} ${CUDA_LIBRARY_DIRS}) + endif() + set(TEST_LIBS umf_test_common ${ARG_LIBS} From bf33da846f4a5bf306a046e70cec6f58b9c4d159 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Thu, 7 Nov 2024 09:21:24 +0100 Subject: [PATCH 251/352] Use umf_ba_global_() API in MALLOC_PROVIDER_OPS Signed-off-by: Lukasz Dorau --- test/CMakeLists.txt | 54 +++++++++++++++++++++++++++------------- test/common/provider.hpp | 15 +++-------- test/provider_coarse.cpp | 2 +- 3 files changed, 42 insertions(+), 29 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c06a6cf15..4427ea0e0 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -150,12 +150,20 @@ if(UMF_POOL_JEMALLOC_ENABLED) set(LIB_JEMALLOC_POOL jemalloc_pool) endif() +if(UMF_BUILD_SHARED_LIBRARY) + # if build as shared library, ba symbols won't be visible in tests + set(BA_SOURCES_FOR_TEST ${BA_SOURCES}) +endif() + add_umf_test(NAME base SRCS base.cpp) add_umf_test( NAME memoryPool - SRCS memoryPoolAPI.cpp malloc_compliance_tests.cpp + SRCS memoryPoolAPI.cpp malloc_compliance_tests.cpp ${BA_SOURCES_FOR_TEST} + LIBS ${UMF_UTILS_FOR_TEST}) +add_umf_test( + NAME memoryProvider + SRCS memoryProviderAPI.cpp ${BA_SOURCES_FOR_TEST} LIBS ${UMF_UTILS_FOR_TEST}) -add_umf_test(NAME memoryProvider SRCS memoryProviderAPI.cpp) add_umf_test( NAME logger SRCS utils/utils_log.cpp ${UMF_UTILS_SOURCES} @@ -173,7 +181,10 @@ if(LINUX) LIBS ${UMF_UTILS_FOR_TEST}) endif() -add_umf_test(NAME provider_coarse SRCS provider_coarse.cpp) +add_umf_test( + NAME provider_coarse + SRCS provider_coarse.cpp ${BA_SOURCES_FOR_TEST} + LIBS ${UMF_UTILS_FOR_TEST}) if(UMF_BUILD_LIBUMF_POOL_DISJOINT) add_umf_test( @@ -208,8 +219,11 @@ if(UMF_POOL_JEMALLOC_ENABLED AND (NOT UMF_DISABLE_HWLOC)) endif() if(UMF_POOL_SCALABLE_ENABLED AND (NOT UMF_DISABLE_HWLOC)) - add_umf_test(NAME scalable_pool SRCS pools/scalable_pool.cpp - malloc_compliance_tests.cpp) + add_umf_test( + NAME scalable_pool + SRCS pools/scalable_pool.cpp malloc_compliance_tests.cpp + ${BA_SOURCES_FOR_TEST} + LIBS ${UMF_UTILS_FOR_TEST}) endif() if(LINUX AND (NOT UMF_DISABLE_HWLOC)) # OS-specific functions are implemented @@ -223,7 +237,7 @@ if(LINUX AND (NOT UMF_DISABLE_HWLOC)) # OS-specific functions are implemented add_umf_test( NAME provider_os_memory - SRCS provider_os_memory.cpp + SRCS provider_os_memory.cpp ${BA_SOURCES_FOR_TEST} LIBS ${UMF_UTILS_FOR_TEST}) if(UMF_BUILD_LIBUMF_POOL_DISJOINT) target_compile_definitions(umf_test-provider_os_memory @@ -277,7 +291,7 @@ if(LINUX AND (NOT UMF_DISABLE_HWLOC)) # OS-specific functions are implemented LIBS ${UMF_UTILS_FOR_TEST}) add_umf_test( NAME provider_devdax_memory_ipc - SRCS provider_devdax_memory_ipc.cpp + SRCS provider_devdax_memory_ipc.cpp ${BA_SOURCES_FOR_TEST} LIBS ${UMF_UTILS_FOR_TEST} ${LIB_JEMALLOC_POOL}) add_umf_test( NAME provider_file_memory @@ -299,11 +313,15 @@ if(LINUX AND (NOT UMF_DISABLE_HWLOC)) # OS-specific functions are implemented # This test requires Linux-only file memory provider if(UMF_POOL_SCALABLE_ENABLED) add_umf_test( - NAME scalable_coarse_file SRCS pools/scalable_coarse_file.cpp - malloc_compliance_tests.cpp) + NAME scalable_coarse_file + SRCS pools/scalable_coarse_file.cpp malloc_compliance_tests.cpp + ${BA_SOURCES_FOR_TEST} + LIBS ${UMF_UTILS_FOR_TEST}) add_umf_test( - NAME scalable_coarse_devdax SRCS pools/scalable_coarse_devdax.cpp - malloc_compliance_tests.cpp) + NAME scalable_coarse_devdax + SRCS pools/scalable_coarse_devdax.cpp malloc_compliance_tests.cpp + ${BA_SOURCES_FOR_TEST} + LIBS ${UMF_UTILS_FOR_TEST}) endif() if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND UMF_BUILD_FUZZTESTS) @@ -318,6 +336,7 @@ if(UMF_BUILD_GPU_TESTS AND UMF_BUILD_LEVEL_ZERO_PROVIDER) add_umf_test( NAME provider_level_zero SRCS providers/provider_level_zero.cpp providers/level_zero_helpers.cpp + ${BA_SOURCES_FOR_TEST} LIBS ${UMF_UTILS_FOR_TEST} ze_loader) target_include_directories(umf_test-provider_level_zero PRIVATE ${LEVEL_ZERO_INCLUDE_DIRS}) @@ -325,6 +344,7 @@ if(UMF_BUILD_GPU_TESTS AND UMF_BUILD_LEVEL_ZERO_PROVIDER) add_umf_test( NAME provider_level_zero_dlopen SRCS providers/provider_level_zero.cpp providers/level_zero_helpers.cpp + ${BA_SOURCES_FOR_TEST} LIBS ${UMF_UTILS_FOR_TEST}) target_compile_definitions(umf_test-provider_level_zero_dlopen PUBLIC USE_DLOPEN=1) @@ -340,6 +360,7 @@ if(UMF_BUILD_GPU_TESTS AND UMF_BUILD_CUDA_PROVIDER) add_umf_test( NAME provider_cuda SRCS providers/provider_cuda.cpp providers/cuda_helpers.cpp + ${BA_SOURCES_FOR_TEST} LIBS ${UMF_UTILS_FOR_TEST} cuda) target_include_directories(umf_test-provider_cuda PRIVATE ${CUDA_INCLUDE_DIRS}) @@ -349,6 +370,7 @@ if(UMF_BUILD_GPU_TESTS AND UMF_BUILD_CUDA_PROVIDER) add_umf_test( NAME provider_cuda_dlopen SRCS providers/provider_cuda.cpp providers/cuda_helpers.cpp + ${BA_SOURCES_FOR_TEST} LIBS ${UMF_UTILS_FOR_TEST}) target_compile_definitions(umf_test-provider_cuda_dlopen PUBLIC USE_DLOPEN=1) @@ -362,11 +384,6 @@ if(UMF_BUILD_GPU_TESTS AND UMF_BUILD_CUDA_PROVIDER) endif() endif() -if(UMF_BUILD_SHARED_LIBRARY) - # if build as shared library, ba symbols won't be visible in tests - set(BA_SOURCES_FOR_TEST ${BA_SOURCES}) -endif() - add_umf_test( NAME base_alloc SRCS ${BA_SOURCES_FOR_TEST} test_base_alloc.cpp @@ -402,7 +419,10 @@ if(UMF_PROXY_LIB_ENABLED PUBLIC UMF_PROXY_LIB_ENABLED=1) endif() -add_umf_test(NAME ipc SRCS ipcAPI.cpp) +add_umf_test( + NAME ipc + SRCS ipcAPI.cpp ${BA_SOURCES_FOR_TEST} + LIBS ${UMF_UTILS_FOR_TEST}) add_umf_test(NAME ipc_negative SRCS ipc_negative.cpp) diff --git a/test/common/provider.hpp b/test/common/provider.hpp index cb4835eb5..514f03b80 100644 --- a/test/common/provider.hpp +++ b/test/common/provider.hpp @@ -14,6 +14,7 @@ #include #include "base.hpp" +#include "base_alloc_global.h" #include "cpp_helpers.hpp" #include "test_helpers.h" @@ -110,24 +111,16 @@ struct provider_malloc : public provider_base_t { // error because of this issue. size_t aligned_size = ALIGN_UP(size, align); -#ifdef _WIN32 - *ptr = _aligned_malloc(aligned_size, align); -#else - *ptr = ::aligned_alloc(align, aligned_size); -#endif + *ptr = umf_ba_global_aligned_alloc(aligned_size, align); return (*ptr) ? UMF_RESULT_SUCCESS : UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; } umf_result_t free(void *ptr, size_t) noexcept { -#ifdef _WIN32 - _aligned_free(ptr); -#else - ::free(ptr); -#endif + umf_ba_global_free(ptr); return UMF_RESULT_SUCCESS; } - const char *get_name() noexcept { return "malloc"; } + const char *get_name() noexcept { return "umf_ba_global"; } }; umf_memory_provider_ops_t MALLOC_PROVIDER_OPS = diff --git a/test/provider_coarse.cpp b/test/provider_coarse.cpp index 6995f6aba..14f69c599 100644 --- a/test/provider_coarse.cpp +++ b/test/provider_coarse.cpp @@ -17,7 +17,7 @@ using umf_test::test; #define GetStats umfCoarseMemoryProviderGetStats -#define UPSTREAM_NAME "malloc" +#define UPSTREAM_NAME "umf_ba_global" #define BASE_NAME "coarse" #define COARSE_NAME BASE_NAME " (" UPSTREAM_NAME ")" From e71430130984be438a6ebf212337e35dd5a47e60 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 6 Nov 2024 14:14:12 +0100 Subject: [PATCH 252/352] Rename provider_malloc to provider_ba_global Signed-off-by: Lukasz Dorau --- test/common/provider.hpp | 6 +++--- test/disjointCoarseMallocPool.cpp | 2 +- test/ipcAPI.cpp | 2 +- test/provider_coarse.cpp | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/common/provider.hpp b/test/common/provider.hpp index 514f03b80..ef24ca01d 100644 --- a/test/common/provider.hpp +++ b/test/common/provider.hpp @@ -99,7 +99,7 @@ typedef struct provider_base_t { umf_memory_provider_ops_t BASE_PROVIDER_OPS = umf::providerMakeCOps(); -struct provider_malloc : public provider_base_t { +struct provider_ba_global : public provider_base_t { umf_result_t alloc(size_t size, size_t align, void **ptr) noexcept { if (!align) { align = 8; @@ -124,10 +124,10 @@ struct provider_malloc : public provider_base_t { }; umf_memory_provider_ops_t MALLOC_PROVIDER_OPS = - umf::providerMakeCOps(); + umf::providerMakeCOps(); struct provider_mock_out_of_mem : public provider_base_t { - provider_malloc helper_prov; + provider_ba_global helper_prov; int allocNum = 0; umf_result_t initialize(int *inAllocNum) noexcept { allocNum = *inAllocNum; diff --git a/test/disjointCoarseMallocPool.cpp b/test/disjointCoarseMallocPool.cpp index 0ff38bb1c..3c5ec6166 100644 --- a/test/disjointCoarseMallocPool.cpp +++ b/test/disjointCoarseMallocPool.cpp @@ -19,7 +19,7 @@ using umf_test::test; #define GetStats umfCoarseMemoryProviderGetStats umf_memory_provider_ops_t UMF_MALLOC_MEMORY_PROVIDER_OPS = - umf::providerMakeCOps(); + umf::providerMakeCOps(); struct CoarseWithMemoryStrategyTest : umf_test::test, diff --git a/test/ipcAPI.cpp b/test/ipcAPI.cpp index 8455af15b..4df32a1c9 100644 --- a/test/ipcAPI.cpp +++ b/test/ipcAPI.cpp @@ -24,7 +24,7 @@ struct provider_mock_ipc : public umf_test::provider_base_t { size_t size; }; - umf_test::provider_malloc helper_prov; + umf_test::provider_ba_global helper_prov; static allocations_mutex_type alloc_mutex; static allocations_map_type allocations; diff --git a/test/provider_coarse.cpp b/test/provider_coarse.cpp index 14f69c599..29e30160d 100644 --- a/test/provider_coarse.cpp +++ b/test/provider_coarse.cpp @@ -22,7 +22,7 @@ using umf_test::test; #define COARSE_NAME BASE_NAME " (" UPSTREAM_NAME ")" umf_memory_provider_ops_t UMF_MALLOC_MEMORY_PROVIDER_OPS = - umf::providerMakeCOps(); + umf::providerMakeCOps(); struct CoarseWithMemoryStrategyTest : umf_test::test, From b51636572268cba7b17997015d882bee1a2b5426 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 6 Nov 2024 14:39:15 +0100 Subject: [PATCH 253/352] Rename MALLOC_PROVIDER_OPS to BA_GLOBAL_PROVIDER_OPS Signed-off-by: Lukasz Dorau --- test/common/provider.hpp | 2 +- test/memoryPoolAPI.cpp | 8 ++++---- test/pools/disjoint_pool.cpp | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/test/common/provider.hpp b/test/common/provider.hpp index ef24ca01d..11c7056db 100644 --- a/test/common/provider.hpp +++ b/test/common/provider.hpp @@ -123,7 +123,7 @@ struct provider_ba_global : public provider_base_t { const char *get_name() noexcept { return "umf_ba_global"; } }; -umf_memory_provider_ops_t MALLOC_PROVIDER_OPS = +umf_memory_provider_ops_t BA_GLOBAL_PROVIDER_OPS = umf::providerMakeCOps(); struct provider_mock_out_of_mem : public provider_base_t { diff --git a/test/memoryPoolAPI.cpp b/test/memoryPoolAPI.cpp index d761780d0..1c6d83f2a 100644 --- a/test/memoryPoolAPI.cpp +++ b/test/memoryPoolAPI.cpp @@ -156,7 +156,7 @@ TEST_F(test, BasicPoolByPtrTest) { umf_memory_provider_handle_t provider; umf_result_t ret = - umfMemoryProviderCreate(&MALLOC_PROVIDER_OPS, NULL, &provider); + umfMemoryProviderCreate(&BA_GLOBAL_PROVIDER_OPS, NULL, &provider); ASSERT_EQ(ret, UMF_RESULT_SUCCESS); auto pool = wrapPoolUnique(createPoolChecked(umfProxyPoolOps(), provider, nullptr, @@ -184,13 +184,13 @@ INSTANTIATE_TEST_SUITE_P( &UMF_NULL_PROVIDER_OPS, nullptr, nullptr}, poolCreateExtParams{umfProxyPoolOps(), nullptr, - &MALLOC_PROVIDER_OPS, nullptr, + &BA_GLOBAL_PROVIDER_OPS, nullptr, nullptr})); INSTANTIATE_TEST_SUITE_P(mallocMultiPoolTest, umfMultiPoolTest, ::testing::Values(poolCreateExtParams{ - umfProxyPoolOps(), nullptr, &MALLOC_PROVIDER_OPS, - nullptr, nullptr})); + umfProxyPoolOps(), nullptr, + &BA_GLOBAL_PROVIDER_OPS, nullptr, nullptr})); INSTANTIATE_TEST_SUITE_P(umfPoolWithCreateFlagsTest, umfPoolWithCreateFlagsTest, ::testing::Values(0, diff --git a/test/pools/disjoint_pool.cpp b/test/pools/disjoint_pool.cpp index 09488c92b..5f048a7e6 100644 --- a/test/pools/disjoint_pool.cpp +++ b/test/pools/disjoint_pool.cpp @@ -148,7 +148,7 @@ auto defaultPoolConfig = poolConfig(); INSTANTIATE_TEST_SUITE_P(disjointPoolTests, umfPoolTest, ::testing::Values(poolCreateExtParams{ umfDisjointPoolOps(), (void *)&defaultPoolConfig, - &MALLOC_PROVIDER_OPS, nullptr, nullptr})); + &BA_GLOBAL_PROVIDER_OPS, nullptr, nullptr})); INSTANTIATE_TEST_SUITE_P( disjointPoolTests, umfMemTest, @@ -161,4 +161,4 @@ INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P(disjointMultiPoolTests, umfMultiPoolTest, ::testing::Values(poolCreateExtParams{ umfDisjointPoolOps(), (void *)&defaultPoolConfig, - &MALLOC_PROVIDER_OPS, nullptr, nullptr})); + &BA_GLOBAL_PROVIDER_OPS, nullptr, nullptr})); From b5c0512ba75f4b1bd5a979d2ab988445ec31626c Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 6 Nov 2024 15:37:58 +0100 Subject: [PATCH 254/352] Skip testing umf_test-disjointPool under helgrind Skip testing umf_test-disjointPool under helgrind, because of the assert in helgrind: Helgrind: hg_main.c:308 (lockN_acquire_reader): \ Assertion 'lk->kind == LK_rdwr' failed. Signed-off-by: Lukasz Dorau --- test/test_valgrind.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/test_valgrind.sh b/test/test_valgrind.sh index 262a86784..ae922f870 100755 --- a/test/test_valgrind.sh +++ b/test/test_valgrind.sh @@ -84,6 +84,14 @@ for test in $(ls -1 umf_test-*); do # skip tests incompatible with valgrind FILTER="" case $test in + umf_test-disjointPool) + if [ "$TOOL" = "helgrind" ]; then + # skip because of the assert in helgrind: + # Helgrind: hg_main.c:308 (lockN_acquire_reader): Assertion 'lk->kind == LK_rdwr' failed. + echo "- SKIPPED (helgrind only)" + continue; + fi + ;; umf_test-ipc_os_prov_*) echo "- SKIPPED" continue; # skip testing helper binaries used by the ipc_os_prov_* tests From f5478202aae2e11e3ccb70b9ab7a34d8917f780a Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Thu, 7 Nov 2024 09:31:03 +0100 Subject: [PATCH 255/352] =?UTF-8?q?Fix=20warning:=20passing=20argument=20d?= =?UTF-8?q?iscards=20=E2=80=98const=E2=80=99=20qualifier=20from=20pointer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix warning: warning: passing argument 4 of ‘cuda_copy’ discards ‘const’ qualifier \ from pointer target type [-Wdiscarded-qualifiers] Signed-off-by: Lukasz Dorau --- test/providers/ipc_cuda_prov_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/providers/ipc_cuda_prov_common.c b/test/providers/ipc_cuda_prov_common.c index fbcf8368d..ac00bb01b 100644 --- a/test/providers/ipc_cuda_prov_common.c +++ b/test/providers/ipc_cuda_prov_common.c @@ -16,7 +16,7 @@ void memcopy(void *dst, const void *src, size_t size, void *context) { cuda_memory_provider_params_t *cu_params = (cuda_memory_provider_params_t *)context; int ret = cuda_copy(cu_params->cuda_context_handle, - cu_params->cuda_device_handle, dst, src, size); + cu_params->cuda_device_handle, dst, (void *)src, size); if (ret != 0) { fprintf(stderr, "cuda_copy failed with error %d\n", ret); } From 1eac5690943d2cf65211f3760a89955ff414fdad Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Thu, 7 Nov 2024 13:49:59 +0100 Subject: [PATCH 256/352] Fix building the provider_file_memory_ipc test Signed-off-by: Lukasz Dorau --- test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 26c4b2d9d..99f963827 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -303,7 +303,7 @@ if(LINUX AND (NOT UMF_DISABLE_HWLOC)) # OS-specific functions are implemented LIBS ${UMF_UTILS_FOR_TEST}) add_umf_test( NAME provider_file_memory_ipc - SRCS provider_file_memory_ipc.cpp + SRCS provider_file_memory_ipc.cpp ${BA_SOURCES_FOR_TEST} LIBS ${UMF_UTILS_FOR_TEST} ${LIB_JEMALLOC_POOL}) # This test requires Linux-only file memory provider From 7760ebc83847be8271cdf729edb66b5793da1367 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Thu, 7 Nov 2024 14:36:35 +0100 Subject: [PATCH 257/352] Increase code coverage of Coarse provider Increase code coverage of Coarse provider: - add missing tests, - remove unreachable checks. Signed-off-by: Lukasz Dorau --- src/provider/provider_coarse.c | 109 ++++++--------------------------- test/provider_coarse.cpp | 35 +++++++++++ 2 files changed, 54 insertions(+), 90 deletions(-) diff --git a/src/provider/provider_coarse.c b/src/provider/provider_coarse.c index ca63664ef..ed7bb1cba 100644 --- a/src/provider/provider_coarse.c +++ b/src/provider/provider_coarse.c @@ -413,11 +413,9 @@ static block_t *free_blocks_rm_ge(struct ravl *free_blocks, size_t size, case CHECK_ALL_BLOCKS_OF_SIZE: block = node_list_rm_with_alignment(head_node, alignment); break; + // wrong value of check_blocks default: - LOG_DEBUG("wrong value of check_blocks"); - block = NULL; - assert(0); - break; + abort(); } if (head_node->head == NULL) { @@ -863,11 +861,7 @@ static umf_result_t coarse_memory_provider_free(void *provider, void *ptr, static umf_result_t coarse_memory_provider_initialize(void *params, void **provider) { - umf_result_t umf_result = UMF_RESULT_ERROR_UNKNOWN; - - if (provider == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } + assert(provider); if (params == NULL) { LOG_ERR("coarse provider parameters are missing"); @@ -931,17 +925,19 @@ static umf_result_t coarse_memory_provider_initialize(void *params, coarse_provider->disable_upstream_provider_free = false; } - umf_result = coarse_memory_provider_set_name(coarse_provider); + 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"); - umf_result = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; goto err_free_name; } @@ -949,7 +945,6 @@ static umf_result_t coarse_memory_provider_initialize(void *params, ravl_new_sized(coarse_ravl_comp, sizeof(ravl_data_t)); if (coarse_provider->free_blocks == NULL) { LOG_ERR("out of the host memory"); - umf_result = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; goto err_delete_ravl_upstream_blocks; } @@ -957,7 +952,6 @@ static umf_result_t coarse_memory_provider_initialize(void *params, ravl_new_sized(coarse_ravl_comp, sizeof(ravl_data_t)); if (coarse_provider->all_blocks == NULL) { LOG_ERR("out of the host memory"); - umf_result = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; goto err_delete_ravl_free_blocks; } @@ -966,6 +960,7 @@ static umf_result_t coarse_memory_provider_initialize(void *params, 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; } @@ -976,7 +971,6 @@ static umf_result_t coarse_memory_provider_initialize(void *params, coarse_memory_provider_alloc( coarse_provider, coarse_params->init_buffer_size, 0, &init_buffer); if (init_buffer == NULL) { - umf_result = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; goto err_destroy_mutex; } @@ -1069,11 +1063,6 @@ static void coarse_ravl_cb_rm_all_blocks_node(void *data, void *arg) { } static void coarse_memory_provider_finalize(void *provider) { - if (provider == NULL) { - assert(0); - return; - } - coarse_memory_provider_t *coarse_provider = (struct coarse_memory_provider_t *)provider; @@ -1199,21 +1188,16 @@ find_free_block(struct ravl *free_blocks, size_t size, size_t alignment, return free_blocks_rm_ge(free_blocks, size + alignment, 0, CHECK_ONLY_THE_FIRST_BLOCK); + // unknown memory allocation strategy default: - LOG_ERR("unknown memory allocation strategy"); - assert(0); - return NULL; + 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_SUCCESS; - - if (provider == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } + umf_result_t umf_result = UMF_RESULT_ERROR_UNKNOWN; if (resultPtr == NULL) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; @@ -1252,9 +1236,7 @@ static umf_result_t coarse_memory_provider_alloc(void *provider, size_t size, umf_result = create_aligned_block(coarse_provider, size, alignment, &curr); if (umf_result != UMF_RESULT_SUCCESS) { - if (utils_mutex_unlock(&coarse_provider->lock) != 0) { - LOG_ERR("unlocking the lock failed"); - } + utils_mutex_unlock(&coarse_provider->lock); return umf_result; } } @@ -1263,9 +1245,7 @@ static umf_result_t coarse_memory_provider_alloc(void *provider, size_t size, // Split the current block and put the new block after the one that we use. umf_result = split_current_block(coarse_provider, curr, size); if (umf_result != UMF_RESULT_SUCCESS) { - if (utils_mutex_unlock(&coarse_provider->lock) != 0) { - LOG_ERR("unlocking the lock failed"); - } + utils_mutex_unlock(&coarse_provider->lock); return umf_result; } @@ -1284,20 +1264,16 @@ static umf_result_t coarse_memory_provider_alloc(void *provider, size_t size, coarse_provider->used_size += size; assert(debug_check(coarse_provider)); - - if (utils_mutex_unlock(&coarse_provider->lock) != 0) { - LOG_ERR("unlocking the lock failed"); - return UMF_RESULT_ERROR_UNKNOWN; - } + 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"); - umf_result = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; goto err_unlock; } @@ -1305,7 +1281,6 @@ static umf_result_t coarse_memory_provider_alloc(void *provider, size_t size, alignment, resultPtr); if (*resultPtr == NULL) { LOG_ERR("out of memory - upstream memory provider allocation failed"); - umf_result = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; goto err_unlock; } @@ -1327,23 +1302,13 @@ static umf_result_t coarse_memory_provider_alloc(void *provider, size_t size, err_unlock: assert(debug_check(coarse_provider)); - - if (utils_mutex_unlock(&coarse_provider->lock) != 0) { - LOG_ERR("unlocking the lock failed"); - if (umf_result == UMF_RESULT_SUCCESS) { - umf_result = UMF_RESULT_ERROR_UNKNOWN; - } - } + utils_mutex_unlock(&coarse_provider->lock); return umf_result; } static umf_result_t coarse_memory_provider_free(void *provider, void *ptr, size_t bytes) { - if (provider == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - coarse_memory_provider_t *coarse_provider = (struct coarse_memory_provider_t *)provider; @@ -1398,11 +1363,7 @@ static umf_result_t coarse_memory_provider_free(void *provider, void *ptr, } assert(debug_check(coarse_provider)); - - if (utils_mutex_unlock(&coarse_provider->lock) != 0) { - LOG_ERR("unlocking the lock failed"); - return UMF_RESULT_ERROR_UNKNOWN; - } + utils_mutex_unlock(&coarse_provider->lock); return UMF_RESULT_SUCCESS; } @@ -1424,10 +1385,6 @@ static void coarse_memory_provider_get_last_native_error(void *provider, static umf_result_t coarse_memory_provider_get_min_page_size(void *provider, void *ptr, size_t *pageSize) { - if (provider == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - coarse_memory_provider_t *coarse_provider = (struct coarse_memory_provider_t *)provider; @@ -1443,10 +1400,6 @@ static umf_result_t coarse_memory_provider_get_min_page_size(void *provider, static umf_result_t coarse_memory_provider_get_recommended_page_size(void *provider, size_t size, size_t *pageSize) { - if (provider == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - coarse_memory_provider_t *coarse_provider = (struct coarse_memory_provider_t *)provider; @@ -1460,10 +1413,6 @@ coarse_memory_provider_get_recommended_page_size(void *provider, size_t size, } static const char *coarse_memory_provider_get_name(void *provider) { - if (provider == NULL) { - return COARSE_BASE_NAME; - } - coarse_memory_provider_t *coarse_provider = (struct coarse_memory_provider_t *)provider; @@ -1503,14 +1452,6 @@ static void ravl_cb_count_free(void *data, void *arg) { static umf_result_t coarse_memory_provider_get_stats(void *provider, coarse_memory_provider_stats_t *stats) { - if (provider == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - - if (stats == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - coarse_memory_provider_t *coarse_provider = (struct coarse_memory_provider_t *)provider; @@ -1628,13 +1569,7 @@ static umf_result_t coarse_memory_provider_allocation_split(void *provider, err_mutex_unlock: assert(debug_check(coarse_provider)); - - if (utils_mutex_unlock(&coarse_provider->lock) != 0) { - LOG_ERR("unlocking the lock failed"); - if (umf_result == UMF_RESULT_SUCCESS) { - umf_result = UMF_RESULT_ERROR_UNKNOWN; - } - } + utils_mutex_unlock(&coarse_provider->lock); return umf_result; } @@ -1731,13 +1666,7 @@ static umf_result_t coarse_memory_provider_allocation_merge(void *provider, err_mutex_unlock: assert(debug_check(coarse_provider)); - - if (utils_mutex_unlock(&coarse_provider->lock) != 0) { - LOG_ERR("unlocking the lock failed"); - if (umf_result == UMF_RESULT_SUCCESS) { - umf_result = UMF_RESULT_ERROR_UNKNOWN; - } - } + utils_mutex_unlock(&coarse_provider->lock); return umf_result; } diff --git a/test/provider_coarse.cpp b/test/provider_coarse.cpp index 29e30160d..c2de4c06a 100644 --- a/test/provider_coarse.cpp +++ b/test/provider_coarse.cpp @@ -70,6 +70,18 @@ TEST_F(test, coarseProvider_name_upstream) { 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); @@ -106,6 +118,18 @@ TEST_F(test, coarseProvider_name_no_upstream) { 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); @@ -122,6 +146,17 @@ TEST_P(CoarseWithMemoryStrategyTest, coarseProvider_null_stats) { 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) { From f04168cdec26eb3229f637c30240870ed6b98417 Mon Sep 17 00:00:00 2001 From: Patryk Kaminski Date: Tue, 2 Jul 2024 09:49:25 +0200 Subject: [PATCH 258/352] Add integer overflow tests --- .github/workflows/reusable_sanitizers.yml | 6 ++++++ test/poolFixtures.hpp | 5 +++++ test/provider_os_memory.cpp | 6 ++++++ .../provider_os_memory_multiple_numa_nodes.cpp | 18 ++++++++++++++++++ test/test_valgrind.sh | 3 +++ 5 files changed, 38 insertions(+) diff --git a/.github/workflows/reusable_sanitizers.yml b/.github/workflows/reusable_sanitizers.yml index 2c63ebd51..3acda6833 100644 --- a/.github/workflows/reusable_sanitizers.yml +++ b/.github/workflows/reusable_sanitizers.yml @@ -73,6 +73,9 @@ jobs: - name: Run tests working-directory: ${{env.BUILD_DIR}} + env: + ASAN_OPTIONS: allocator_may_return_null=1 + TSAN_OPTIONS: allocator_may_return_null=1 run: | ${{ matrix.compiler.cxx == 'icpx' && '. /opt/intel/oneapi/setvars.sh' || true }} ctest --output-on-failure @@ -141,4 +144,7 @@ jobs: - name: Run tests working-directory: ${{env.BUILD_DIR}} + env: + ASAN_OPTIONS: allocator_may_return_null=1 + TSAN_OPTIONS: allocator_may_return_null=1 run: ctest -C Debug --output-on-failure diff --git a/test/poolFixtures.hpp b/test/poolFixtures.hpp index 93d839391..e1c1cc722 100644 --- a/test/poolFixtures.hpp +++ b/test/poolFixtures.hpp @@ -451,4 +451,9 @@ TEST_P(umfPoolTest, realloc_compliance) { TEST_P(umfPoolTest, free_compliance) { free_compliance_test(pool.get()); } +TEST_P(umfPoolTest, allocMaxSize) { + auto *ptr = umfPoolMalloc(pool.get(), SIZE_MAX); + ASSERT_EQ(ptr, nullptr); +} + #endif /* UMF_TEST_POOL_FIXTURES_HPP */ diff --git a/test/provider_os_memory.cpp b/test/provider_os_memory.cpp index 734ebeec9..d0f24d617 100644 --- a/test/provider_os_memory.cpp +++ b/test/provider_os_memory.cpp @@ -260,6 +260,12 @@ TEST_P(umfProviderTest, alloc_WRONG_SIZE) { UMF_OS_RESULT_ERROR_ALLOC_FAILED); } +TEST_P(umfProviderTest, alloc_MAX_SIZE) { + test_alloc_failure(provider.get(), SIZE_MAX, 0, + UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC, + UMF_OS_RESULT_ERROR_ALLOC_FAILED); +} + // other positive tests TEST_P(umfProviderTest, get_min_page_size) { diff --git a/test/provider_os_memory_multiple_numa_nodes.cpp b/test/provider_os_memory_multiple_numa_nodes.cpp index 8c771a642..7f0a1401b 100644 --- a/test/provider_os_memory_multiple_numa_nodes.cpp +++ b/test/provider_os_memory_multiple_numa_nodes.cpp @@ -774,3 +774,21 @@ TEST_F(testNuma, checkModeInterleaveIllegalArgSet) { ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); ASSERT_EQ(os_memory_provider, nullptr); } + +// Interleave mode set with SIZE_MAX part size +TEST_F(testNuma, maxPartSize) { + std::vector numa_nodes = get_available_numa_nodes(); + + umf_os_memory_provider_params_t os_memory_provider_params = + UMF_OS_MEMORY_PROVIDER_PARAMS_TEST; + os_memory_provider_params.numa_mode = UMF_NUMA_MODE_INTERLEAVE; + os_memory_provider_params.part_size = SIZE_MAX; + os_memory_provider_params.numa_list = numa_nodes.data(); + os_memory_provider_params.numa_list_len = numa_nodes.size(); + + auto res = umfMemoryProviderCreate(umfOsMemoryProviderOps(), + &os_memory_provider_params, + &os_memory_provider); + ASSERT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT); + ASSERT_EQ(os_memory_provider, nullptr); +} diff --git a/test/test_valgrind.sh b/test/test_valgrind.sh index ae922f870..9f84cf0d3 100755 --- a/test/test_valgrind.sh +++ b/test/test_valgrind.sh @@ -125,6 +125,9 @@ for test in $(ls -1 umf_test-*); do umf_test-memspace_lowest_latency) FILTER='--gtest_filter="-*allocLocalMt*"' ;; + umf_test-memoryPool) + FILTER='--gtest_filter="-*allocMaxSize*"' + ;; esac [ "$FILTER" != "" ] && echo -n "($FILTER) " From b6c37039cf49f9e355f94737b563a9d22b63a768 Mon Sep 17 00:00:00 2001 From: Patryk Kaminski Date: Fri, 5 Jul 2024 08:16:57 +0200 Subject: [PATCH 259/352] Fix integer overflows --- src/base_alloc/base_alloc_global.c | 9 +++++++++ src/provider/provider_os_memory.c | 27 ++++++++++++++++++++++++--- test/common/provider.hpp | 4 ++++ 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/base_alloc/base_alloc_global.c b/src/base_alloc/base_alloc_global.c index ec6bc9fcb..fc3e476b0 100644 --- a/src/base_alloc/base_alloc_global.c +++ b/src/base_alloc/base_alloc_global.c @@ -155,10 +155,19 @@ void *umf_ba_global_aligned_alloc(size_t size, size_t alignment) { return NULL; } + if (size > SIZE_MAX - ALLOC_METADATA_SIZE) { + LOG_ERR("base_alloc: allocation size (%zu) too large.", size); + return NULL; + } + // for metadata size += ALLOC_METADATA_SIZE; if (alignment > ALLOC_METADATA_SIZE) { + if (size > SIZE_MAX - alignment) { + LOG_ERR("base_alloc: allocation size (%zu) too large.", size); + return NULL; + } size += alignment; } diff --git a/src/provider/provider_os_memory.c b/src/provider/provider_os_memory.c index 87dd08cf7..68d1678bf 100644 --- a/src/provider/provider_os_memory.c +++ b/src/provider/provider_os_memory.c @@ -341,6 +341,22 @@ validatePartitions(umf_os_memory_provider_params_t *params) { return UMF_RESULT_SUCCESS; } +static umf_result_t os_get_min_page_size(void *provider, void *ptr, + size_t *page_size); + +static umf_result_t validatePartSize(os_memory_provider_t *provider, + umf_os_memory_provider_params_t *params) { + size_t page_size; + os_get_min_page_size(provider, NULL, &page_size); + if (ALIGN_UP(params->part_size, page_size) < params->part_size) { + LOG_ERR("partition size (%zu) is too big, cannot align with a page " + "size (%zu)", + params->part_size, page_size); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + return UMF_RESULT_SUCCESS; +} + static void free_bitmaps(os_memory_provider_t *provider) { for (unsigned i = 0; i < provider->nodeset_len; i++) { hwloc_bitmap_free(provider->nodeset[i]); @@ -427,6 +443,14 @@ static umf_result_t translate_params(umf_os_memory_provider_params_t *in_params, return result; } + if (in_params->numa_mode == UMF_NUMA_MODE_INTERLEAVE) { + result = validatePartSize(provider, in_params); + if (result != UMF_RESULT_SUCCESS) { + LOG_ERR("incorrect partition size: %zu", in_params->part_size); + return result; + } + } + int is_dedicated_node_bind = dedicated_node_bind(in_params); provider->numa_policy = translate_numa_mode(in_params->numa_mode, is_dedicated_node_bind); @@ -574,9 +598,6 @@ static void os_finalize(void *provider) { umf_ba_global_free(os_provider); } -static umf_result_t os_get_min_page_size(void *provider, void *ptr, - size_t *page_size); - // TODO: this function should be re-enabled when CTL is implemented #if 0 static void print_numa_nodes(os_memory_provider_t *os_provider, void *addr, diff --git a/test/common/provider.hpp b/test/common/provider.hpp index 11c7056db..dec5ddbee 100644 --- a/test/common/provider.hpp +++ b/test/common/provider.hpp @@ -105,6 +105,10 @@ struct provider_ba_global : public provider_base_t { align = 8; } + if (size > SIZE_MAX - align + 1) { + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + // aligned_malloc returns a valid pointer despite not meeting the // requirement of 'size' being multiple of 'align' even though the // documentation says that it has to. AddressSanitizer returns an From 4859b62f676e8621edff9874b3853fff6398e44e Mon Sep 17 00:00:00 2001 From: Patryk Kaminski Date: Mon, 29 Jul 2024 10:49:42 +0200 Subject: [PATCH 260/352] Align values up safely Co-authored-by: lukasz.plewa@intel.com --- src/base_alloc/base_alloc.c | 10 ++++++-- src/base_alloc/base_alloc_global.c | 8 +++++-- src/base_alloc/base_alloc_linear.c | 19 ++++++++++++--- src/provider/provider_os_memory.c | 14 ++++++++--- src/proxy_lib/proxy_lib.c | 2 +- src/utils/utils_common.h | 4 ++++ test/common/provider.hpp | 9 ++++--- test/common/test_helpers.h | 5 +--- test/supp/helgrind-umf_test-disjointPool.supp | 24 +++++++++++++++++++ 9 files changed, 75 insertions(+), 20 deletions(-) diff --git a/src/base_alloc/base_alloc.c b/src/base_alloc/base_alloc.c index 7a98684c6..209ace7fe 100644 --- a/src/base_alloc/base_alloc.c +++ b/src/base_alloc/base_alloc.c @@ -134,7 +134,10 @@ static void *ba_os_alloc_annotated(size_t pool_size) { } umf_ba_pool_t *umf_ba_create(size_t size) { - size_t chunk_size = ALIGN_UP(size, MEMORY_ALIGNMENT); + size_t chunk_size = ALIGN_UP_SAFE(size, MEMORY_ALIGNMENT); + if (chunk_size == 0) { + return NULL; + } size_t mutex_size = ALIGN_UP(utils_mutex_get_size(), MEMORY_ALIGNMENT); size_t metadata_size = sizeof(struct umf_ba_main_pool_meta_t); @@ -144,7 +147,10 @@ umf_ba_pool_t *umf_ba_create(size_t size) { pool_size = MINIMUM_POOL_SIZE; } - pool_size = ALIGN_UP(pool_size, ba_os_get_page_size()); + pool_size = ALIGN_UP_SAFE(pool_size, ba_os_get_page_size()); + if (pool_size == 0) { + return NULL; + } umf_ba_pool_t *pool = (umf_ba_pool_t *)ba_os_alloc_annotated(pool_size); if (!pool) { diff --git a/src/base_alloc/base_alloc_global.c b/src/base_alloc/base_alloc_global.c index fc3e476b0..11d88b731 100644 --- a/src/base_alloc/base_alloc_global.c +++ b/src/base_alloc/base_alloc_global.c @@ -96,8 +96,12 @@ static void *add_metadata_and_align(void *ptr, size_t size, size_t alignment) { if (alignment <= ALLOC_METADATA_SIZE) { user_ptr = (void *)((uintptr_t)ptr + ALLOC_METADATA_SIZE); } else { - user_ptr = - (void *)ALIGN_UP((uintptr_t)ptr + ALLOC_METADATA_SIZE, alignment); + user_ptr = (void *)ALIGN_UP_SAFE((uintptr_t)ptr + ALLOC_METADATA_SIZE, + alignment); + if (!user_ptr) { + LOG_ERR("base_alloc: pointer alignment overflow"); + return NULL; + } } size_t ptr_offset_from_original = (uintptr_t)user_ptr - (uintptr_t)ptr; diff --git a/src/base_alloc/base_alloc_linear.c b/src/base_alloc/base_alloc_linear.c index 8773e5cab..a35a6c243 100644 --- a/src/base_alloc/base_alloc_linear.c +++ b/src/base_alloc/base_alloc_linear.c @@ -88,7 +88,11 @@ umf_ba_linear_pool_t *umf_ba_linear_create(size_t pool_size) { pool_size = MINIMUM_LINEAR_POOL_SIZE; } - pool_size = ALIGN_UP(pool_size, ba_os_get_page_size()); + pool_size = ALIGN_UP_SAFE(pool_size, ba_os_get_page_size()); + if (pool_size == 0) { + LOG_ERR("pool_size page alignment overflow"); + return NULL; + } umf_ba_linear_pool_t *pool = (umf_ba_linear_pool_t *)ba_os_alloc(pool_size); if (!pool) { @@ -122,7 +126,11 @@ void *umf_ba_linear_alloc(umf_ba_linear_pool_t *pool, size_t size) { if (size == 0) { return NULL; } - size_t aligned_size = ALIGN_UP(size, MEMORY_ALIGNMENT); + size_t aligned_size = ALIGN_UP_SAFE(size, MEMORY_ALIGNMENT); + if (aligned_size == 0) { + LOG_ERR("size alignment overflow"); + return NULL; + } utils_mutex_lock(&pool->metadata.lock); if (pool->metadata.size_left < aligned_size) { size_t pool_size = MINIMUM_LINEAR_POOL_SIZE; @@ -130,7 +138,12 @@ void *umf_ba_linear_alloc(umf_ba_linear_pool_t *pool, size_t size) { pool_size - offsetof(umf_ba_next_linear_pool_t, data); if (usable_size < aligned_size) { pool_size += aligned_size - usable_size; - pool_size = ALIGN_UP(pool_size, ba_os_get_page_size()); + pool_size = ALIGN_UP_SAFE(pool_size, ba_os_get_page_size()); + if (pool_size == 0) { + utils_mutex_unlock(&pool->metadata.lock); + LOG_ERR("pool_size page alignment overflow"); + return NULL; + } } assert(pool_size - offsetof(umf_ba_next_linear_pool_t, data) >= diff --git a/src/provider/provider_os_memory.c b/src/provider/provider_os_memory.c index 68d1678bf..8c5a9dc46 100644 --- a/src/provider/provider_os_memory.c +++ b/src/provider/provider_os_memory.c @@ -834,12 +834,12 @@ static membind_t membindFirst(os_memory_provider_t *provider, void *addr, membind_t membind; memset(&membind, 0, sizeof(membind)); - membind.alloc_size = ALIGN_UP(size, page_size); + membind.alloc_size = size; membind.page_size = page_size; membind.addr = addr; membind.pages = membind.alloc_size / membind.page_size; if (provider->nodeset_len == 1) { - membind.bind_size = ALIGN_UP(size, membind.page_size); + membind.bind_size = size; membind.bitmap = provider->nodeset[0]; return membind; } @@ -945,7 +945,15 @@ static umf_result_t os_alloc(void *provider, size_t size, size_t alignment, // Bind memory to NUMA nodes if numa_policy is other than DEFAULT if (os_provider->numa_policy != HWLOC_MEMBIND_DEFAULT) { - membind_t membind = membindFirst(os_provider, addr, size, page_size); + size_t first_size = ALIGN_UP_SAFE(size, page_size); + if (first_size == 0) { + LOG_ERR("size is too big, page align failed"); + (void)utils_munmap(addr, size); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + membind_t membind = + membindFirst(os_provider, addr, first_size, page_size); if (membind.bitmap == NULL) { goto err_unmap; } diff --git a/src/proxy_lib/proxy_lib.c b/src/proxy_lib/proxy_lib.c index ca8d69315..c654655ba 100644 --- a/src/proxy_lib/proxy_lib.c +++ b/src/proxy_lib/proxy_lib.c @@ -231,7 +231,7 @@ static inline void *ba_leak_realloc(void *ptr, size_t size, size_t max_size) { static inline void *ba_leak_aligned_alloc(size_t alignment, size_t size) { ba_leak_init_once(); void *ptr = umf_ba_linear_alloc(Base_alloc_leak, size + alignment); - return (void *)ALIGN_UP((uintptr_t)ptr, alignment); + return (void *)ALIGN_UP_SAFE((uintptr_t)ptr, alignment); } static inline int ba_leak_free(void *ptr) { diff --git a/src/utils/utils_common.h b/src/utils/utils_common.h index 25a840d97..eebc461f6 100644 --- a/src/utils/utils_common.h +++ b/src/utils/utils_common.h @@ -40,6 +40,10 @@ typedef enum umf_purge_advise_t { #define IS_NOT_ALIGNED(value, align) \ ((align != 0 && (((value) & ((align)-1)) != 0))) #define ALIGN_UP(value, align) (((value) + (align)-1) & ~((align)-1)) +#define ALIGN_UP_SAFE(value, align) \ + (((align) == 0) \ + ? (value) \ + : (((value) + (align)-1) < (value) ? 0 : ALIGN_UP((value), (align)))) #define ALIGN_DOWN(value, align) ((value) & ~((align)-1)) #define ASSERT_IS_ALIGNED(value, align) \ DO_WHILE_EXPRS(assert(IS_ALIGNED(value, align))) diff --git a/test/common/provider.hpp b/test/common/provider.hpp index dec5ddbee..148f34dc8 100644 --- a/test/common/provider.hpp +++ b/test/common/provider.hpp @@ -105,15 +105,14 @@ struct provider_ba_global : public provider_base_t { align = 8; } - if (size > SIZE_MAX - align + 1) { - return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; - } - // aligned_malloc returns a valid pointer despite not meeting the // requirement of 'size' being multiple of 'align' even though the // documentation says that it has to. AddressSanitizer returns an // error because of this issue. - size_t aligned_size = ALIGN_UP(size, align); + size_t aligned_size = ALIGN_UP_SAFE(size, align); + if (aligned_size == 0) { + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } *ptr = umf_ba_global_aligned_alloc(aligned_size, align); diff --git a/test/common/test_helpers.h b/test/common/test_helpers.h index 4a581bc4d..494528b57 100644 --- a/test/common/test_helpers.h +++ b/test/common/test_helpers.h @@ -14,6 +14,7 @@ #include #include "provider_trace.h" +#include "utils_common.h" #ifdef __cplusplus extern "C" { @@ -22,10 +23,6 @@ extern "C" { // Needed for CI #define TEST_SKIP_ERROR_CODE 125 -#ifndef ALIGN_UP -#define ALIGN_UP(value, align) (((value) + (align)-1) & ~((align)-1)) -#endif - int bufferIsFilledWithChar(void *ptr, size_t size, char c); int buffersHaveSameContent(void *first, void *second, size_t size); diff --git a/test/supp/helgrind-umf_test-disjointPool.supp b/test/supp/helgrind-umf_test-disjointPool.supp index 917237d7e..3ada32736 100644 --- a/test/supp/helgrind-umf_test-disjointPool.supp +++ b/test/supp/helgrind-umf_test-disjointPool.supp @@ -27,3 +27,27 @@ fun:*gthread_mutex_unlock*pthread_mutex_t ... } + +{ + Incompatibility with helgrind's implementation ("pthread_rwlock_{rd,rw}lock with a pthread_mutex_t* argument") + Helgrind:Misc + obj:*vgpreload_helgrind-amd64-linux.so + fun:*glibcxx_rwlock_wrlock*pthread_rwlock_t + ... +} + +{ + Incompatibility with helgrind's implementation ("pthread_rwlock_unlock with a pthread_mutex_t* argument") + Helgrind:Misc + obj:*vgpreload_helgrind-amd64-linux.so + fun:*glibcxx_rwlock_unlock*pthread_rwlock_t + ... +} + +{ + Incompatibility with helgrind's implementation ("pthread_rwlock_{rd,rw}lock with a pthread_mutex_t* argument") + Helgrind:Misc + obj:*vgpreload_helgrind-amd64-linux.so + fun:*glibcxx_rwlock_rdlock*pthread_rwlock_t* + ... +} From 0d64d11b2e19aef40d970ada10fffd69cbeb2c55 Mon Sep 17 00:00:00 2001 From: Rafal Rudnicki Date: Wed, 2 Oct 2024 12:32:07 +0200 Subject: [PATCH 261/352] enable tracker in ProxyLib by default --- src/provider/provider_tracking.c | 17 +++++++++++------ src/proxy_lib/proxy_lib.c | 7 ++----- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/provider/provider_tracking.c b/src/provider/provider_tracking.c index 70f63f937..d058af271 100644 --- a/src/provider/provider_tracking.c +++ b/src/provider/provider_tracking.c @@ -48,13 +48,14 @@ static umf_result_t umfMemoryTrackerAdd(umf_memory_tracker_handle_t hTracker, int ret = critnib_insert(hTracker->map, (uintptr_t)ptr, value, 0); if (ret == 0) { - LOG_DEBUG("memory region is added, tracker=%p, ptr=%p, size=%zu", - (void *)hTracker, ptr, size); + LOG_DEBUG( + "memory region is added, tracker=%p, ptr=%p, pool=%p, size=%zu", + (void *)hTracker, ptr, (void *)pool, size); return UMF_RESULT_SUCCESS; } - LOG_ERR("failed to insert tracker value, ret=%d, ptr=%p, size=%zu", ret, - ptr, size); + LOG_ERR("failed to insert tracker value, ret=%d, ptr=%p, pool=%p, size=%zu", + ret, ptr, (void *)pool, size); umf_ba_free(hTracker->tracker_allocator, value); @@ -303,8 +304,8 @@ static umf_result_t trackingAllocationMerge(void *hProvider, void *lowPtr, ret = umfMemoryProviderAllocationMerge(provider->hUpstream, lowPtr, highPtr, totalSize); if (ret != UMF_RESULT_SUCCESS) { - LOG_ERR("upstream provider failed to merge regions"); - goto err; + LOG_WARN("upstream provider failed to merge regions"); + goto not_merged; } // We'll have a duplicate entry for the range [highPtr, highValue->size] but this is fine, @@ -329,7 +330,11 @@ static umf_result_t trackingAllocationMerge(void *hProvider, void *lowPtr, return UMF_RESULT_SUCCESS; err: + assert(0); + +not_merged: utils_mutex_unlock(&provider->hTracker->splitMergeMutex); + err_lock: umf_ba_free(provider->hTracker->tracker_allocator, mergedValue); return ret; diff --git a/src/proxy_lib/proxy_lib.c b/src/proxy_lib/proxy_lib.c index ca8d69315..2730b9f17 100644 --- a/src/proxy_lib/proxy_lib.c +++ b/src/proxy_lib/proxy_lib.c @@ -124,8 +124,6 @@ void proxy_lib_create_common(void) { } else if (utils_env_var_has_str("UMF_PROXY", "page.disposition=shared-shm")) { - LOG_DEBUG("proxy_lib: using the MAP_SHARED visibility mode with the " - "named shared memory"); os_params.visibility = UMF_MEM_MAP_SHARED; memset(shm_name, 0, NAME_MAX); @@ -145,9 +143,8 @@ void proxy_lib_create_common(void) { exit(-1); } - umf_result = - umfPoolCreate(umfPoolManagerOps(), OS_memory_provider, NULL, - UMF_POOL_CREATE_FLAG_DISABLE_TRACKING, &Proxy_pool); + umf_result = umfPoolCreate(umfPoolManagerOps(), OS_memory_provider, NULL, 0, + &Proxy_pool); if (umf_result != UMF_RESULT_SUCCESS) { LOG_ERR("creating UMF pool manager failed"); exit(-1); From 57b96f9aa30031e7a0d6a2d240c0fdd0913f0847 Mon Sep 17 00:00:00 2001 From: Rafal Rudnicki Date: Wed, 2 Oct 2024 13:09:21 +0200 Subject: [PATCH 262/352] add IPC test with proxy lib --- CMakeLists.txt | 10 +- src/CMakeLists.txt | 4 +- test/CMakeLists.txt | 17 ++- test/ipc_os_prov_proxy.c | 256 ++++++++++++++++++++++++++++++++++++++ test/ipc_os_prov_proxy.sh | 26 ++++ 5 files changed, 305 insertions(+), 8 deletions(-) create mode 100644 test/ipc_os_prov_proxy.c create mode 100755 test/ipc_os_prov_proxy.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index b0ab6ac64..eb52a80dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -432,8 +432,16 @@ if(WINDOWS) ) endif() endif() + # set UMF_PROXY_LIB_ENABLED -if(UMF_PROXY_LIB_BASED_ON_POOL STREQUAL SCALABLE) +if(UMF_LINK_HWLOC_STATICALLY) + message( + STATUS + "Disabling the proxy library, because HWLOC is set to link statically which is not supported" + ) +elseif(UMF_DISABLE_HWLOC) + message(STATUS "Disabling the proxy library, because HWLOC is disabled") +elseif(UMF_PROXY_LIB_BASED_ON_POOL STREQUAL SCALABLE) if(UMF_POOL_SCALABLE_ENABLED) set(UMF_PROXY_LIB_ENABLED ON) set(PROXY_LIB_USES_SCALABLE_POOL ON) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9fabe2a08..7078d629f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -195,8 +195,6 @@ install(TARGETS umf EXPORT ${PROJECT_NAME}-targets) add_subdirectory(pool) -if(UMF_PROXY_LIB_ENABLED - AND NOT UMF_LINK_HWLOC_STATICALLY - AND NOT UMF_DISABLE_HWLOC) +if(UMF_PROXY_LIB_ENABLED) add_subdirectory(proxy_lib) endif() diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 99f963827..df17d9b2c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -408,10 +408,7 @@ add_umf_test( LIBS ${UMF_UTILS_FOR_TEST}) # tests for the proxy library -if(UMF_PROXY_LIB_ENABLED - AND UMF_BUILD_SHARED_LIBRARY - AND NOT UMF_DISABLE_HWLOC - AND NOT UMF_LINK_HWLOC_STATICALLY) +if(UMF_PROXY_LIB_ENABLED AND UMF_BUILD_SHARED_LIBRARY) add_umf_test( NAME proxy_lib_basic SRCS ${BA_SOURCES_FOR_TEST} test_proxy_lib.cpp @@ -486,6 +483,18 @@ if(LINUX) add_umf_ipc_test(TEST ipc_os_prov_anon_fd) add_umf_ipc_test(TEST ipc_os_prov_shm) + if(UMF_PROXY_LIB_ENABLED AND UMF_BUILD_SHARED_LIBRARY) + build_umf_test( + NAME + ipc_os_prov_proxy + SRCS + ipc_os_prov_proxy.c + common/ipc_common.c + LIBS + ${UMF_UTILS_FOR_TEST}) + add_umf_ipc_test(TEST ipc_os_prov_proxy) + endif() + build_umf_test( NAME ipc_devdax_prov_consumer diff --git a/test/ipc_os_prov_proxy.c b/test/ipc_os_prov_proxy.c new file mode 100644 index 000000000..a17518658 --- /dev/null +++ b/test/ipc_os_prov_proxy.c @@ -0,0 +1,256 @@ +/* + * Copyright (C) 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 +#include + +#include + +#include "ipc_common.h" +#include "utils_load_library.h" + +umf_result_t (*pfnGetIPCHandle)(const void *ptr, umf_ipc_handle_t *umfIPCHandle, + size_t *size); +umf_result_t (*pfnPutIPCHandle)(umf_ipc_handle_t umfIPCHandle); + +// This is a test for a scenario where a user process is started using the +// LD_PRELOAD with the UMF Proxy Lib and this process uses UMF by loading +// libumf.so at runtime. +// In this test, we expect that all allocations made by the process will be +// handled by UMF in the Proxy Lib and added to the UMF tracker so that they +// can be used later in the UMF IPC API. +int main(int argc, char *argv[]) { + int ret = 0; + umf_result_t umf_result = UMF_RESULT_ERROR_UNKNOWN; + int producer_socket = -1; + const size_t MSG_SIZE = 2048; + char consumer_message[MSG_SIZE]; + + if (argc < 2) { + fprintf(stderr, "usage: %s [shm_name]\n", argv[0]); + return -1; + } + + int port = atoi(argv[1]); + + int fd = open("/proc/self/maps", O_RDONLY); + if (fd == -1) { + return -1; + } + + // read the "/proc/self/maps" file until the "libumf_proxy.so" of the maps + // is found or EOF is reached. + const size_t SIZE_BUF = 8192; + char buf[SIZE_BUF]; + ssize_t nbytes = 1; + char *found = NULL; + while (nbytes > 0 && found == NULL) { + memset(buf, 0, SIZE_BUF); // erase previous data + nbytes = read(fd, buf, SIZE_BUF); + if (nbytes <= 0) { + break; + } + found = strstr(buf, "libumf_proxy.so"); + } + (void)close(fd); + + if (found == NULL) { + fprintf( + stderr, + "test binary not run under LD_PRELOAD with \"libumf_proxy.so\"\n"); + return -1; + } + + // open the UMF library and get umfGetIPCHandle() function + const char *umf_lib_name = "libumf.so"; + void *umf_lib_handle = utils_open_library(umf_lib_name, 0); + if (umf_lib_handle == NULL) { + fprintf(stderr, "utils_open_library: UMF library not found (%s)\n", + umf_lib_name); + return -1; + } + + *(void **)&pfnGetIPCHandle = + utils_get_symbol_addr(umf_lib_handle, "umfGetIPCHandle", umf_lib_name); + if (pfnGetIPCHandle == NULL) { + ret = -1; + goto err_close_lib; + } + + *(void **)&pfnPutIPCHandle = + utils_get_symbol_addr(umf_lib_handle, "umfPutIPCHandle", umf_lib_name); + if (pfnPutIPCHandle == NULL) { + ret = -1; + goto err_close_lib; + } + + // create simple allocation - it should be added to the UMF tracker if the + // process was launched under UMF Proxy Lib + size_t size = 2137; + void *ptr = malloc(size); + if (ptr == NULL) { + fprintf(stderr, "malloc() failed!\n"); + ret = -1; + goto err_close_lib; + } + + fprintf(stderr, "Allocated memory - %zu\n", size); + size_t val = 144; + size_t expected_val = val / 2; + *(size_t *)ptr = val; + + // get IPC handle of the allocation + umf_ipc_handle_t ipc_handle = NULL; + size_t ipc_handle_size = 0; + umf_result_t res = pfnGetIPCHandle(ptr, &ipc_handle, &ipc_handle_size); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "pfnGetIPCHandle() failed!\n"); + ret = -1; + goto err_free_mem; + } + + // check if we got valid data + if (ipc_handle == NULL || ipc_handle_size == 0) { + fprintf(stderr, "pfnGetIPCHandle() couldn't find the handle data!\n"); + ret = -1; + goto err_free_mem; + } + + fprintf(stderr, "Got IPCHandle for memory - %p | size - %zu\n", + (void *)ipc_handle, ipc_handle_size); + + producer_socket = producer_connect(port); + if (producer_socket < 0) { + goto err_PutIPCHandle; + } + + // send the ipc_handle_size to the consumer + ssize_t len = + send(producer_socket, &ipc_handle_size, sizeof(ipc_handle_size), 0); + if (len < 0) { + fprintf(stderr, "[producer] ERROR: unable to send the ipc_handle_size " + "to the consumer\n"); + goto err_close_producer_socket; + } + + fprintf(stderr, + "[producer] Sent the size of the IPC handle (%zu) to the consumer " + "(sent %zu bytes)\n", + ipc_handle_size, len); + + // zero the consumer_message buffer + memset(consumer_message, 0, sizeof(consumer_message)); + + // receive the consumer's confirmation - IPC handle size + len = recv(producer_socket, consumer_message, sizeof(consumer_message), 0); + if (len < 0) { + fprintf(stderr, "[producer] ERROR: error while receiving the " + "confirmation from the consumer\n"); + goto err_close_producer_socket; + } + + size_t conf_IPC_handle_size = *(size_t *)consumer_message; + if (conf_IPC_handle_size == ipc_handle_size) { + fprintf(stderr, + "[producer] Received the correct confirmation (%zu) from the " + "consumer (%zu bytes)\n", + conf_IPC_handle_size, len); + } else { + fprintf(stderr, + "[producer] Received an INCORRECT confirmation (%zu) from the " + "consumer (%zu bytes)\n", + conf_IPC_handle_size, len); + goto err_close_producer_socket; + } + + // send the ipc_handle of ipc_handle_size to the consumer + if (send(producer_socket, ipc_handle, ipc_handle_size, 0) < 0) { + fprintf(stderr, "[producer] ERROR: unable to send the ipc_handle to " + "the consumer\n"); + goto err_close_producer_socket; + } + + fprintf(stderr, + "[producer] Sent the IPC handle to the consumer (%zu bytes)\n", + ipc_handle_size); + + // zero the consumer_message buffer + memset(consumer_message, 0, sizeof(consumer_message)); + + // receive the consumer's response + if (recv(producer_socket, consumer_message, sizeof(consumer_message) - 1, + 0) < 0) { + fprintf( + stderr, + "[producer] ERROR: error while receiving the consumer's message\n"); + goto err_close_producer_socket; + } + + fprintf(stderr, "[producer] Received the consumer's response: \"%s\"\n", + consumer_message); + + if (strncmp(consumer_message, "SKIP", 5 /* length of "SKIP" + 1 */) == 0) { + fprintf(stderr, "[producer] SKIP: received the 'SKIP' response from " + "consumer, skipping ...\n"); + ret = 1; + goto err_close_producer_socket; + } + + // read a new value - the expected correct value val / 2 + volatile unsigned long long new_val = *(unsigned long long *)ptr; + if (new_val == expected_val) { + ret = 0; // got the correct value - success! + fprintf( + stderr, + "[producer] The consumer wrote the correct value (the old one / 2) " + "to my shared memory: %llu\n", + new_val); + } else { + fprintf( + stderr, + "[producer] ERROR: The consumer did NOT write the correct value " + "(the old one / 2 = %llu) to my shared memory: %llu\n", + expected_val, new_val); + } + +err_close_producer_socket: + close(producer_socket); + +err_PutIPCHandle: + umf_result = pfnPutIPCHandle(ipc_handle); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "[producer] ERROR: putting the IPC handle failed\n"); + } + + fprintf(stderr, "[producer] Put the IPC handle\n"); + + if (ret == 0) { + fprintf(stderr, "[producer] Shutting down (status OK) ...\n"); + } else if (ret == 1) { + fprintf(stderr, "[producer] Shutting down (status SKIP) ...\n"); + ret = 0; + } else { + fprintf(stderr, "[producer] Shutting down (status ERROR) ...\n"); + } + + return ret; + +err_free_mem: + free(ptr); + +err_close_lib: + utils_close_library(umf_lib_handle); + + return ret; +} diff --git a/test/ipc_os_prov_proxy.sh b/test/ipc_os_prov_proxy.sh new file mode 100755 index 000000000..86b95a235 --- /dev/null +++ b/test/ipc_os_prov_proxy.sh @@ -0,0 +1,26 @@ +# +# Copyright (C) 2024 Intel Corporation +# +# Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +#!/bin/bash + +set -e + +UMF_LOG_VAL="level:debug;flush:debug;output:stderr;pid:yes" +UMF_PROXY_VAL="page.disposition=shared-shm" +LD_PRELOAD_VAL="../lib/libumf_proxy.so" + +# port should be a number from the range <1024, 65535> +PORT=$(( 1024 + ( $$ % ( 65535 - 1024 )))) + +echo "Starting CONSUMER on port $PORT ..." +UMF_LOG=$UMF_LOG_VAL ./umf_test-ipc_os_prov_consumer $PORT & + +echo "Waiting 1 sec ..." +sleep 1 + +echo "Starting ipc_os_prov_proxy PRODUCER on port $PORT ..." +LD_PRELOAD=$LD_PRELOAD_VAL UMF_LOG=$UMF_LOG_VAL UMF_PROXY=$UMF_PROXY_VAL ./umf_test-ipc_os_prov_proxy $PORT From 62d7b069172c9c323a1a27df1fa633227b6e8bd6 Mon Sep 17 00:00:00 2001 From: Rafal Rudnicki Date: Sat, 19 Oct 2024 14:10:35 +0200 Subject: [PATCH 263/352] enable Proxy with static HWLOC --- .github/workflows/reusable_basic.yml | 2 +- CMakeLists.txt | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/.github/workflows/reusable_basic.yml b/.github/workflows/reusable_basic.yml index 3b5fdbbf7..8ae0d576a 100644 --- a/.github/workflows/reusable_basic.yml +++ b/.github/workflows/reusable_basic.yml @@ -210,7 +210,7 @@ jobs: --build-type ${{matrix.build_type}} --disjoint-pool --jemalloc-pool - ${{ matrix.install_tbb == 'ON' && matrix.disable_hwloc != 'ON' && matrix.link_hwloc_statically != 'ON' && '--proxy' || '' }} + ${{ matrix.install_tbb == 'ON' && matrix.disable_hwloc != 'ON' && '--proxy' || '' }} --umf-version ${{env.UMF_VERSION}} ${{ matrix.shared_library == 'ON' && '--shared-library' || '' }} diff --git a/CMakeLists.txt b/CMakeLists.txt index eb52a80dd..cc87f50de 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -434,12 +434,7 @@ if(WINDOWS) endif() # set UMF_PROXY_LIB_ENABLED -if(UMF_LINK_HWLOC_STATICALLY) - message( - STATUS - "Disabling the proxy library, because HWLOC is set to link statically which is not supported" - ) -elseif(UMF_DISABLE_HWLOC) +if(UMF_DISABLE_HWLOC) message(STATUS "Disabling the proxy library, because HWLOC is disabled") elseif(UMF_PROXY_LIB_BASED_ON_POOL STREQUAL SCALABLE) if(UMF_POOL_SCALABLE_ENABLED) From 05ddc128def9e82012372cf5023c95dcfd2d77c0 Mon Sep 17 00:00:00 2001 From: Rafal Rudnicki Date: Mon, 28 Oct 2024 16:18:13 +0100 Subject: [PATCH 264/352] disable Proxy Lib when UMF is build as static lib --- .github/workflows/reusable_basic.yml | 6 +++--- CMakeLists.txt | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/reusable_basic.yml b/.github/workflows/reusable_basic.yml index 8ae0d576a..807fd14f0 100644 --- a/.github/workflows/reusable_basic.yml +++ b/.github/workflows/reusable_basic.yml @@ -210,7 +210,7 @@ jobs: --build-type ${{matrix.build_type}} --disjoint-pool --jemalloc-pool - ${{ matrix.install_tbb == 'ON' && matrix.disable_hwloc != 'ON' && '--proxy' || '' }} + ${{ matrix.install_tbb == 'ON' && matrix.disable_hwloc != 'ON' && matrix.shared_library == 'ON' && '--proxy' || '' }} --umf-version ${{env.UMF_VERSION}} ${{ matrix.shared_library == 'ON' && '--shared-library' || '' }} @@ -300,7 +300,7 @@ jobs: --build-type ${{matrix.build_type}} --disjoint-pool --jemalloc-pool - --proxy + ${{matrix.shared_library == 'ON' && '--proxy' || '' }} --umf-version ${{env.UMF_VERSION}} ${{ matrix.shared_library == 'ON' && '--shared-library' || ''}} @@ -310,7 +310,7 @@ jobs: shell: pwsh - name: check /DEPENDENTLOADFLAG in umf_proxy.dll - if: ${{matrix.compiler.cxx == 'cl'}} + if: ${{matrix.shared_library == 'ON' && matrix.compiler.cxx == 'cl'}} run: ${{github.workspace}}/.github/scripts/check_dll_flags.ps1 ${{env.BUILD_DIR}}/src/proxy_lib/${{matrix.build_type}}/umf_proxy.dll shell: pwsh diff --git a/CMakeLists.txt b/CMakeLists.txt index cc87f50de..aef1ee16b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -436,6 +436,12 @@ endif() # set UMF_PROXY_LIB_ENABLED if(UMF_DISABLE_HWLOC) message(STATUS "Disabling the proxy library, because HWLOC is disabled") +elseif(NOT UMF_BUILD_SHARED_LIBRARY) + # TODO enable this scenario + message( + STATUS + "Disabling the proxy library, because UMF is built as static library" + ) elseif(UMF_PROXY_LIB_BASED_ON_POOL STREQUAL SCALABLE) if(UMF_POOL_SCALABLE_ENABLED) set(UMF_PROXY_LIB_ENABLED ON) From 09ee70e6c305df6b3f56c7d5c500bac96ece8b74 Mon Sep 17 00:00:00 2001 From: Rafal Rudnicki Date: Fri, 8 Nov 2024 09:30:39 +0100 Subject: [PATCH 265/352] fix devdax_allocation_merge arg checks --- src/provider/provider_devdax_memory.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/provider/provider_devdax_memory.c b/src/provider/provider_devdax_memory.c index 7751eb463..bae968a1d 100644 --- a/src/provider/provider_devdax_memory.c +++ b/src/provider/provider_devdax_memory.c @@ -360,13 +360,9 @@ static umf_result_t devdax_allocation_split(void *provider, void *ptr, static umf_result_t devdax_allocation_merge(void *provider, void *lowPtr, void *highPtr, size_t totalSize) { - (void)provider; - - if ((uintptr_t)highPtr <= (uintptr_t)lowPtr) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - - if ((uintptr_t)highPtr - (uintptr_t)lowPtr <= totalSize) { + if (provider == NULL || lowPtr == NULL || highPtr == NULL || + ((uintptr_t)highPtr <= (uintptr_t)lowPtr) || + ((uintptr_t)highPtr - (uintptr_t)lowPtr >= totalSize)) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; } From 912be58d9be88134f31e39cc01b9d7eef2e5db33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Staniewski?= Date: Tue, 12 Nov 2024 09:35:54 +0000 Subject: [PATCH 266/352] Add explicit condition check for Coverity --- test/utils/utils_linux.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/utils/utils_linux.cpp b/test/utils/utils_linux.cpp index aceefd4c6..82061409b 100644 --- a/test/utils/utils_linux.cpp +++ b/test/utils/utils_linux.cpp @@ -29,9 +29,12 @@ TEST_F(test, utils_get_file_size_invalid_args) { int fd = utils_create_anonymous_fd(); ASSERT_GE(fd, 0); - ret = utils_get_file_size(fd, &size); - EXPECT_EQ(ret, 0); - EXPECT_EQ(size, 0); + // Explicit condition for coverity + if (fd >= 0) { + ret = utils_get_file_size(fd, &size); + EXPECT_EQ(ret, 0); + EXPECT_EQ(size, 0); + } } TEST_F(test, utils_set_file_size_invalid_args) { From cb120ddc8020cac313a9e03c2314ddf1efba760f Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Thu, 7 Nov 2024 15:51:02 +0100 Subject: [PATCH 267/352] Introduce config params for scalable pool --- include/umf/pools/pool_scalable.h | 38 ++++++++++++++ src/libumf.def | 4 ++ src/libumf.map | 4 ++ src/pool/pool_scalable.c | 83 +++++++++++++++++++++++++++++-- 4 files changed, 125 insertions(+), 4 deletions(-) diff --git a/include/umf/pools/pool_scalable.h b/include/umf/pools/pool_scalable.h index 3b9945f0b..072169b68 100644 --- a/include/umf/pools/pool_scalable.h +++ b/include/umf/pools/pool_scalable.h @@ -14,9 +14,47 @@ extern "C" { #endif +#include + #include #include +struct umf_scalable_pool_params_t; + +/// @brief handle to the parameters of the scalable pool. +typedef struct umf_scalable_pool_params_t *umf_scalable_pool_params_handle_t; + +/// @brief Create a struct to store parameters of scalable pool. +/// @param hParams [out] handle to the newly created parameters struct. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t +umfScalablePoolParamsCreate(umf_scalable_pool_params_handle_t *hParams); + +/// @brief Destroy parameters struct. +/// @param hParams handle to the parameters of the scalable pool. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t +umfScalablePoolParamsDestroy(umf_scalable_pool_params_handle_t hParams); + +/// @brief Set granularity of allocations that scalable pool requests from a memory provider. +/// @param hParams handle to the parameters of the scalable pool. +/// @param granularity granularity in bytes. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t +umfScalablePoolParamsSetGranularity(umf_scalable_pool_params_handle_t hParams, + size_t granularity); + +/// @brief Set if scalable pool should keep all memory allocated from memory provider till destruction. +/// @param hParams handle to the parameters of the scalable pool. +/// @param keepAllMemory \p true if the scalable pool should not call +/// \p umfMemoryProviderFree until it is destroyed, \p false otherwise. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t +umfScalablePoolParamsSetKeepAllMemory(umf_scalable_pool_params_handle_t hParams, + bool keepAllMemory); + +/// @brief Return \p ops structure containing pointers to the scalable pool implementation. +/// @return pointer to the \p umf_memory_pool_ops_t struct. umf_memory_pool_ops_t *umfScalablePoolOps(void); #ifdef __cplusplus diff --git a/src/libumf.def b/src/libumf.def index 979187d96..56e26050c 100644 --- a/src/libumf.def +++ b/src/libumf.def @@ -82,3 +82,7 @@ EXPORTS umfProxyPoolOps umfPutIPCHandle umfScalablePoolOps + umfScalablePoolParamsCreate + umfScalablePoolParamsDestroy + umfScalablePoolParamsSetGranularity + umfScalablePoolParamsSetKeepAllMemory diff --git a/src/libumf.map b/src/libumf.map index bfca09a27..19235705c 100644 --- a/src/libumf.map +++ b/src/libumf.map @@ -76,6 +76,10 @@ UMF_1.0 { umfProxyPoolOps; umfPutIPCHandle; umfScalablePoolOps; + umfScalablePoolParamsCreate; + umfScalablePoolParamsDestroy; + umfScalablePoolParamsSetGranularity; + umfScalablePoolParamsSetKeepAllMemory; local: *; }; diff --git a/src/pool/pool_scalable.c b/src/pool/pool_scalable.c index ebf42493c..26ab7ad63 100644 --- a/src/pool/pool_scalable.c +++ b/src/pool/pool_scalable.c @@ -31,6 +31,7 @@ typedef void (*raw_free_tbb_type)(intptr_t, void *, size_t); static __TLS umf_result_t TLS_last_allocation_error; static __TLS umf_result_t TLS_last_free_error; +static const size_t DEFAULT_GRANULARITY = 2 * 1024 * 1024; // 2MB typedef struct tbb_mem_pool_policy_t { raw_alloc_tbb_type pAlloc; raw_free_tbb_type pFree; @@ -39,6 +40,11 @@ typedef struct tbb_mem_pool_policy_t { unsigned fixed_pool : 1, keep_all_memory : 1, reserved : 30; } tbb_mem_pool_policy_t; +typedef struct umf_scalable_pool_params_t { + size_t granularity; + bool keep_all_memory; +} umf_scalable_pool_params_t; + typedef struct tbb_callbacks_t { void *(*pool_malloc)(void *, size_t); void *(*pool_realloc)(void *, void *, size_t); @@ -167,19 +173,88 @@ static void tbb_raw_free_wrapper(intptr_t pool_id, void *ptr, size_t bytes) { } } +umf_result_t +umfScalablePoolParamsCreate(umf_scalable_pool_params_handle_t *params) { + if (!params) { + LOG_ERR("scalable pool params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + umf_scalable_pool_params_t *params_data = + umf_ba_global_alloc(sizeof(umf_scalable_pool_params_t)); + if (!params_data) { + LOG_ERR("cannot allocate memory for scalable poolparams"); + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + params_data->granularity = DEFAULT_GRANULARITY; + params_data->keep_all_memory = false; + + *params = (umf_scalable_pool_params_handle_t)params_data; + + return UMF_RESULT_SUCCESS; +} + +umf_result_t +umfScalablePoolParamsDestroy(umf_scalable_pool_params_handle_t params) { + if (!params) { + LOG_ERR("params is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + umf_ba_global_free(params); + + return UMF_RESULT_SUCCESS; +} + +umf_result_t +umfScalablePoolParamsSetGranularity(umf_scalable_pool_params_handle_t params, + size_t granularity) { + if (!params) { + LOG_ERR("params is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + if (granularity == 0) { + LOG_ERR("granularity cannot be 0"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + params->granularity = granularity; + + return UMF_RESULT_SUCCESS; +} + +umf_result_t +umfScalablePoolParamsSetKeepAllMemory(umf_scalable_pool_params_handle_t params, + bool keep_all_memory) { + if (!params) { + LOG_ERR("params is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + params->keep_all_memory = keep_all_memory; + + return UMF_RESULT_SUCCESS; +} + static umf_result_t tbb_pool_initialize(umf_memory_provider_handle_t provider, void *params, void **pool) { - (void)params; // unused - - const size_t GRANULARITY = 2 * 1024 * 1024; tbb_mem_pool_policy_t policy = {.pAlloc = tbb_raw_alloc_wrapper, .pFree = tbb_raw_free_wrapper, - .granularity = GRANULARITY, + .granularity = DEFAULT_GRANULARITY, .version = 1, .fixed_pool = false, .keep_all_memory = false, .reserved = 0}; + if (params) { + umf_scalable_pool_params_handle_t scalable_params = + (umf_scalable_pool_params_handle_t)params; + policy.granularity = scalable_params->granularity; + policy.keep_all_memory = scalable_params->keep_all_memory; + } + tbb_memory_pool_t *pool_data = umf_ba_global_alloc(sizeof(tbb_memory_pool_t)); if (!pool_data) { From e0ef5d269e0e3af898bc2b4ca89de180ca796f9e Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Thu, 7 Nov 2024 16:51:58 +0100 Subject: [PATCH 268/352] Add tests for scalable pool params --- src/cpp_helpers.hpp | 4 +- test/pools/scalable_pool.cpp | 138 ++++++++++++++++++ .../supp/memcheck-umf_test-scalable_pool.supp | 18 +++ 3 files changed, 158 insertions(+), 2 deletions(-) create mode 100644 test/supp/memcheck-umf_test-scalable_pool.supp diff --git a/src/cpp_helpers.hpp b/src/cpp_helpers.hpp index aafc7c4db..6316ccbc7 100644 --- a/src/cpp_helpers.hpp +++ b/src/cpp_helpers.hpp @@ -79,7 +79,7 @@ template umf_memory_pool_ops_t poolOpsBase() { return ops; } -template umf_memory_provider_ops_t providerOpsBase() { +template constexpr umf_memory_provider_ops_t providerOpsBase() { umf_memory_provider_ops_t ops{}; ops.version = UMF_VERSION_CURRENT; ops.finalize = [](void *obj) { delete reinterpret_cast(obj); }; @@ -134,7 +134,7 @@ template umf_memory_pool_ops_t poolMakeCOps() { // C API. 'params' from ops.initialize will be casted to 'ParamType*' // and passed to T::initialize() function. template -umf_memory_provider_ops_t providerMakeCOps() { +constexpr umf_memory_provider_ops_t providerMakeCOps() { umf_memory_provider_ops_t ops = detail::providerOpsBase(); ops.initialize = []([[maybe_unused]] void *params, void **obj) { diff --git a/test/pools/scalable_pool.cpp b/test/pools/scalable_pool.cpp index 2be29eb9d..68409b4bb 100644 --- a/test/pools/scalable_pool.cpp +++ b/test/pools/scalable_pool.cpp @@ -7,6 +7,7 @@ #include "pool.hpp" #include "poolFixtures.hpp" +#include "provider.hpp" auto defaultParams = umfOsMemoryProviderParamsDefault(); INSTANTIATE_TEST_SUITE_P(scalablePoolTest, umfPoolTest, @@ -14,3 +15,140 @@ INSTANTIATE_TEST_SUITE_P(scalablePoolTest, umfPoolTest, umfScalablePoolOps(), nullptr, umfOsMemoryProviderOps(), &defaultParams, nullptr})); + +using scalablePoolParams = std::tuple; +struct umfScalablePoolParamsTest + : umf_test::test, + ::testing::WithParamInterface { + + struct validation_params_t { + size_t granularity; + bool keep_all_memory; + }; + + struct provider_validator : public umf_test::provider_ba_global { + using base_provider = umf_test::provider_ba_global; + + umf_result_t initialize(validation_params_t *params) noexcept { + EXPECT_NE(params, nullptr); + expected_params = params; + return UMF_RESULT_SUCCESS; + } + umf_result_t alloc(size_t size, size_t align, void **ptr) noexcept { + EXPECT_EQ(size, expected_params->granularity); + return base_provider::alloc(size, align, ptr); + } + umf_result_t free(void *ptr, size_t size) noexcept { + EXPECT_EQ(expected_params->keep_all_memory, false); + return base_provider::free(ptr, size); + } + + validation_params_t *expected_params; + }; + + static constexpr umf_memory_provider_ops_t VALIDATOR_PROVIDER_OPS = + umf::providerMakeCOps(); + + umfScalablePoolParamsTest() {} + void SetUp() override { + test::SetUp(); + auto [granularity, keep_all_memory] = this->GetParam(); + expected_params.granularity = granularity; + expected_params.keep_all_memory = keep_all_memory; + umf_result_t ret = umfScalablePoolParamsCreate(¶ms); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ret = umfScalablePoolParamsSetGranularity(params, granularity); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ret = umfScalablePoolParamsSetKeepAllMemory(params, keep_all_memory); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + } + + void TearDown() override { + umfScalablePoolParamsDestroy(params); + test::TearDown(); + } + + umf::pool_unique_handle_t makePool() { + umf_memory_provider_handle_t hProvider = nullptr; + umf_memory_pool_handle_t hPool = nullptr; + + auto ret = umfMemoryProviderCreate(&VALIDATOR_PROVIDER_OPS, + &expected_params, &hProvider); + EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + + ret = umfPoolCreate(umfScalablePoolOps(), hProvider, params, + UMF_POOL_CREATE_FLAG_OWN_PROVIDER, &hPool); + EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + + return umf::pool_unique_handle_t(hPool, &umfPoolDestroy); + } + + void allocFreeFlow() { + static const size_t ALLOC_SIZE = 128; + static const size_t NUM_ALLOCATIONS = + expected_params.granularity / ALLOC_SIZE * 20; + std::vector ptrs; + + auto pool = makePool(); + ASSERT_NE(pool, nullptr); + + for (size_t i = 0; i < NUM_ALLOCATIONS; ++i) { + auto *ptr = umfPoolMalloc(pool.get(), ALLOC_SIZE); + ASSERT_NE(ptr, nullptr); + ptrs.push_back(ptr); + } + + for (size_t i = 0; i < NUM_ALLOCATIONS; ++i) { + auto ret = umfPoolFree(pool.get(), ptrs[i]); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + } + + // Now pool can call free during pool destruction + expected_params.keep_all_memory = false; + } + + validation_params_t expected_params; + umf_scalable_pool_params_handle_t params; +}; + +TEST_P(umfScalablePoolParamsTest, allocFree) { allocFreeFlow(); } + +TEST_P(umfScalablePoolParamsTest, updateParams) { + expected_params.granularity *= 2; + umf_result_t ret = umfScalablePoolParamsSetGranularity( + params, expected_params.granularity); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + expected_params.keep_all_memory = !expected_params.keep_all_memory; + ret = umfScalablePoolParamsSetKeepAllMemory( + params, expected_params.keep_all_memory); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + allocFreeFlow(); +} + +TEST_P(umfScalablePoolParamsTest, invalidParams) { + umf_result_t ret = umfScalablePoolParamsCreate(nullptr); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + ret = umfScalablePoolParamsSetGranularity(nullptr, 2 * 1024 * 1024); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + ret = umfScalablePoolParamsSetGranularity(params, 0); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + ret = umfScalablePoolParamsSetKeepAllMemory(nullptr, true); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + ret = umfScalablePoolParamsSetKeepAllMemory(nullptr, false); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + ret = umfScalablePoolParamsDestroy(nullptr); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} + +INSTANTIATE_TEST_SUITE_P( + scalablePoolTest, umfScalablePoolParamsTest, + testing::Combine(testing::Values(2 * 1024 * 1024, 3 * 1024 * 1024, + 4 * 1024 * 1024, 5 * 1024 * 1024), + testing::Values(false, true))); diff --git a/test/supp/memcheck-umf_test-scalable_pool.supp b/test/supp/memcheck-umf_test-scalable_pool.supp new file mode 100644 index 000000000..114dfb236 --- /dev/null +++ b/test/supp/memcheck-umf_test-scalable_pool.supp @@ -0,0 +1,18 @@ +{ + Conditional jump or move depends on uninitialised value(s) - internal issue of libtbbmalloc.so + Memcheck:Cond + fun:_ZN3rml9pool_freeEPNS_10MemoryPoolEPv + fun:tbb_free + fun:umfPoolFree + ... +} + +{ + Conditional jump or move depends on uninitialised value(s) - internal issue of libtbbmalloc.so + Memcheck:Cond + obj:*libtbbmalloc.so* + fun:_ZN3rml9pool_freeEPNS_10MemoryPoolEPv + fun:tbb_free + fun:umfPoolFree + ... +} From 96532dc73ccc7cb727dc91f27827ae9f0b3120b0 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Tue, 12 Nov 2024 15:05:38 +0100 Subject: [PATCH 269/352] Do not run tests under proxy lib if libumf is not a shared lib Do not run tests under the proxy library if libumf is not a shared library, because the proxy library is built only if libumf is a shared library. Signed-off-by: Lukasz Dorau --- .github/workflows/reusable_dax.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/reusable_dax.yml b/.github/workflows/reusable_dax.yml index b30cc0afc..f7c5d0d21 100644 --- a/.github/workflows/reusable_dax.yml +++ b/.github/workflows/reusable_dax.yml @@ -109,6 +109,8 @@ jobs: # TODO: enable the provider_devdax_memory_ipc test when the IPC tests with the proxy library are fixed # see the issue: https://github.com/oneapi-src/unified-memory-framework/issues/864 - name: Run the DEVDAX tests with the proxy library + # proxy library is built only if libumf is a shared library + if: ${{ matrix.shared_library == 'ON' }} working-directory: ${{env.BUILD_DIR}} run: > LD_PRELOAD=./lib/libumf_proxy.so @@ -119,6 +121,8 @@ jobs: # TODO: enable the provider_file_memory_ipc test when the IPC tests with the proxy library are fixed # see the issue: https://github.com/oneapi-src/unified-memory-framework/issues/864 - name: Run the FSDAX tests with the proxy library + # proxy library is built only if libumf is a shared library + if: ${{ matrix.shared_library == 'ON' }} working-directory: ${{env.BUILD_DIR}} run: > LD_PRELOAD=./lib/libumf_proxy.so From 43c9cd7edda835e6ea0377c24395769b742f3885 Mon Sep 17 00:00:00 2001 From: Sergei Vinogradov Date: Sun, 13 Oct 2024 21:01:54 +0200 Subject: [PATCH 270/352] Fix utils_atomic_load_acquire on Windows --- src/utils/utils_concurrency.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils/utils_concurrency.h b/src/utils/utils_concurrency.h index f48c6f910..c6c75f02b 100644 --- a/src/utils/utils_concurrency.h +++ b/src/utils/utils_concurrency.h @@ -75,7 +75,8 @@ static __inline unsigned char utils_mssb_index(long long value) { // There is no good way to do atomic_load on windows... #define utils_atomic_load_acquire(object, dest) \ do { \ - *dest = InterlockedOr64Acquire((LONG64 volatile *)object, 0); \ + *(LONG64 *)dest = \ + InterlockedOr64Acquire((LONG64 volatile *)object, 0); \ } while (0) #define utils_atomic_store_release(object, desired) \ From 5364731719dc0ec548bc6d635206d8bddc1fdfd0 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Wed, 4 Sep 2024 17:55:04 +0200 Subject: [PATCH 271/352] Add utils_atomic_decrement function --- src/utils/utils_concurrency.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/utils/utils_concurrency.h b/src/utils/utils_concurrency.h index c6c75f02b..155184cc4 100644 --- a/src/utils/utils_concurrency.h +++ b/src/utils/utils_concurrency.h @@ -83,6 +83,8 @@ static __inline unsigned char utils_mssb_index(long long value) { InterlockedExchange64((LONG64 volatile *)object, (LONG64)desired) #define utils_atomic_increment(object) \ InterlockedIncrement64((LONG64 volatile *)object) +#define utils_atomic_decrement(object) \ + InterlockedDecrement64((LONG64 volatile *)object) #define utils_fetch_and_add64(ptr, value) \ InterlockedExchangeAdd64((LONG64 *)(ptr), value) #else @@ -102,7 +104,10 @@ static __inline unsigned char utils_mssb_index(long long value) { #define utils_atomic_increment(object) \ __atomic_add_fetch(object, 1, __ATOMIC_ACQ_REL) +#define utils_atomic_decrement(object) \ + __atomic_sub_fetch(object, 1, __ATOMIC_ACQ_REL) #define utils_fetch_and_add64 __sync_fetch_and_add + #endif #ifdef __cplusplus From 0f72af250ae963881047218221b0ea3e2a55463a Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Mon, 3 Jun 2024 16:21:23 +0200 Subject: [PATCH 272/352] Add uthash and utlist implemenation --- src/uthash/uthash.h | 1255 +++++++++++++++++++++++++++++++++++++++++++ src/uthash/utlist.h | 1148 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 2403 insertions(+) create mode 100644 src/uthash/uthash.h create mode 100644 src/uthash/utlist.h diff --git a/src/uthash/uthash.h b/src/uthash/uthash.h new file mode 100644 index 000000000..97e384d12 --- /dev/null +++ b/src/uthash/uthash.h @@ -0,0 +1,1255 @@ +/* +Copyright (c) 2003-2022, Troy D. Hanson https://troydhanson.github.io/uthash/ +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef UTHASH_H +#define UTHASH_H + +#define UTHASH_VERSION 2.3.0 + +#include /* ptrdiff_t */ +#include /* exit */ +#include /* memcmp, memset, strlen */ + +#if defined(HASH_DEFINE_OWN_STDINT) && HASH_DEFINE_OWN_STDINT +/* This codepath is provided for backward compatibility, but I plan to remove it. */ +#warning \ + "HASH_DEFINE_OWN_STDINT is deprecated; please use HASH_NO_STDINT instead" +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; +#elif defined(HASH_NO_STDINT) && HASH_NO_STDINT +#else +#include /* uint8_t, uint32_t */ +#endif + +/* These macros use decltype or the earlier __typeof GNU extension. + As decltype is only available in newer compilers (VS2010 or gcc 4.3+ + when compiling c++ source) this code uses whatever method is needed + or, for VS2008 where neither is available, uses casting workarounds. */ +#if !defined(DECLTYPE) && !defined(NO_DECLTYPE) +#if defined(_MSC_VER) /* MS compiler */ +#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ +#define DECLTYPE(x) (decltype(x)) +#else /* VS2008 or older (or VS2010 in C mode) */ +#define NO_DECLTYPE +#endif +#elif defined(__MCST__) /* Elbrus C Compiler */ +#define DECLTYPE(x) (__typeof(x)) +#elif defined(__BORLANDC__) || defined(__ICCARM__) || defined(__LCC__) || \ + defined(__WATCOMC__) +#define NO_DECLTYPE +#else /* GNU, Sun and other compilers */ +#define DECLTYPE(x) (__typeof(x)) +#endif +#endif + +#ifdef NO_DECLTYPE +#define DECLTYPE(x) +#define DECLTYPE_ASSIGN(dst, src) \ + do { \ + char **_da_dst = (char **)(&(dst)); \ + *_da_dst = (char *)(src); \ + } while (0) +#else +#define DECLTYPE_ASSIGN(dst, src) \ + do { \ + (dst) = DECLTYPE(dst)(src); \ + } while (0) +#endif + +#ifndef uthash_malloc +#define uthash_malloc(sz) malloc(sz) /* malloc fcn */ +#endif +#ifndef uthash_free +#define uthash_free(ptr, sz) free(ptr) /* free fcn */ +#endif +#ifndef uthash_bzero +#define uthash_bzero(a, n) memset(a, '\0', n) +#endif +#ifndef uthash_strlen +#define uthash_strlen(s) strlen(s) +#endif + +#ifndef HASH_FUNCTION +#define HASH_FUNCTION(keyptr, keylen, hashv) HASH_JEN(keyptr, keylen, hashv) +#endif + +#ifndef HASH_KEYCMP +#define HASH_KEYCMP(a, b, n) memcmp(a, b, n) +#endif + +#ifndef uthash_noexpand_fyi +#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ +#endif +#ifndef uthash_expand_fyi +#define uthash_expand_fyi(tbl) /* can be defined to log expands */ +#endif + +#ifndef HASH_NONFATAL_OOM +#define HASH_NONFATAL_OOM 0 +#endif + +#if HASH_NONFATAL_OOM +/* malloc failures can be recovered from */ + +#ifndef uthash_nonfatal_oom +#define uthash_nonfatal_oom(obj) \ + do { \ + } while (0) /* non-fatal OOM error */ +#endif + +#define HASH_RECORD_OOM(oomed) \ + do { \ + (oomed) = 1; \ + } while (0) +#define IF_HASH_NONFATAL_OOM(x) x + +#else +/* malloc failures result in lost memory, hash tables are unusable */ + +#ifndef uthash_fatal +#define uthash_fatal(msg) exit(-1) /* fatal OOM error */ +#endif + +#define HASH_RECORD_OOM(oomed) uthash_fatal("out of memory") +#define IF_HASH_NONFATAL_OOM(x) + +#endif + +/* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS 32U /* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS_LOG2 5U /* lg2 of initial number of buckets */ +#define HASH_BKT_CAPACITY_THRESH 10U /* expand when bucket count reaches */ + +/* calculate the element whose hash handle address is hhp */ +#define ELMT_FROM_HH(tbl, hhp) ((void *)(((char *)(hhp)) - ((tbl)->hho))) +/* calculate the hash handle from element address elp */ +#define HH_FROM_ELMT(tbl, elp) \ + ((UT_hash_handle *)(void *)(((char *)(elp)) + ((tbl)->hho))) + +#define HASH_ROLLBACK_BKT(hh, head, itemptrhh) \ + do { \ + struct UT_hash_handle *_hd_hh_item = (itemptrhh); \ + unsigned _hd_bkt; \ + HASH_TO_BKT(_hd_hh_item->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ + (head)->hh.tbl->buckets[_hd_bkt].count++; \ + _hd_hh_item->hh_next = NULL; \ + _hd_hh_item->hh_prev = NULL; \ + } while (0) + +#define HASH_VALUE(keyptr, keylen, hashv) \ + do { \ + HASH_FUNCTION(keyptr, keylen, hashv); \ + } while (0) + +#define HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, hashval, out) \ + do { \ + (out) = NULL; \ + if (head) { \ + unsigned _hf_bkt; \ + HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _hf_bkt); \ + if (HASH_BLOOM_TEST((head)->hh.tbl, hashval)) { \ + HASH_FIND_IN_BKT((head)->hh.tbl, hh, \ + (head)->hh.tbl->buckets[_hf_bkt], keyptr, \ + keylen, hashval, out); \ + } \ + } \ + } while (0) + +#define HASH_FIND(hh, head, keyptr, keylen, out) \ + do { \ + (out) = NULL; \ + if (head) { \ + unsigned _hf_hashv; \ + HASH_VALUE(keyptr, keylen, _hf_hashv); \ + HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, _hf_hashv, out); \ + } \ + } while (0) + +#ifdef HASH_BLOOM +#define HASH_BLOOM_BITLEN (1UL << HASH_BLOOM) +#define HASH_BLOOM_BYTELEN \ + (HASH_BLOOM_BITLEN / 8UL) + (((HASH_BLOOM_BITLEN % 8UL) != 0UL) ? 1UL : 0UL) +#define HASH_BLOOM_MAKE(tbl, oomed) \ + do { \ + (tbl)->bloom_nbits = HASH_BLOOM; \ + (tbl)->bloom_bv = (uint8_t *)uthash_malloc(HASH_BLOOM_BYTELEN); \ + if (!(tbl)->bloom_bv) { \ + HASH_RECORD_OOM(oomed); \ + } else { \ + uthash_bzero((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ + (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ + } \ + } while (0) + +#define HASH_BLOOM_FREE(tbl) \ + do { \ + uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ + } while (0) + +#define HASH_BLOOM_BITSET(bv, idx) (bv[(idx) / 8U] |= (1U << ((idx) % 8U))) +#define HASH_BLOOM_BITTEST(bv, idx) \ + ((bv[(idx) / 8U] & (1U << ((idx) % 8U))) != 0) + +#define HASH_BLOOM_ADD(tbl, hashv) \ + HASH_BLOOM_BITSET( \ + (tbl)->bloom_bv, \ + ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U))) + +#define HASH_BLOOM_TEST(tbl, hashv) \ + HASH_BLOOM_BITTEST( \ + (tbl)->bloom_bv, \ + ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U))) + +#else +#define HASH_BLOOM_MAKE(tbl, oomed) +#define HASH_BLOOM_FREE(tbl) +#define HASH_BLOOM_ADD(tbl, hashv) +#define HASH_BLOOM_TEST(tbl, hashv) 1 +#define HASH_BLOOM_BYTELEN 0U +#endif + +#define HASH_MAKE_TABLE(hh, head, oomed) \ + do { \ + (head)->hh.tbl = \ + (UT_hash_table *)uthash_malloc(sizeof(UT_hash_table)); \ + if (!(head)->hh.tbl) { \ + HASH_RECORD_OOM(oomed); \ + } else { \ + uthash_bzero((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head)->hh.tbl->tail = &((head)->hh); \ + (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ + (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ + (head)->hh.tbl->hho = (char *)(&(head)->hh) - (char *)(head); \ + (head)->hh.tbl->buckets = (UT_hash_bucket *)uthash_malloc( \ + HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \ + (head)->hh.tbl->signature = HASH_SIGNATURE; \ + if (!(head)->hh.tbl->buckets) { \ + HASH_RECORD_OOM(oomed); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + } else { \ + uthash_bzero((head)->hh.tbl->buckets, \ + HASH_INITIAL_NUM_BUCKETS * \ + sizeof(struct UT_hash_bucket)); \ + HASH_BLOOM_MAKE((head)->hh.tbl, oomed); \ + IF_HASH_NONFATAL_OOM(if (oomed) { \ + uthash_free((head)->hh.tbl->buckets, \ + HASH_INITIAL_NUM_BUCKETS * \ + sizeof(struct UT_hash_bucket)); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + }) \ + } \ + } \ + } while (0) + +#define HASH_REPLACE_BYHASHVALUE_INORDER(hh, head, fieldname, keylen_in, \ + hashval, add, replaced, cmpfcn) \ + do { \ + (replaced) = NULL; \ + HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, \ + hashval, replaced); \ + if (replaced) { \ + HASH_DELETE(hh, head, replaced); \ + } \ + HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), \ + keylen_in, hashval, add, cmpfcn); \ + } while (0) + +#define HASH_REPLACE_BYHASHVALUE(hh, head, fieldname, keylen_in, hashval, add, \ + replaced) \ + do { \ + (replaced) = NULL; \ + HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, \ + hashval, replaced); \ + if (replaced) { \ + HASH_DELETE(hh, head, replaced); \ + } \ + HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, \ + hashval, add); \ + } while (0) + +#define HASH_REPLACE(hh, head, fieldname, keylen_in, add, replaced) \ + do { \ + unsigned _hr_hashv; \ + HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ + HASH_REPLACE_BYHASHVALUE(hh, head, fieldname, keylen_in, _hr_hashv, \ + add, replaced); \ + } while (0) + +#define HASH_REPLACE_INORDER(hh, head, fieldname, keylen_in, add, replaced, \ + cmpfcn) \ + do { \ + unsigned _hr_hashv; \ + HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ + HASH_REPLACE_BYHASHVALUE_INORDER(hh, head, fieldname, keylen_in, \ + _hr_hashv, add, replaced, cmpfcn); \ + } while (0) + +#define HASH_APPEND_LIST(hh, head, add) \ + do { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ + (head)->hh.tbl->tail->next = (add); \ + (head)->hh.tbl->tail = &((add)->hh); \ + } while (0) + +#define HASH_AKBI_INNER_LOOP(hh, head, add, cmpfcn) \ + do { \ + do { \ + if (cmpfcn(DECLTYPE(head)(_hs_iter), add) > 0) { \ + break; \ + } \ + } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \ + } while (0) + +#ifdef NO_DECLTYPE +#undef HASH_AKBI_INNER_LOOP +#define HASH_AKBI_INNER_LOOP(hh, head, add, cmpfcn) \ + do { \ + char *_hs_saved_head = (char *)(head); \ + do { \ + DECLTYPE_ASSIGN(head, _hs_iter); \ + if (cmpfcn(head, add) > 0) { \ + DECLTYPE_ASSIGN(head, _hs_saved_head); \ + break; \ + } \ + DECLTYPE_ASSIGN(head, _hs_saved_head); \ + } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \ + } while (0) +#endif + +#if HASH_NONFATAL_OOM + +#define HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, oomed) \ + do { \ + if (!(oomed)) { \ + unsigned _ha_bkt; \ + (head)->hh.tbl->num_items++; \ + HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ + HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, \ + oomed); \ + if (oomed) { \ + HASH_ROLLBACK_BKT(hh, head, &(add)->hh); \ + HASH_DELETE_HH(hh, head, &(add)->hh); \ + (add)->hh.tbl = NULL; \ + uthash_nonfatal_oom(add); \ + } else { \ + HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ + HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ + } \ + } else { \ + (add)->hh.tbl = NULL; \ + uthash_nonfatal_oom(add); \ + } \ + } while (0) + +#else + +#define HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, oomed) \ + do { \ + unsigned _ha_bkt; \ + (head)->hh.tbl->num_items++; \ + HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ + HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, \ + oomed); \ + HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ + HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ + } while (0) + +#endif + +#define HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, keyptr, keylen_in, \ + hashval, add, cmpfcn) \ + do { \ + IF_HASH_NONFATAL_OOM(int _ha_oomed = 0;) \ + (add)->hh.hashv = (hashval); \ + (add)->hh.key = (char *)(keyptr); \ + (add)->hh.keylen = (unsigned)(keylen_in); \ + if (!(head)) { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = NULL; \ + HASH_MAKE_TABLE(hh, add, _ha_oomed); \ + IF_HASH_NONFATAL_OOM(if (!_ha_oomed) { ) \ + (head) = (add); \ + IF_HASH_NONFATAL_OOM( \ + }) \ + } else { \ + void *_hs_iter = (head); \ + (add)->hh.tbl = (head)->hh.tbl; \ + HASH_AKBI_INNER_LOOP(hh, head, add, cmpfcn); \ + if (_hs_iter) { \ + (add)->hh.next = _hs_iter; \ + if (((add)->hh.prev = \ + HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev)) { \ + HH_FROM_ELMT((head)->hh.tbl, (add)->hh.prev)->next = \ + (add); \ + } else { \ + (head) = (add); \ + } \ + HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev = (add); \ + } else { \ + HASH_APPEND_LIST(hh, head, add); \ + } \ + } \ + HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, \ + _ha_oomed); \ + HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE_INORDER"); \ + } while (0) + +#define HASH_ADD_KEYPTR_INORDER(hh, head, keyptr, keylen_in, add, cmpfcn) \ + do { \ + unsigned _hs_hashv; \ + HASH_VALUE(keyptr, keylen_in, _hs_hashv); \ + HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, keyptr, keylen_in, \ + _hs_hashv, add, cmpfcn); \ + } while (0) + +#define HASH_ADD_BYHASHVALUE_INORDER(hh, head, fieldname, keylen_in, hashval, \ + add, cmpfcn) \ + HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), \ + keylen_in, hashval, add, cmpfcn) + +#define HASH_ADD_INORDER(hh, head, fieldname, keylen_in, add, cmpfcn) \ + HASH_ADD_KEYPTR_INORDER(hh, head, &((add)->fieldname), keylen_in, add, \ + cmpfcn) + +#define HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, keyptr, keylen_in, hashval, add) \ + do { \ + IF_HASH_NONFATAL_OOM(int _ha_oomed = 0;) \ + (add)->hh.hashv = (hashval); \ + (add)->hh.key = (const void *)(keyptr); \ + (add)->hh.keylen = (unsigned)(keylen_in); \ + if (!(head)) { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = NULL; \ + HASH_MAKE_TABLE(hh, add, _ha_oomed); \ + IF_HASH_NONFATAL_OOM(if (!_ha_oomed) { ) \ + (head) = (add); \ + IF_HASH_NONFATAL_OOM( \ + }) \ + } else { \ + (add)->hh.tbl = (head)->hh.tbl; \ + HASH_APPEND_LIST(hh, head, add); \ + } \ + HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, \ + _ha_oomed); \ + HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE"); \ + } while (0) + +#define HASH_ADD_KEYPTR(hh, head, keyptr, keylen_in, add) \ + do { \ + unsigned _ha_hashv; \ + HASH_VALUE(keyptr, keylen_in, _ha_hashv); \ + HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, keyptr, keylen_in, _ha_hashv, \ + add); \ + } while (0) + +#define HASH_ADD_BYHASHVALUE(hh, head, fieldname, keylen_in, hashval, add) \ + HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, \ + hashval, add) + +#define HASH_ADD(hh, head, fieldname, keylen_in, add) \ + HASH_ADD_KEYPTR(hh, head, &((add)->fieldname), keylen_in, add) + +#define HASH_TO_BKT(hashv, num_bkts, bkt) \ + do { \ + bkt = ((hashv) & ((num_bkts)-1U)); \ + } while (0) + +/* delete "delptr" from the hash table. + * "the usual" patch-up process for the app-order doubly-linked-list. + * The use of _hd_hh_del below deserves special explanation. + * These used to be expressed using (delptr) but that led to a bug + * if someone used the same symbol for the head and deletee, like + * HASH_DELETE(hh,users,users); + * We want that to work, but by changing the head (users) below + * we were forfeiting our ability to further refer to the deletee (users) + * in the patch-up process. Solution: use scratch space to + * copy the deletee pointer, then the latter references are via that + * scratch pointer rather than through the repointed (users) symbol. + */ +#define HASH_DELETE(hh, head, delptr) HASH_DELETE_HH(hh, head, &(delptr)->hh) + +#define HASH_DELETE_HH(hh, head, delptrhh) \ + do { \ + const struct UT_hash_handle *_hd_hh_del = (delptrhh); \ + if ((_hd_hh_del->prev == NULL) && (_hd_hh_del->next == NULL)) { \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets * \ + sizeof(struct UT_hash_bucket)); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head) = NULL; \ + } else { \ + unsigned _hd_bkt; \ + if (_hd_hh_del == (head)->hh.tbl->tail) { \ + (head)->hh.tbl->tail = \ + HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev); \ + } \ + if (_hd_hh_del->prev != NULL) { \ + HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev)->next = \ + _hd_hh_del->next; \ + } else { \ + DECLTYPE_ASSIGN(head, _hd_hh_del->next); \ + } \ + if (_hd_hh_del->next != NULL) { \ + HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->next)->prev = \ + _hd_hh_del->prev; \ + } \ + HASH_TO_BKT(_hd_hh_del->hashv, (head)->hh.tbl->num_buckets, \ + _hd_bkt); \ + HASH_DEL_IN_BKT((head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ + (head)->hh.tbl->num_items--; \ + } \ + HASH_FSCK(hh, head, "HASH_DELETE_HH"); \ + } while (0) + +/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ +#define HASH_FIND_STR(head, findstr, out) \ + do { \ + unsigned _uthash_hfstr_keylen = (unsigned)uthash_strlen(findstr); \ + HASH_FIND(hh, head, findstr, _uthash_hfstr_keylen, out); \ + } while (0) +#define HASH_ADD_STR(head, strfield, add) \ + do { \ + unsigned _uthash_hastr_keylen = \ + (unsigned)uthash_strlen((add)->strfield); \ + HASH_ADD(hh, head, strfield[0], _uthash_hastr_keylen, add); \ + } while (0) +#define HASH_REPLACE_STR(head, strfield, add, replaced) \ + do { \ + unsigned _uthash_hrstr_keylen = \ + (unsigned)uthash_strlen((add)->strfield); \ + HASH_REPLACE(hh, head, strfield[0], _uthash_hrstr_keylen, add, \ + replaced); \ + } while (0) +#define HASH_FIND_INT(head, findint, out) \ + HASH_FIND(hh, head, findint, sizeof(int), out) +#define HASH_ADD_INT(head, intfield, add) \ + HASH_ADD(hh, head, intfield, sizeof(int), add) +#define HASH_REPLACE_INT(head, intfield, add, replaced) \ + HASH_REPLACE(hh, head, intfield, sizeof(int), add, replaced) +#define HASH_FIND_PTR(head, findptr, out) \ + HASH_FIND(hh, head, findptr, sizeof(void *), out) +#define HASH_ADD_PTR(head, ptrfield, add) \ + HASH_ADD(hh, head, ptrfield, sizeof(void *), add) +#define HASH_REPLACE_PTR(head, ptrfield, add, replaced) \ + HASH_REPLACE(hh, head, ptrfield, sizeof(void *), add, replaced) +#define HASH_DEL(head, delptr) HASH_DELETE(hh, head, delptr) + +/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. + * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. + */ +#ifdef HASH_DEBUG +#include /* fprintf, stderr */ +#define HASH_OOPS(...) \ + do { \ + fprintf(stderr, __VA_ARGS__); \ + exit(-1); \ + } while (0) +#define HASH_FSCK(hh, head, where) \ + do { \ + struct UT_hash_handle *_thh; \ + if (head) { \ + unsigned _bkt_i; \ + unsigned _count = 0; \ + char *_prev; \ + for (_bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; ++_bkt_i) { \ + unsigned _bkt_count = 0; \ + _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ + _prev = NULL; \ + while (_thh) { \ + if (_prev != (char *)(_thh->hh_prev)) { \ + HASH_OOPS("%s: invalid hh_prev %p, actual %p\n", \ + (where), (void *)_thh->hh_prev, \ + (void *)_prev); \ + } \ + _bkt_count++; \ + _prev = (char *)(_thh); \ + _thh = _thh->hh_next; \ + } \ + _count += _bkt_count; \ + if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ + HASH_OOPS("%s: invalid bucket count %u, actual %u\n", \ + (where), (head)->hh.tbl->buckets[_bkt_i].count, \ + _bkt_count); \ + } \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("%s: invalid hh item count %u, actual %u\n", \ + (where), (head)->hh.tbl->num_items, _count); \ + } \ + _count = 0; \ + _prev = NULL; \ + _thh = &(head)->hh; \ + while (_thh) { \ + _count++; \ + if (_prev != (char *)_thh->prev) { \ + HASH_OOPS("%s: invalid prev %p, actual %p\n", (where), \ + (void *)_thh->prev, (void *)_prev); \ + } \ + _prev = (char *)ELMT_FROM_HH((head)->hh.tbl, _thh); \ + _thh = (_thh->next ? HH_FROM_ELMT((head)->hh.tbl, _thh->next) \ + : NULL); \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("%s: invalid app item count %u, actual %u\n", \ + (where), (head)->hh.tbl->num_items, _count); \ + } \ + } \ + } while (0) +#else +#define HASH_FSCK(hh, head, where) +#endif + +/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to + * the descriptor to which this macro is defined for tuning the hash function. + * The app can #include to get the prototype for write(2). */ +#ifdef HASH_EMIT_KEYS +#define HASH_EMIT_KEY(hh, head, keyptr, fieldlen) \ + do { \ + unsigned _klen = fieldlen; \ + write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ + write(HASH_EMIT_KEYS, keyptr, (unsigned long)fieldlen); \ + } while (0) +#else +#define HASH_EMIT_KEY(hh, head, keyptr, fieldlen) +#endif + +/* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */ +#define HASH_BER(key, keylen, hashv) \ + do { \ + unsigned _hb_keylen = (unsigned)keylen; \ + const unsigned char *_hb_key = (const unsigned char *)(key); \ + (hashv) = 0; \ + while (_hb_keylen-- != 0U) { \ + (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; \ + } \ + } while (0) + +/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at + * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx + * (archive link: https://archive.is/Ivcan ) + */ +#define HASH_SAX(key, keylen, hashv) \ + do { \ + unsigned _sx_i; \ + const unsigned char *_hs_key = (const unsigned char *)(key); \ + hashv = 0; \ + for (_sx_i = 0; _sx_i < keylen; _sx_i++) { \ + hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ + } \ + } while (0) +/* FNV-1a variation */ +#define HASH_FNV(key, keylen, hashv) \ + do { \ + unsigned _fn_i; \ + const unsigned char *_hf_key = (const unsigned char *)(key); \ + (hashv) = 2166136261U; \ + for (_fn_i = 0; _fn_i < keylen; _fn_i++) { \ + hashv = hashv ^ _hf_key[_fn_i]; \ + hashv = hashv * 16777619U; \ + } \ + } while (0) + +#define HASH_OAT(key, keylen, hashv) \ + do { \ + unsigned _ho_i; \ + const unsigned char *_ho_key = (const unsigned char *)(key); \ + hashv = 0; \ + for (_ho_i = 0; _ho_i < keylen; _ho_i++) { \ + hashv += _ho_key[_ho_i]; \ + hashv += (hashv << 10); \ + hashv ^= (hashv >> 6); \ + } \ + hashv += (hashv << 3); \ + hashv ^= (hashv >> 11); \ + hashv += (hashv << 15); \ + } while (0) + +#define HASH_JEN_MIX(a, b, c) \ + do { \ + a -= b; \ + a -= c; \ + a ^= (c >> 13); \ + b -= c; \ + b -= a; \ + b ^= (a << 8); \ + c -= a; \ + c -= b; \ + c ^= (b >> 13); \ + a -= b; \ + a -= c; \ + a ^= (c >> 12); \ + b -= c; \ + b -= a; \ + b ^= (a << 16); \ + c -= a; \ + c -= b; \ + c ^= (b >> 5); \ + a -= b; \ + a -= c; \ + a ^= (c >> 3); \ + b -= c; \ + b -= a; \ + b ^= (a << 10); \ + c -= a; \ + c -= b; \ + c ^= (b >> 15); \ + } while (0) + +#define HASH_JEN(key, keylen, hashv) \ + do { \ + unsigned _hj_i, _hj_j, _hj_k; \ + unsigned const char *_hj_key = (unsigned const char *)(key); \ + hashv = 0xfeedbeefu; \ + _hj_i = _hj_j = 0x9e3779b9u; \ + _hj_k = (unsigned)(keylen); \ + while (_hj_k >= 12U) { \ + _hj_i += \ + (_hj_key[0] + ((unsigned)_hj_key[1] << 8) + \ + ((unsigned)_hj_key[2] << 16) + ((unsigned)_hj_key[3] << 24)); \ + _hj_j += \ + (_hj_key[4] + ((unsigned)_hj_key[5] << 8) + \ + ((unsigned)_hj_key[6] << 16) + ((unsigned)_hj_key[7] << 24)); \ + hashv += (_hj_key[8] + ((unsigned)_hj_key[9] << 8) + \ + ((unsigned)_hj_key[10] << 16) + \ + ((unsigned)_hj_key[11] << 24)); \ + \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + \ + _hj_key += 12; \ + _hj_k -= 12U; \ + } \ + hashv += (unsigned)(keylen); \ + switch (_hj_k) { \ + case 11: \ + hashv += ((unsigned)_hj_key[10] << 24); /* FALLTHROUGH */ \ + case 10: \ + hashv += ((unsigned)_hj_key[9] << 16); /* FALLTHROUGH */ \ + case 9: \ + hashv += ((unsigned)_hj_key[8] << 8); /* FALLTHROUGH */ \ + case 8: \ + _hj_j += ((unsigned)_hj_key[7] << 24); /* FALLTHROUGH */ \ + case 7: \ + _hj_j += ((unsigned)_hj_key[6] << 16); /* FALLTHROUGH */ \ + case 6: \ + _hj_j += ((unsigned)_hj_key[5] << 8); /* FALLTHROUGH */ \ + case 5: \ + _hj_j += _hj_key[4]; /* FALLTHROUGH */ \ + case 4: \ + _hj_i += ((unsigned)_hj_key[3] << 24); /* FALLTHROUGH */ \ + case 3: \ + _hj_i += ((unsigned)_hj_key[2] << 16); /* FALLTHROUGH */ \ + case 2: \ + _hj_i += ((unsigned)_hj_key[1] << 8); /* FALLTHROUGH */ \ + case 1: \ + _hj_i += _hj_key[0]; /* FALLTHROUGH */ \ + default:; \ + } \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + } while (0) + +/* The Paul Hsieh hash function */ +#undef get16bits +#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) || \ + defined(_MSC_VER) || defined(__BORLANDC__) || defined(__TURBOC__) +#define get16bits(d) (*((const uint16_t *)(d))) +#endif + +#if !defined(get16bits) +#define get16bits(d) \ + ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) + \ + (uint32_t)(((const uint8_t *)(d))[0])) +#endif +#define HASH_SFH(key, keylen, hashv) \ + do { \ + unsigned const char *_sfh_key = (unsigned const char *)(key); \ + uint32_t _sfh_tmp, _sfh_len = (uint32_t)keylen; \ + \ + unsigned _sfh_rem = _sfh_len & 3U; \ + _sfh_len >>= 2; \ + hashv = 0xcafebabeu; \ + \ + /* Main loop */ \ + for (; _sfh_len > 0U; _sfh_len--) { \ + hashv += get16bits(_sfh_key); \ + _sfh_tmp = ((uint32_t)(get16bits(_sfh_key + 2)) << 11) ^ hashv; \ + hashv = (hashv << 16) ^ _sfh_tmp; \ + _sfh_key += 2U * sizeof(uint16_t); \ + hashv += hashv >> 11; \ + } \ + \ + /* Handle end cases */ \ + switch (_sfh_rem) { \ + case 3: \ + hashv += get16bits(_sfh_key); \ + hashv ^= hashv << 16; \ + hashv ^= (uint32_t)(_sfh_key[sizeof(uint16_t)]) << 18; \ + hashv += hashv >> 11; \ + break; \ + case 2: \ + hashv += get16bits(_sfh_key); \ + hashv ^= hashv << 11; \ + hashv += hashv >> 17; \ + break; \ + case 1: \ + hashv += *_sfh_key; \ + hashv ^= hashv << 10; \ + hashv += hashv >> 1; \ + break; \ + default:; \ + } \ + \ + /* Force "avalanching" of final 127 bits */ \ + hashv ^= hashv << 3; \ + hashv += hashv >> 5; \ + hashv ^= hashv << 4; \ + hashv += hashv >> 17; \ + hashv ^= hashv << 25; \ + hashv += hashv >> 6; \ + } while (0) + +/* iterate over items in a known bucket to find desired item */ +#define HASH_FIND_IN_BKT(tbl, hh, head, keyptr, keylen_in, hashval, out) \ + do { \ + if ((head).hh_head != NULL) { \ + DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (head).hh_head)); \ + } else { \ + (out) = NULL; \ + } \ + while ((out) != NULL) { \ + if ((out)->hh.hashv == (hashval) && \ + (out)->hh.keylen == (keylen_in)) { \ + if (HASH_KEYCMP((out)->hh.key, keyptr, keylen_in) == 0) { \ + break; \ + } \ + } \ + if ((out)->hh.hh_next != NULL) { \ + DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (out)->hh.hh_next)); \ + } else { \ + (out) = NULL; \ + } \ + } \ + } while (0) + +/* add an item to a bucket */ +#define HASH_ADD_TO_BKT(head, hh, addhh, oomed) \ + do { \ + UT_hash_bucket *_ha_head = &(head); \ + _ha_head->count++; \ + (addhh)->hh_next = _ha_head->hh_head; \ + (addhh)->hh_prev = NULL; \ + if (_ha_head->hh_head != NULL) { \ + _ha_head->hh_head->hh_prev = (addhh); \ + } \ + _ha_head->hh_head = (addhh); \ + if ((_ha_head->count >= \ + ((_ha_head->expand_mult + 1U) * HASH_BKT_CAPACITY_THRESH)) && \ + !(addhh)->tbl->noexpand) { \ + HASH_EXPAND_BUCKETS(addhh, (addhh)->tbl, oomed); \ + IF_HASH_NONFATAL_OOM(if (oomed) { HASH_DEL_IN_BKT(head, addhh); }) \ + } \ + } while (0) + +/* remove an item from a given bucket */ +#define HASH_DEL_IN_BKT(head, delhh) \ + do { \ + UT_hash_bucket *_hd_head = &(head); \ + _hd_head->count--; \ + if (_hd_head->hh_head == (delhh)) { \ + _hd_head->hh_head = (delhh)->hh_next; \ + } \ + if ((delhh)->hh_prev) { \ + (delhh)->hh_prev->hh_next = (delhh)->hh_next; \ + } \ + if ((delhh)->hh_next) { \ + (delhh)->hh_next->hh_prev = (delhh)->hh_prev; \ + } \ + } while (0) + +/* Bucket expansion has the effect of doubling the number of buckets + * and redistributing the items into the new buckets. Ideally the + * items will distribute more or less evenly into the new buckets + * (the extent to which this is true is a measure of the quality of + * the hash function as it applies to the key domain). + * + * With the items distributed into more buckets, the chain length + * (item count) in each bucket is reduced. Thus by expanding buckets + * the hash keeps a bound on the chain length. This bounded chain + * length is the essence of how a hash provides constant time lookup. + * + * The calculation of tbl->ideal_chain_maxlen below deserves some + * explanation. First, keep in mind that we're calculating the ideal + * maximum chain length based on the *new* (doubled) bucket count. + * In fractions this is just n/b (n=number of items,b=new num buckets). + * Since the ideal chain length is an integer, we want to calculate + * ceil(n/b). We don't depend on floating point arithmetic in this + * hash, so to calculate ceil(n/b) with integers we could write + * + * ceil(n/b) = (n/b) + ((n%b)?1:0) + * + * and in fact a previous version of this hash did just that. + * But now we have improved things a bit by recognizing that b is + * always a power of two. We keep its base 2 log handy (call it lb), + * so now we can write this with a bit shift and logical AND: + * + * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) + * + */ +#define HASH_EXPAND_BUCKETS(hh, tbl, oomed) \ + do { \ + unsigned _he_bkt; \ + unsigned _he_bkt_i; \ + struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ + UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ + _he_new_buckets = (UT_hash_bucket *)uthash_malloc( \ + sizeof(struct UT_hash_bucket) * (tbl)->num_buckets * 2U); \ + if (!_he_new_buckets) { \ + HASH_RECORD_OOM(oomed); \ + } else { \ + uthash_bzero(_he_new_buckets, sizeof(struct UT_hash_bucket) * \ + (tbl)->num_buckets * 2U); \ + (tbl)->ideal_chain_maxlen = \ + ((tbl)->num_items >> ((tbl)->log2_num_buckets + 1U)) + \ + ((((tbl)->num_items & (((tbl)->num_buckets * 2U) - 1U)) != 0U) \ + ? 1U \ + : 0U); \ + (tbl)->nonideal_items = 0; \ + for (_he_bkt_i = 0; _he_bkt_i < (tbl)->num_buckets; _he_bkt_i++) { \ + _he_thh = (tbl)->buckets[_he_bkt_i].hh_head; \ + while (_he_thh != NULL) { \ + _he_hh_nxt = _he_thh->hh_next; \ + HASH_TO_BKT(_he_thh->hashv, (tbl)->num_buckets * 2U, \ + _he_bkt); \ + _he_newbkt = &(_he_new_buckets[_he_bkt]); \ + if (++(_he_newbkt->count) > (tbl)->ideal_chain_maxlen) { \ + (tbl)->nonideal_items++; \ + if (_he_newbkt->count > \ + _he_newbkt->expand_mult * \ + (tbl)->ideal_chain_maxlen) { \ + _he_newbkt->expand_mult++; \ + } \ + } \ + _he_thh->hh_prev = NULL; \ + _he_thh->hh_next = _he_newbkt->hh_head; \ + if (_he_newbkt->hh_head != NULL) { \ + _he_newbkt->hh_head->hh_prev = _he_thh; \ + } \ + _he_newbkt->hh_head = _he_thh; \ + _he_thh = _he_hh_nxt; \ + } \ + } \ + uthash_free((tbl)->buckets, \ + (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \ + (tbl)->num_buckets *= 2U; \ + (tbl)->log2_num_buckets++; \ + (tbl)->buckets = _he_new_buckets; \ + (tbl)->ineff_expands = \ + ((tbl)->nonideal_items > ((tbl)->num_items >> 1)) \ + ? ((tbl)->ineff_expands + 1U) \ + : 0U; \ + if ((tbl)->ineff_expands > 1U) { \ + (tbl)->noexpand = 1; \ + uthash_noexpand_fyi(tbl); \ + } \ + uthash_expand_fyi(tbl); \ + } \ + } while (0) + +/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ +/* Note that HASH_SORT assumes the hash handle name to be hh. + * HASH_SRT was added to allow the hash handle name to be passed in. */ +#define HASH_SORT(head, cmpfcn) HASH_SRT(hh, head, cmpfcn) +#define HASH_SRT(hh, head, cmpfcn) \ + do { \ + unsigned _hs_i; \ + unsigned _hs_looping, _hs_nmerges, _hs_insize, _hs_psize, _hs_qsize; \ + struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ + if (head != NULL) { \ + _hs_insize = 1; \ + _hs_looping = 1; \ + _hs_list = &((head)->hh); \ + while (_hs_looping != 0U) { \ + _hs_p = _hs_list; \ + _hs_list = NULL; \ + _hs_tail = NULL; \ + _hs_nmerges = 0; \ + while (_hs_p != NULL) { \ + _hs_nmerges++; \ + _hs_q = _hs_p; \ + _hs_psize = 0; \ + for (_hs_i = 0; _hs_i < _hs_insize; ++_hs_i) { \ + _hs_psize++; \ + _hs_q = \ + ((_hs_q->next != NULL) \ + ? HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) \ + : NULL); \ + if (_hs_q == NULL) { \ + break; \ + } \ + } \ + _hs_qsize = _hs_insize; \ + while ((_hs_psize != 0U) || \ + ((_hs_qsize != 0U) && (_hs_q != NULL))) { \ + if (_hs_psize == 0U) { \ + _hs_e = _hs_q; \ + _hs_q = ((_hs_q->next != NULL) \ + ? HH_FROM_ELMT((head)->hh.tbl, \ + _hs_q->next) \ + : NULL); \ + _hs_qsize--; \ + } else if ((_hs_qsize == 0U) || (_hs_q == NULL)) { \ + _hs_e = _hs_p; \ + if (_hs_p != NULL) { \ + _hs_p = ((_hs_p->next != NULL) \ + ? HH_FROM_ELMT((head)->hh.tbl, \ + _hs_p->next) \ + : NULL); \ + } \ + _hs_psize--; \ + } else if ((cmpfcn(DECLTYPE(head)(ELMT_FROM_HH( \ + (head)->hh.tbl, _hs_p)), \ + DECLTYPE(head)(ELMT_FROM_HH( \ + (head)->hh.tbl, _hs_q)))) <= \ + 0) { \ + _hs_e = _hs_p; \ + if (_hs_p != NULL) { \ + _hs_p = ((_hs_p->next != NULL) \ + ? HH_FROM_ELMT((head)->hh.tbl, \ + _hs_p->next) \ + : NULL); \ + } \ + _hs_psize--; \ + } else { \ + _hs_e = _hs_q; \ + _hs_q = ((_hs_q->next != NULL) \ + ? HH_FROM_ELMT((head)->hh.tbl, \ + _hs_q->next) \ + : NULL); \ + _hs_qsize--; \ + } \ + if (_hs_tail != NULL) { \ + _hs_tail->next = \ + ((_hs_e != NULL) \ + ? ELMT_FROM_HH((head)->hh.tbl, _hs_e) \ + : NULL); \ + } else { \ + _hs_list = _hs_e; \ + } \ + if (_hs_e != NULL) { \ + _hs_e->prev = \ + ((_hs_tail != NULL) \ + ? ELMT_FROM_HH((head)->hh.tbl, _hs_tail) \ + : NULL); \ + } \ + _hs_tail = _hs_e; \ + } \ + _hs_p = _hs_q; \ + } \ + if (_hs_tail != NULL) { \ + _hs_tail->next = NULL; \ + } \ + if (_hs_nmerges <= 1U) { \ + _hs_looping = 0; \ + (head)->hh.tbl->tail = _hs_tail; \ + DECLTYPE_ASSIGN(head, \ + ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ + } \ + _hs_insize *= 2U; \ + } \ + HASH_FSCK(hh, head, "HASH_SRT"); \ + } \ + } while (0) + +/* This function selects items from one hash into another hash. + * The end result is that the selected items have dual presence + * in both hashes. There is no copy of the items made; rather + * they are added into the new hash through a secondary hash + * hash handle that must be present in the structure. */ +#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ + do { \ + unsigned _src_bkt, _dst_bkt; \ + void *_last_elt = NULL, *_elt; \ + UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh = NULL; \ + ptrdiff_t _dst_hho = ((char *)(&(dst)->hh_dst) - (char *)(dst)); \ + if ((src) != NULL) { \ + for (_src_bkt = 0; _src_bkt < (src)->hh_src.tbl->num_buckets; \ + _src_bkt++) { \ + for (_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ + _src_hh != NULL; _src_hh = _src_hh->hh_next) { \ + _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ + if (cond(_elt)) { \ + IF_HASH_NONFATAL_OOM(int _hs_oomed = 0;) \ + _dst_hh = (UT_hash_handle *)(void *)(((char *)_elt) + \ + _dst_hho); \ + _dst_hh->key = _src_hh->key; \ + _dst_hh->keylen = _src_hh->keylen; \ + _dst_hh->hashv = _src_hh->hashv; \ + _dst_hh->prev = _last_elt; \ + _dst_hh->next = NULL; \ + if (_last_elt_hh != NULL) { \ + _last_elt_hh->next = _elt; \ + } \ + if ((dst) == NULL) { \ + DECLTYPE_ASSIGN(dst, _elt); \ + HASH_MAKE_TABLE(hh_dst, dst, _hs_oomed); \ + IF_HASH_NONFATAL_OOM(if (_hs_oomed) { \ + uthash_nonfatal_oom(_elt); \ + (dst) = NULL; \ + continue; \ + }) \ + } else { \ + _dst_hh->tbl = (dst)->hh_dst.tbl; \ + } \ + HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, \ + _dst_bkt); \ + HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt], \ + hh_dst, _dst_hh, _hs_oomed); \ + (dst)->hh_dst.tbl->num_items++; \ + IF_HASH_NONFATAL_OOM(if (_hs_oomed) { \ + HASH_ROLLBACK_BKT(hh_dst, dst, _dst_hh); \ + HASH_DELETE_HH(hh_dst, dst, _dst_hh); \ + _dst_hh->tbl = NULL; \ + uthash_nonfatal_oom(_elt); \ + continue; \ + }) \ + HASH_BLOOM_ADD(_dst_hh->tbl, _dst_hh->hashv); \ + _last_elt = _elt; \ + _last_elt_hh = _dst_hh; \ + } \ + } \ + } \ + } \ + HASH_FSCK(hh_dst, dst, "HASH_SELECT"); \ + } while (0) + +#define HASH_CLEAR(hh, head) \ + do { \ + if ((head) != NULL) { \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets * \ + sizeof(struct UT_hash_bucket)); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head) = NULL; \ + } \ + } while (0) + +#define HASH_OVERHEAD(hh, head) \ + (((head) != NULL) \ + ? ((size_t)(((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \ + ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \ + sizeof(UT_hash_table) + (HASH_BLOOM_BYTELEN))) \ + : 0U) + +#ifdef NO_DECLTYPE +#define HASH_ITER(hh, head, el, tmp) \ + for (((el) = (head)), \ + ((*(char **)(&(tmp))) = \ + (char *)((head != NULL) ? (head)->hh.next : NULL)); \ + (el) != NULL; ((el) = (tmp)), \ + ((*(char **)(&(tmp))) = \ + (char *)((tmp != NULL) ? (tmp)->hh.next : NULL))) +#else +#define HASH_ITER(hh, head, el, tmp) \ + for (((el) = (head)), \ + ((tmp) = DECLTYPE(el)((head != NULL) ? (head)->hh.next : NULL)); \ + (el) != NULL; \ + ((el) = (tmp)), \ + ((tmp) = DECLTYPE(el)((tmp != NULL) ? (tmp)->hh.next : NULL))) +#endif + +/* obtain a count of items in the hash */ +#define HASH_COUNT(head) HASH_CNT(hh, head) +#define HASH_CNT(hh, head) ((head != NULL) ? ((head)->hh.tbl->num_items) : 0U) + +typedef struct UT_hash_bucket { + struct UT_hash_handle *hh_head; + unsigned count; + + /* expand_mult is normally set to 0. In this situation, the max chain length + * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If + * the bucket's chain exceeds this length, bucket expansion is triggered). + * However, setting expand_mult to a non-zero value delays bucket expansion + * (that would be triggered by additions to this particular bucket) + * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. + * (The multiplier is simply expand_mult+1). The whole idea of this + * multiplier is to reduce bucket expansions, since they are expensive, in + * situations where we know that a particular bucket tends to be overused. + * It is better to let its chain length grow to a longer yet-still-bounded + * value, than to do an O(n) bucket expansion too often. + */ + unsigned expand_mult; + +} UT_hash_bucket; + +/* random signature used only to find hash tables in external analysis */ +#define HASH_SIGNATURE 0xa0111fe1u +#define HASH_BLOOM_SIGNATURE 0xb12220f2u + +typedef struct UT_hash_table { + UT_hash_bucket *buckets; + unsigned num_buckets, log2_num_buckets; + unsigned num_items; + struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ + ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ + + /* in an ideal situation (all buckets used equally), no bucket would have + * more than ceil(#items/#buckets) items. that's the ideal chain length. */ + unsigned ideal_chain_maxlen; + + /* nonideal_items is the number of items in the hash whose chain position + * exceeds the ideal chain maxlen. these items pay the penalty for an uneven + * hash distribution; reaching them in a chain traversal takes >ideal steps */ + unsigned nonideal_items; + + /* ineffective expands occur when a bucket doubling was performed, but + * afterward, more than half the items in the hash had nonideal chain + * positions. If this happens on two consecutive expansions we inhibit any + * further expansion, as it's not helping; this happens when the hash + * function isn't a good fit for the key domain. When expansion is inhibited + * the hash will still work, albeit no longer in constant time. */ + unsigned ineff_expands, noexpand; + + uint32_t signature; /* used only to find hash tables in external analysis */ +#ifdef HASH_BLOOM + uint32_t + bloom_sig; /* used only to test bloom exists in external analysis */ + uint8_t *bloom_bv; + uint8_t bloom_nbits; +#endif + +} UT_hash_table; + +typedef struct UT_hash_handle { + struct UT_hash_table *tbl; + void *prev; /* prev element in app order */ + void *next; /* next element in app order */ + struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ + struct UT_hash_handle *hh_next; /* next hh in bucket order */ + const void *key; /* ptr to enclosing struct's key */ + unsigned keylen; /* enclosing struct's key len */ + unsigned hashv; /* result of hash-fcn(key) */ +} UT_hash_handle; + +#endif /* UTHASH_H */ diff --git a/src/uthash/utlist.h b/src/uthash/utlist.h new file mode 100644 index 000000000..ed4660b49 --- /dev/null +++ b/src/uthash/utlist.h @@ -0,0 +1,1148 @@ +/* +Copyright (c) 2007-2022, Troy D. Hanson https://troydhanson.github.io/uthash/ +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef UTLIST_H +#define UTLIST_H + +#define UTLIST_VERSION 2.3.0 + +#include + +/* + * This file contains macros to manipulate singly and doubly-linked lists. + * + * 1. LL_ macros: singly-linked lists. + * 2. DL_ macros: doubly-linked lists. + * 3. CDL_ macros: circular doubly-linked lists. + * + * To use singly-linked lists, your structure must have a "next" pointer. + * To use doubly-linked lists, your structure must "prev" and "next" pointers. + * Either way, the pointer to the head of the list must be initialized to NULL. + * + * ----------------.EXAMPLE ------------------------- + * struct item { + * int id; + * struct item *prev, *next; + * } + * + * struct item *list = NULL: + * + * int main() { + * struct item *item; + * ... allocate and populate item ... + * DL_APPEND(list, item); + * } + * -------------------------------------------------- + * + * For doubly-linked lists, the append and delete macros are O(1) + * For singly-linked lists, append and delete are O(n) but prepend is O(1) + * The sort macro is O(n log(n)) for all types of single/double/circular lists. + */ + +/* These macros use decltype or the earlier __typeof GNU extension. + As decltype is only available in newer compilers (VS2010 or gcc 4.3+ + when compiling c++ source) this code uses whatever method is needed + or, for VS2008 where neither is available, uses casting workarounds. */ +#if !defined(LDECLTYPE) && !defined(NO_DECLTYPE) +#if defined(_MSC_VER) /* MS compiler */ +#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ +#define LDECLTYPE(x) decltype(x) +#else /* VS2008 or older (or VS2010 in C mode) */ +#define NO_DECLTYPE +#endif +#elif defined(__MCST__) /* Elbrus C Compiler */ +#define LDECLTYPE(x) __typeof(x) +#elif defined(__BORLANDC__) || defined(__ICCARM__) || defined(__LCC__) || \ + defined(__WATCOMC__) +#define NO_DECLTYPE +#else /* GNU, Sun and other compilers */ +#define LDECLTYPE(x) __typeof(x) +#endif +#endif + +/* for VS2008 we use some workarounds to get around the lack of decltype, + * namely, we always reassign our tmp variable to the list head if we need + * to dereference its prev/next pointers, and save/restore the real head.*/ +#ifdef NO_DECLTYPE +#define IF_NO_DECLTYPE(x) x +#define LDECLTYPE(x) char * +#define UTLIST_SV(elt, list) \ + _tmp = (char *)(list); \ + { \ + char **_alias = (char **)&(list); \ + *_alias = (elt); \ + } +#define UTLIST_NEXT(elt, list, next) ((char *)((list)->next)) +#define UTLIST_NEXTASGN(elt, list, to, next) \ + { \ + char **_alias = (char **)&((list)->next); \ + *_alias = (char *)(to); \ + } +/* #define UTLIST_PREV(elt,list,prev) ((char*)((list)->prev)) */ +#define UTLIST_PREVASGN(elt, list, to, prev) \ + { \ + char **_alias = (char **)&((list)->prev); \ + *_alias = (char *)(to); \ + } +#define UTLIST_RS(list) \ + { \ + char **_alias = (char **)&(list); \ + *_alias = _tmp; \ + } +#define UTLIST_CASTASGN(a, b) \ + { \ + char **_alias = (char **)&(a); \ + *_alias = (char *)(b); \ + } +#else +#define IF_NO_DECLTYPE(x) +#define UTLIST_SV(elt, list) +#define UTLIST_NEXT(elt, list, next) ((elt)->next) +#define UTLIST_NEXTASGN(elt, list, to, next) ((elt)->next) = (to) +/* #define UTLIST_PREV(elt,list,prev) ((elt)->prev) */ +#define UTLIST_PREVASGN(elt, list, to, prev) ((elt)->prev) = (to) +#define UTLIST_RS(list) +#define UTLIST_CASTASGN(a, b) (a) = (b) +#endif + +/****************************************************************************** + * The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort * + * Unwieldy variable names used here to avoid shadowing passed-in variables. * + *****************************************************************************/ +#define LL_SORT(list, cmp) LL_SORT2(list, cmp, next) + +#define LL_SORT2(list, cmp, next) \ + do { \ + LDECLTYPE(list) _ls_p; \ + LDECLTYPE(list) _ls_q; \ + LDECLTYPE(list) _ls_e; \ + LDECLTYPE(list) _ls_tail; \ + IF_NO_DECLTYPE(LDECLTYPE(list) _tmp;) \ + int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ + if (list) { \ + _ls_insize = 1; \ + _ls_looping = 1; \ + while (_ls_looping) { \ + UTLIST_CASTASGN(_ls_p, list); \ + (list) = NULL; \ + _ls_tail = NULL; \ + _ls_nmerges = 0; \ + while (_ls_p) { \ + _ls_nmerges++; \ + _ls_q = _ls_p; \ + _ls_psize = 0; \ + for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ + _ls_psize++; \ + UTLIST_SV(_ls_q, list); \ + _ls_q = UTLIST_NEXT(_ls_q, list, next); \ + UTLIST_RS(list); \ + if (!_ls_q) \ + break; \ + } \ + _ls_qsize = _ls_insize; \ + while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ + if (_ls_psize == 0) { \ + _ls_e = _ls_q; \ + UTLIST_SV(_ls_q, list); \ + _ls_q = UTLIST_NEXT(_ls_q, list, next); \ + UTLIST_RS(list); \ + _ls_qsize--; \ + } else if (_ls_qsize == 0 || !_ls_q) { \ + _ls_e = _ls_p; \ + UTLIST_SV(_ls_p, list); \ + _ls_p = UTLIST_NEXT(_ls_p, list, next); \ + UTLIST_RS(list); \ + _ls_psize--; \ + } else if (cmp(_ls_p, _ls_q) <= 0) { \ + _ls_e = _ls_p; \ + UTLIST_SV(_ls_p, list); \ + _ls_p = UTLIST_NEXT(_ls_p, list, next); \ + UTLIST_RS(list); \ + _ls_psize--; \ + } else { \ + _ls_e = _ls_q; \ + UTLIST_SV(_ls_q, list); \ + _ls_q = UTLIST_NEXT(_ls_q, list, next); \ + UTLIST_RS(list); \ + _ls_qsize--; \ + } \ + if (_ls_tail) { \ + UTLIST_SV(_ls_tail, list); \ + UTLIST_NEXTASGN(_ls_tail, list, _ls_e, next); \ + UTLIST_RS(list); \ + } else { \ + UTLIST_CASTASGN(list, _ls_e); \ + } \ + _ls_tail = _ls_e; \ + } \ + _ls_p = _ls_q; \ + } \ + if (_ls_tail) { \ + UTLIST_SV(_ls_tail, list); \ + UTLIST_NEXTASGN(_ls_tail, list, NULL, next); \ + UTLIST_RS(list); \ + } \ + if (_ls_nmerges <= 1) { \ + _ls_looping = 0; \ + } \ + _ls_insize *= 2; \ + } \ + } \ + } while (0) + +#define DL_SORT(list, cmp) DL_SORT2(list, cmp, prev, next) + +#define DL_SORT2(list, cmp, prev, next) \ + do { \ + LDECLTYPE(list) _ls_p; \ + LDECLTYPE(list) _ls_q; \ + LDECLTYPE(list) _ls_e; \ + LDECLTYPE(list) _ls_tail; \ + IF_NO_DECLTYPE(LDECLTYPE(list) _tmp;) \ + int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ + if (list) { \ + _ls_insize = 1; \ + _ls_looping = 1; \ + while (_ls_looping) { \ + UTLIST_CASTASGN(_ls_p, list); \ + (list) = NULL; \ + _ls_tail = NULL; \ + _ls_nmerges = 0; \ + while (_ls_p) { \ + _ls_nmerges++; \ + _ls_q = _ls_p; \ + _ls_psize = 0; \ + for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ + _ls_psize++; \ + UTLIST_SV(_ls_q, list); \ + _ls_q = UTLIST_NEXT(_ls_q, list, next); \ + UTLIST_RS(list); \ + if (!_ls_q) \ + break; \ + } \ + _ls_qsize = _ls_insize; \ + while ((_ls_psize > 0) || ((_ls_qsize > 0) && _ls_q)) { \ + if (_ls_psize == 0) { \ + _ls_e = _ls_q; \ + UTLIST_SV(_ls_q, list); \ + _ls_q = UTLIST_NEXT(_ls_q, list, next); \ + UTLIST_RS(list); \ + _ls_qsize--; \ + } else if ((_ls_qsize == 0) || (!_ls_q)) { \ + _ls_e = _ls_p; \ + UTLIST_SV(_ls_p, list); \ + _ls_p = UTLIST_NEXT(_ls_p, list, next); \ + UTLIST_RS(list); \ + _ls_psize--; \ + } else if (cmp(_ls_p, _ls_q) <= 0) { \ + _ls_e = _ls_p; \ + UTLIST_SV(_ls_p, list); \ + _ls_p = UTLIST_NEXT(_ls_p, list, next); \ + UTLIST_RS(list); \ + _ls_psize--; \ + } else { \ + _ls_e = _ls_q; \ + UTLIST_SV(_ls_q, list); \ + _ls_q = UTLIST_NEXT(_ls_q, list, next); \ + UTLIST_RS(list); \ + _ls_qsize--; \ + } \ + if (_ls_tail) { \ + UTLIST_SV(_ls_tail, list); \ + UTLIST_NEXTASGN(_ls_tail, list, _ls_e, next); \ + UTLIST_RS(list); \ + } else { \ + UTLIST_CASTASGN(list, _ls_e); \ + } \ + UTLIST_SV(_ls_e, list); \ + UTLIST_PREVASGN(_ls_e, list, _ls_tail, prev); \ + UTLIST_RS(list); \ + _ls_tail = _ls_e; \ + } \ + _ls_p = _ls_q; \ + } \ + UTLIST_CASTASGN((list)->prev, _ls_tail); \ + UTLIST_SV(_ls_tail, list); \ + UTLIST_NEXTASGN(_ls_tail, list, NULL, next); \ + UTLIST_RS(list); \ + if (_ls_nmerges <= 1) { \ + _ls_looping = 0; \ + } \ + _ls_insize *= 2; \ + } \ + } \ + } while (0) + +#define CDL_SORT(list, cmp) CDL_SORT2(list, cmp, prev, next) + +#define CDL_SORT2(list, cmp, prev, next) \ + do { \ + LDECLTYPE(list) _ls_p; \ + LDECLTYPE(list) _ls_q; \ + LDECLTYPE(list) _ls_e; \ + LDECLTYPE(list) _ls_tail; \ + LDECLTYPE(list) _ls_oldhead; \ + LDECLTYPE(list) _tmp; \ + int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \ + if (list) { \ + _ls_insize = 1; \ + _ls_looping = 1; \ + while (_ls_looping) { \ + UTLIST_CASTASGN(_ls_p, list); \ + UTLIST_CASTASGN(_ls_oldhead, list); \ + (list) = NULL; \ + _ls_tail = NULL; \ + _ls_nmerges = 0; \ + while (_ls_p) { \ + _ls_nmerges++; \ + _ls_q = _ls_p; \ + _ls_psize = 0; \ + for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \ + _ls_psize++; \ + UTLIST_SV(_ls_q, list); \ + if (UTLIST_NEXT(_ls_q, list, next) == _ls_oldhead) { \ + _ls_q = NULL; \ + } else { \ + _ls_q = UTLIST_NEXT(_ls_q, list, next); \ + } \ + UTLIST_RS(list); \ + if (!_ls_q) \ + break; \ + } \ + _ls_qsize = _ls_insize; \ + while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \ + if (_ls_psize == 0) { \ + _ls_e = _ls_q; \ + UTLIST_SV(_ls_q, list); \ + _ls_q = UTLIST_NEXT(_ls_q, list, next); \ + UTLIST_RS(list); \ + _ls_qsize--; \ + if (_ls_q == _ls_oldhead) { \ + _ls_q = NULL; \ + } \ + } else if (_ls_qsize == 0 || !_ls_q) { \ + _ls_e = _ls_p; \ + UTLIST_SV(_ls_p, list); \ + _ls_p = UTLIST_NEXT(_ls_p, list, next); \ + UTLIST_RS(list); \ + _ls_psize--; \ + if (_ls_p == _ls_oldhead) { \ + _ls_p = NULL; \ + } \ + } else if (cmp(_ls_p, _ls_q) <= 0) { \ + _ls_e = _ls_p; \ + UTLIST_SV(_ls_p, list); \ + _ls_p = UTLIST_NEXT(_ls_p, list, next); \ + UTLIST_RS(list); \ + _ls_psize--; \ + if (_ls_p == _ls_oldhead) { \ + _ls_p = NULL; \ + } \ + } else { \ + _ls_e = _ls_q; \ + UTLIST_SV(_ls_q, list); \ + _ls_q = UTLIST_NEXT(_ls_q, list, next); \ + UTLIST_RS(list); \ + _ls_qsize--; \ + if (_ls_q == _ls_oldhead) { \ + _ls_q = NULL; \ + } \ + } \ + if (_ls_tail) { \ + UTLIST_SV(_ls_tail, list); \ + UTLIST_NEXTASGN(_ls_tail, list, _ls_e, next); \ + UTLIST_RS(list); \ + } else { \ + UTLIST_CASTASGN(list, _ls_e); \ + } \ + UTLIST_SV(_ls_e, list); \ + UTLIST_PREVASGN(_ls_e, list, _ls_tail, prev); \ + UTLIST_RS(list); \ + _ls_tail = _ls_e; \ + } \ + _ls_p = _ls_q; \ + } \ + UTLIST_CASTASGN((list)->prev, _ls_tail); \ + UTLIST_CASTASGN(_tmp, list); \ + UTLIST_SV(_ls_tail, list); \ + UTLIST_NEXTASGN(_ls_tail, list, _tmp, next); \ + UTLIST_RS(list); \ + if (_ls_nmerges <= 1) { \ + _ls_looping = 0; \ + } \ + _ls_insize *= 2; \ + } \ + } \ + } while (0) + +/****************************************************************************** + * singly linked list macros (non-circular) * + *****************************************************************************/ +#define LL_PREPEND(head, add) LL_PREPEND2(head, add, next) + +#define LL_PREPEND2(head, add, next) \ + do { \ + (add)->next = (head); \ + (head) = (add); \ + } while (0) + +#define LL_CONCAT(head1, head2) LL_CONCAT2(head1, head2, next) + +#define LL_CONCAT2(head1, head2, next) \ + do { \ + LDECLTYPE(head1) _tmp; \ + if (head1) { \ + _tmp = (head1); \ + while (_tmp->next) { \ + _tmp = _tmp->next; \ + } \ + _tmp->next = (head2); \ + } else { \ + (head1) = (head2); \ + } \ + } while (0) + +#define LL_APPEND(head, add) LL_APPEND2(head, add, next) + +#define LL_APPEND2(head, add, next) \ + do { \ + LDECLTYPE(head) _tmp; \ + (add)->next = NULL; \ + if (head) { \ + _tmp = (head); \ + while (_tmp->next) { \ + _tmp = _tmp->next; \ + } \ + _tmp->next = (add); \ + } else { \ + (head) = (add); \ + } \ + } while (0) + +#define LL_INSERT_INORDER(head, add, cmp) \ + LL_INSERT_INORDER2(head, add, cmp, next) + +#define LL_INSERT_INORDER2(head, add, cmp, next) \ + do { \ + LDECLTYPE(head) _tmp; \ + if (head) { \ + LL_LOWER_BOUND2(head, _tmp, add, cmp, next); \ + LL_APPEND_ELEM2(head, _tmp, add, next); \ + } else { \ + (head) = (add); \ + (head)->next = NULL; \ + } \ + } while (0) + +#define LL_LOWER_BOUND(head, elt, like, cmp) \ + LL_LOWER_BOUND2(head, elt, like, cmp, next) + +#define LL_LOWER_BOUND2(head, elt, like, cmp, next) \ + do { \ + if ((head) == NULL || (cmp(head, like)) >= 0) { \ + (elt) = NULL; \ + } else { \ + for ((elt) = (head); (elt)->next != NULL; (elt) = (elt)->next) { \ + if (cmp((elt)->next, like) >= 0) { \ + break; \ + } \ + } \ + } \ + } while (0) + +#define LL_DELETE(head, del) LL_DELETE2(head, del, next) + +#define LL_DELETE2(head, del, next) \ + do { \ + LDECLTYPE(head) _tmp; \ + if ((head) == (del)) { \ + (head) = (head)->next; \ + } else { \ + _tmp = (head); \ + while (_tmp->next && (_tmp->next != (del))) { \ + _tmp = _tmp->next; \ + } \ + if (_tmp->next) { \ + _tmp->next = (del)->next; \ + } \ + } \ + } while (0) + +#define LL_COUNT(head, el, counter) LL_COUNT2(head, el, counter, next) + +#define LL_COUNT2(head, el, counter, next) \ + do { \ + (counter) = 0; \ + LL_FOREACH2(head, el, next) { ++(counter); } \ + } while (0) + +#define LL_FOREACH(head, el) LL_FOREACH2(head, el, next) + +#define LL_FOREACH2(head, el, next) for ((el) = (head); el; (el) = (el)->next) + +#define LL_FOREACH_SAFE(head, el, tmp) LL_FOREACH_SAFE2(head, el, tmp, next) + +#define LL_FOREACH_SAFE2(head, el, tmp, next) \ + for ((el) = (head); (el) && ((tmp) = (el)->next, 1); (el) = (tmp)) + +#define LL_SEARCH_SCALAR(head, out, field, val) \ + LL_SEARCH_SCALAR2(head, out, field, val, next) + +#define LL_SEARCH_SCALAR2(head, out, field, val, next) \ + do { \ + LL_FOREACH2(head, out, next) { \ + if ((out)->field == (val)) \ + break; \ + } \ + } while (0) + +#define LL_SEARCH(head, out, elt, cmp) LL_SEARCH2(head, out, elt, cmp, next) + +#define LL_SEARCH2(head, out, elt, cmp, next) \ + do { \ + LL_FOREACH2(head, out, next) { \ + if ((cmp(out, elt)) == 0) \ + break; \ + } \ + } while (0) + +#define LL_REPLACE_ELEM2(head, el, add, next) \ + do { \ + LDECLTYPE(head) _tmp; \ + assert((head) != NULL); \ + assert((el) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el)->next; \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + _tmp = (head); \ + while (_tmp->next && (_tmp->next != (el))) { \ + _tmp = _tmp->next; \ + } \ + if (_tmp->next) { \ + _tmp->next = (add); \ + } \ + } \ + } while (0) + +#define LL_REPLACE_ELEM(head, el, add) LL_REPLACE_ELEM2(head, el, add, next) + +#define LL_PREPEND_ELEM2(head, el, add, next) \ + do { \ + if (el) { \ + LDECLTYPE(head) _tmp; \ + assert((head) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el); \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + _tmp = (head); \ + while (_tmp->next && (_tmp->next != (el))) { \ + _tmp = _tmp->next; \ + } \ + if (_tmp->next) { \ + _tmp->next = (add); \ + } \ + } \ + } else { \ + LL_APPEND2(head, add, next); \ + } \ + } while (0) + +#define LL_PREPEND_ELEM(head, el, add) LL_PREPEND_ELEM2(head, el, add, next) + +#define LL_APPEND_ELEM2(head, el, add, next) \ + do { \ + if (el) { \ + assert((head) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el)->next; \ + (el)->next = (add); \ + } else { \ + LL_PREPEND2(head, add, next); \ + } \ + } while (0) + +#define LL_APPEND_ELEM(head, el, add) LL_APPEND_ELEM2(head, el, add, next) + +#ifdef NO_DECLTYPE +/* Here are VS2008 / NO_DECLTYPE replacements for a few functions */ + +#undef LL_CONCAT2 +#define LL_CONCAT2(head1, head2, next) \ + do { \ + char *_tmp; \ + if (head1) { \ + _tmp = (char *)(head1); \ + while ((head1)->next) { \ + (head1) = (head1)->next; \ + } \ + (head1)->next = (head2); \ + UTLIST_RS(head1); \ + } else { \ + (head1) = (head2); \ + } \ + } while (0) + +#undef LL_APPEND2 +#define LL_APPEND2(head, add, next) \ + do { \ + if (head) { \ + (add)->next = head; /* use add->next as a temp variable */ \ + while ((add)->next->next) { \ + (add)->next = (add)->next->next; \ + } \ + (add)->next->next = (add); \ + } else { \ + (head) = (add); \ + } \ + (add)->next = NULL; \ + } while (0) + +#undef LL_INSERT_INORDER2 +#define LL_INSERT_INORDER2(head, add, cmp, next) \ + do { \ + if ((head) == NULL || (cmp(head, add)) >= 0) { \ + (add)->next = (head); \ + (head) = (add); \ + } else { \ + char *_tmp = (char *)(head); \ + while ((head)->next != NULL && (cmp((head)->next, add)) < 0) { \ + (head) = (head)->next; \ + } \ + (add)->next = (head)->next; \ + (head)->next = (add); \ + UTLIST_RS(head); \ + } \ + } while (0) + +#undef LL_DELETE2 +#define LL_DELETE2(head, del, next) \ + do { \ + if ((head) == (del)) { \ + (head) = (head)->next; \ + } else { \ + char *_tmp = (char *)(head); \ + while ((head)->next && ((head)->next != (del))) { \ + (head) = (head)->next; \ + } \ + if ((head)->next) { \ + (head)->next = ((del)->next); \ + } \ + UTLIST_RS(head); \ + } \ + } while (0) + +#undef LL_REPLACE_ELEM2 +#define LL_REPLACE_ELEM2(head, el, add, next) \ + do { \ + assert((head) != NULL); \ + assert((el) != NULL); \ + assert((add) != NULL); \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + (add)->next = head; \ + while ((add)->next->next && ((add)->next->next != (el))) { \ + (add)->next = (add)->next->next; \ + } \ + if ((add)->next->next) { \ + (add)->next->next = (add); \ + } \ + } \ + (add)->next = (el)->next; \ + } while (0) + +#undef LL_PREPEND_ELEM2 +#define LL_PREPEND_ELEM2(head, el, add, next) \ + do { \ + if (el) { \ + assert((head) != NULL); \ + assert((add) != NULL); \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + (add)->next = (head); \ + while ((add)->next->next && ((add)->next->next != (el))) { \ + (add)->next = (add)->next->next; \ + } \ + if ((add)->next->next) { \ + (add)->next->next = (add); \ + } \ + } \ + (add)->next = (el); \ + } else { \ + LL_APPEND2(head, add, next); \ + } \ + } while (0) + +#endif /* NO_DECLTYPE */ + +/****************************************************************************** + * doubly linked list macros (non-circular) * + *****************************************************************************/ +#define DL_PREPEND(head, add) DL_PREPEND2(head, add, prev, next) + +#define DL_PREPEND2(head, add, prev, next) \ + do { \ + (add)->next = (head); \ + if (head) { \ + (add)->prev = (head)->prev; \ + (head)->prev = (add); \ + } else { \ + (add)->prev = (add); \ + } \ + (head) = (add); \ + } while (0) + +#define DL_APPEND(head, add) DL_APPEND2(head, add, prev, next) + +#define DL_APPEND2(head, add, prev, next) \ + do { \ + if (head) { \ + (add)->prev = (head)->prev; \ + (head)->prev->next = (add); \ + (head)->prev = (add); \ + (add)->next = NULL; \ + } else { \ + (head) = (add); \ + (head)->prev = (head); \ + (head)->next = NULL; \ + } \ + } while (0) + +#define DL_INSERT_INORDER(head, add, cmp) \ + DL_INSERT_INORDER2(head, add, cmp, prev, next) + +#define DL_INSERT_INORDER2(head, add, cmp, prev, next) \ + do { \ + LDECLTYPE(head) _tmp; \ + if (head) { \ + DL_LOWER_BOUND2(head, _tmp, add, cmp, next); \ + DL_APPEND_ELEM2(head, _tmp, add, prev, next); \ + } else { \ + (head) = (add); \ + (head)->prev = (head); \ + (head)->next = NULL; \ + } \ + } while (0) + +#define DL_LOWER_BOUND(head, elt, like, cmp) \ + DL_LOWER_BOUND2(head, elt, like, cmp, next) + +#define DL_LOWER_BOUND2(head, elt, like, cmp, next) \ + do { \ + if ((head) == NULL || (cmp(head, like)) >= 0) { \ + (elt) = NULL; \ + } else { \ + for ((elt) = (head); (elt)->next != NULL; (elt) = (elt)->next) { \ + if ((cmp((elt)->next, like)) >= 0) { \ + break; \ + } \ + } \ + } \ + } while (0) + +#define DL_CONCAT(head1, head2) DL_CONCAT2(head1, head2, prev, next) + +#define DL_CONCAT2(head1, head2, prev, next) \ + do { \ + LDECLTYPE(head1) _tmp; \ + if (head2) { \ + if (head1) { \ + UTLIST_CASTASGN(_tmp, (head2)->prev); \ + (head2)->prev = (head1)->prev; \ + (head1)->prev->next = (head2); \ + UTLIST_CASTASGN((head1)->prev, _tmp); \ + } else { \ + (head1) = (head2); \ + } \ + } \ + } while (0) + +#define DL_DELETE(head, del) DL_DELETE2(head, del, prev, next) + +#define DL_DELETE2(head, del, prev, next) \ + do { \ + assert((head) != NULL); \ + assert((del)->prev != NULL); \ + if ((del)->prev == (del)) { \ + (head) = NULL; \ + } else if ((del) == (head)) { \ + assert((del)->next != NULL); \ + (del)->next->prev = (del)->prev; \ + (head) = (del)->next; \ + } else { \ + (del)->prev->next = (del)->next; \ + if ((del)->next) { \ + (del)->next->prev = (del)->prev; \ + } else { \ + (head)->prev = (del)->prev; \ + } \ + } \ + } while (0) + +#define DL_COUNT(head, el, counter) DL_COUNT2(head, el, counter, next) + +#define DL_COUNT2(head, el, counter, next) \ + do { \ + (counter) = 0; \ + DL_FOREACH2(head, el, next) { ++(counter); } \ + } while (0) + +#define DL_FOREACH(head, el) DL_FOREACH2(head, el, next) + +#define DL_FOREACH2(head, el, next) for ((el) = (head); el; (el) = (el)->next) + +/* this version is safe for deleting the elements during iteration */ +#define DL_FOREACH_SAFE(head, el, tmp) DL_FOREACH_SAFE2(head, el, tmp, next) + +#define DL_FOREACH_SAFE2(head, el, tmp, next) \ + for ((el) = (head); (el) && ((tmp) = (el)->next, 1); (el) = (tmp)) + +/* these are identical to their singly-linked list counterparts */ +#define DL_SEARCH_SCALAR LL_SEARCH_SCALAR +#define DL_SEARCH LL_SEARCH +#define DL_SEARCH_SCALAR2 LL_SEARCH_SCALAR2 +#define DL_SEARCH2 LL_SEARCH2 + +#define DL_REPLACE_ELEM2(head, el, add, prev, next) \ + do { \ + assert((head) != NULL); \ + assert((el) != NULL); \ + assert((add) != NULL); \ + if ((head) == (el)) { \ + (head) = (add); \ + (add)->next = (el)->next; \ + if ((el)->next == NULL) { \ + (add)->prev = (add); \ + } else { \ + (add)->prev = (el)->prev; \ + (add)->next->prev = (add); \ + } \ + } else { \ + (add)->next = (el)->next; \ + (add)->prev = (el)->prev; \ + (add)->prev->next = (add); \ + if ((el)->next == NULL) { \ + (head)->prev = (add); \ + } else { \ + (add)->next->prev = (add); \ + } \ + } \ + } while (0) + +#define DL_REPLACE_ELEM(head, el, add) \ + DL_REPLACE_ELEM2(head, el, add, prev, next) + +#define DL_PREPEND_ELEM2(head, el, add, prev, next) \ + do { \ + if (el) { \ + assert((head) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el); \ + (add)->prev = (el)->prev; \ + (el)->prev = (add); \ + if ((head) == (el)) { \ + (head) = (add); \ + } else { \ + (add)->prev->next = (add); \ + } \ + } else { \ + DL_APPEND2(head, add, prev, next); \ + } \ + } while (0) + +#define DL_PREPEND_ELEM(head, el, add) \ + DL_PREPEND_ELEM2(head, el, add, prev, next) + +#define DL_APPEND_ELEM2(head, el, add, prev, next) \ + do { \ + if (el) { \ + assert((head) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el)->next; \ + (add)->prev = (el); \ + (el)->next = (add); \ + if ((add)->next) { \ + (add)->next->prev = (add); \ + } else { \ + (head)->prev = (add); \ + } \ + } else { \ + DL_PREPEND2(head, add, prev, next); \ + } \ + } while (0) + +#define DL_APPEND_ELEM(head, el, add) DL_APPEND_ELEM2(head, el, add, prev, next) + +#ifdef NO_DECLTYPE +/* Here are VS2008 / NO_DECLTYPE replacements for a few functions */ + +#undef DL_INSERT_INORDER2 +#define DL_INSERT_INORDER2(head, add, cmp, prev, next) \ + do { \ + if ((head) == NULL) { \ + (add)->prev = (add); \ + (add)->next = NULL; \ + (head) = (add); \ + } else if ((cmp(head, add)) >= 0) { \ + (add)->prev = (head)->prev; \ + (add)->next = (head); \ + (head)->prev = (add); \ + (head) = (add); \ + } else { \ + char *_tmp = (char *)(head); \ + while ((head)->next && (cmp((head)->next, add)) < 0) { \ + (head) = (head)->next; \ + } \ + (add)->prev = (head); \ + (add)->next = (head)->next; \ + (head)->next = (add); \ + UTLIST_RS(head); \ + if ((add)->next) { \ + (add)->next->prev = (add); \ + } else { \ + (head)->prev = (add); \ + } \ + } \ + } while (0) +#endif /* NO_DECLTYPE */ + +/****************************************************************************** + * circular doubly linked list macros * + *****************************************************************************/ +#define CDL_APPEND(head, add) CDL_APPEND2(head, add, prev, next) + +#define CDL_APPEND2(head, add, prev, next) \ + do { \ + if (head) { \ + (add)->prev = (head)->prev; \ + (add)->next = (head); \ + (head)->prev = (add); \ + (add)->prev->next = (add); \ + } else { \ + (add)->prev = (add); \ + (add)->next = (add); \ + (head) = (add); \ + } \ + } while (0) + +#define CDL_PREPEND(head, add) CDL_PREPEND2(head, add, prev, next) + +#define CDL_PREPEND2(head, add, prev, next) \ + do { \ + if (head) { \ + (add)->prev = (head)->prev; \ + (add)->next = (head); \ + (head)->prev = (add); \ + (add)->prev->next = (add); \ + } else { \ + (add)->prev = (add); \ + (add)->next = (add); \ + } \ + (head) = (add); \ + } while (0) + +#define CDL_INSERT_INORDER(head, add, cmp) \ + CDL_INSERT_INORDER2(head, add, cmp, prev, next) + +#define CDL_INSERT_INORDER2(head, add, cmp, prev, next) \ + do { \ + LDECLTYPE(head) _tmp; \ + if (head) { \ + CDL_LOWER_BOUND2(head, _tmp, add, cmp, next); \ + CDL_APPEND_ELEM2(head, _tmp, add, prev, next); \ + } else { \ + (head) = (add); \ + (head)->next = (head); \ + (head)->prev = (head); \ + } \ + } while (0) + +#define CDL_LOWER_BOUND(head, elt, like, cmp) \ + CDL_LOWER_BOUND2(head, elt, like, cmp, next) + +#define CDL_LOWER_BOUND2(head, elt, like, cmp, next) \ + do { \ + if ((head) == NULL || (cmp(head, like)) >= 0) { \ + (elt) = NULL; \ + } else { \ + for ((elt) = (head); (elt)->next != (head); (elt) = (elt)->next) { \ + if ((cmp((elt)->next, like)) >= 0) { \ + break; \ + } \ + } \ + } \ + } while (0) + +#define CDL_DELETE(head, del) CDL_DELETE2(head, del, prev, next) + +#define CDL_DELETE2(head, del, prev, next) \ + do { \ + if (((head) == (del)) && ((head)->next == (head))) { \ + (head) = NULL; \ + } else { \ + (del)->next->prev = (del)->prev; \ + (del)->prev->next = (del)->next; \ + if ((del) == (head)) \ + (head) = (del)->next; \ + } \ + } while (0) + +#define CDL_COUNT(head, el, counter) CDL_COUNT2(head, el, counter, next) + +#define CDL_COUNT2(head, el, counter, next) \ + do { \ + (counter) = 0; \ + CDL_FOREACH2(head, el, next) { ++(counter); } \ + } while (0) + +#define CDL_FOREACH(head, el) CDL_FOREACH2(head, el, next) + +#define CDL_FOREACH2(head, el, next) \ + for ((el) = (head); el; (el) = (((el)->next == (head)) ? NULL : (el)->next)) + +#define CDL_FOREACH_SAFE(head, el, tmp1, tmp2) \ + CDL_FOREACH_SAFE2(head, el, tmp1, tmp2, prev, next) + +#define CDL_FOREACH_SAFE2(head, el, tmp1, tmp2, prev, next) \ + for ((el) = (head), (tmp1) = (head) ? (head)->prev : NULL; \ + (el) && ((tmp2) = (el)->next, 1); \ + (el) = ((el) == (tmp1) ? NULL : (tmp2))) + +#define CDL_SEARCH_SCALAR(head, out, field, val) \ + CDL_SEARCH_SCALAR2(head, out, field, val, next) + +#define CDL_SEARCH_SCALAR2(head, out, field, val, next) \ + do { \ + CDL_FOREACH2(head, out, next) { \ + if ((out)->field == (val)) \ + break; \ + } \ + } while (0) + +#define CDL_SEARCH(head, out, elt, cmp) CDL_SEARCH2(head, out, elt, cmp, next) + +#define CDL_SEARCH2(head, out, elt, cmp, next) \ + do { \ + CDL_FOREACH2(head, out, next) { \ + if ((cmp(out, elt)) == 0) \ + break; \ + } \ + } while (0) + +#define CDL_REPLACE_ELEM2(head, el, add, prev, next) \ + do { \ + assert((head) != NULL); \ + assert((el) != NULL); \ + assert((add) != NULL); \ + if ((el)->next == (el)) { \ + (add)->next = (add); \ + (add)->prev = (add); \ + (head) = (add); \ + } else { \ + (add)->next = (el)->next; \ + (add)->prev = (el)->prev; \ + (add)->next->prev = (add); \ + (add)->prev->next = (add); \ + if ((head) == (el)) { \ + (head) = (add); \ + } \ + } \ + } while (0) + +#define CDL_REPLACE_ELEM(head, el, add) \ + CDL_REPLACE_ELEM2(head, el, add, prev, next) + +#define CDL_PREPEND_ELEM2(head, el, add, prev, next) \ + do { \ + if (el) { \ + assert((head) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el); \ + (add)->prev = (el)->prev; \ + (el)->prev = (add); \ + (add)->prev->next = (add); \ + if ((head) == (el)) { \ + (head) = (add); \ + } \ + } else { \ + CDL_APPEND2(head, add, prev, next); \ + } \ + } while (0) + +#define CDL_PREPEND_ELEM(head, el, add) \ + CDL_PREPEND_ELEM2(head, el, add, prev, next) + +#define CDL_APPEND_ELEM2(head, el, add, prev, next) \ + do { \ + if (el) { \ + assert((head) != NULL); \ + assert((add) != NULL); \ + (add)->next = (el)->next; \ + (add)->prev = (el); \ + (el)->next = (add); \ + (add)->next->prev = (add); \ + } else { \ + CDL_PREPEND2(head, add, prev, next); \ + } \ + } while (0) + +#define CDL_APPEND_ELEM(head, el, add) \ + CDL_APPEND_ELEM2(head, el, add, prev, next) + +#ifdef NO_DECLTYPE +/* Here are VS2008 / NO_DECLTYPE replacements for a few functions */ + +#undef CDL_INSERT_INORDER2 +#define CDL_INSERT_INORDER2(head, add, cmp, prev, next) \ + do { \ + if ((head) == NULL) { \ + (add)->prev = (add); \ + (add)->next = (add); \ + (head) = (add); \ + } else if ((cmp(head, add)) >= 0) { \ + (add)->prev = (head)->prev; \ + (add)->next = (head); \ + (add)->prev->next = (add); \ + (head)->prev = (add); \ + (head) = (add); \ + } else { \ + char *_tmp = (char *)(head); \ + while ((char *)(head)->next != _tmp && \ + (cmp((head)->next, add)) < 0) { \ + (head) = (head)->next; \ + } \ + (add)->prev = (head); \ + (add)->next = (head)->next; \ + (add)->next->prev = (add); \ + (head)->next = (add); \ + UTLIST_RS(head); \ + } \ + } while (0) +#endif /* NO_DECLTYPE */ + +#endif /* UTLIST_H */ From 7278552b76f3123ec8590035013e019d377ad30b Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Tue, 1 Oct 2024 16:17:42 +0200 Subject: [PATCH 273/352] Use the UMF base allocator in UThash --- src/uthash/uthash.h | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/uthash/uthash.h b/src/uthash/uthash.h index 97e384d12..6058e638e 100644 --- a/src/uthash/uthash.h +++ b/src/uthash/uthash.h @@ -1,4 +1,5 @@ /* +Copyright (C) 2024 Intel Corporation Copyright (c) 2003-2022, Troy D. Hanson https://troydhanson.github.io/uthash/ All rights reserved. @@ -21,6 +22,12 @@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/* +Modifications by Intel: +- define uthash_malloc unconditional as a umf_ba_global_alloc +- define uthash_free unconditional as a umf_ba_global_free +*/ + #ifndef UTHASH_H #define UTHASH_H @@ -30,6 +37,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include /* exit */ #include /* memcmp, memset, strlen */ +#include "base_alloc_global.h" + #if defined(HASH_DEFINE_OWN_STDINT) && HASH_DEFINE_OWN_STDINT /* This codepath is provided for backward compatibility, but I plan to remove it. */ #warning \ @@ -76,12 +85,9 @@ typedef unsigned char uint8_t; } while (0) #endif -#ifndef uthash_malloc -#define uthash_malloc(sz) malloc(sz) /* malloc fcn */ -#endif -#ifndef uthash_free -#define uthash_free(ptr, sz) free(ptr) /* free fcn */ -#endif +#define uthash_malloc(sz) umf_ba_global_alloc(sz) /* malloc fcn */ +#define uthash_free(ptr, sz) umf_ba_global_free(ptr) /* free fcn */ + #ifndef uthash_bzero #define uthash_bzero(a, n) memset(a, '\0', n) #endif From e574428a82d82be1c16ff29d78dd90028e069970 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Tue, 4 Jun 2024 14:14:53 +0200 Subject: [PATCH 274/352] Enable IPC cache for Open/Close functions --- src/CMakeLists.txt | 2 + src/ipc.c | 2 + src/ipc_cache.c | 237 +++++++++++++++++++++++++++++++ src/ipc_cache.h | 52 +++++++ src/ipc_internal.h | 6 +- src/libumf.c | 13 +- src/provider/provider_tracking.c | 216 +++++++++++++++++++--------- test/ipcFixtures.hpp | 6 +- 8 files changed, 459 insertions(+), 75 deletions(-) create mode 100644 src/ipc_cache.c create mode 100644 src/ipc_cache.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7078d629f..50ce0f3f4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -46,6 +46,7 @@ set(UMF_SOURCES ${BA_SOURCES} libumf.c ipc.c + ipc_cache.c memory_pool.c memory_provider.c memory_provider_get_last_failed.c @@ -189,6 +190,7 @@ target_include_directories( $ $ $ + $ $) install(TARGETS umf EXPORT ${PROJECT_NAME}-targets) diff --git a/src/ipc.c b/src/ipc.c index f7497b340..45e098619 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -90,6 +90,8 @@ umf_result_t umfGetIPCHandle(const void *ptr, umf_ipc_handle_t *umfIPCHandle, return ret; } + // ipcData->handle_id is filled by tracking provider + ipcData->base = allocInfo.base; ipcData->pid = utils_getpid(); ipcData->baseSize = allocInfo.baseSize; ipcData->offset = (uintptr_t)ptr - (uintptr_t)allocInfo.base; diff --git a/src/ipc_cache.c b/src/ipc_cache.c new file mode 100644 index 000000000..bff251b2e --- /dev/null +++ b/src/ipc_cache.c @@ -0,0 +1,237 @@ +/* + * + * Copyright (C) 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 "base_alloc_global.h" +#include "ipc_cache.h" +#include "uthash.h" +#include "utils_common.h" +#include "utils_concurrency.h" +#include "utils_log.h" +#include "utlist.h" + +struct ipc_handle_cache_entry_t; + +typedef struct ipc_handle_cache_entry_t *hash_map_t; +typedef struct ipc_handle_cache_entry_t *lru_list_t; + +typedef struct ipc_handle_cache_entry_t { + UT_hash_handle hh; + struct ipc_handle_cache_entry_t *next, *prev; + ipc_mapped_handle_cache_key_t key; + uint64_t ref_count; + uint64_t handle_id; + hash_map_t + *hash_table; // pointer to the hash table to which the entry belongs + ipc_mapped_handle_cache_value_t value; +} ipc_handle_cache_entry_t; + +typedef struct ipc_mapped_handle_cache_global_t { + utils_mutex_t cache_lock; + umf_ba_pool_t *cache_allocator; + size_t max_size; + size_t cur_size; + lru_list_t lru_list; +} ipc_mapped_handle_cache_global_t; + +typedef struct ipc_mapped_handle_cache_t { + ipc_mapped_handle_cache_global_t *global; + hash_map_t hash_table; + ipc_mapped_handle_cache_eviction_cb_t eviction_cb; +} ipc_mapped_handle_cache_t; + +ipc_mapped_handle_cache_global_t *IPC_MAPPED_CACHE_GLOBAL = NULL; + +umf_result_t umfIpcCacheGlobalInit(void) { + umf_result_t ret = UMF_RESULT_SUCCESS; + ipc_mapped_handle_cache_global_t *cache_global = + umf_ba_global_alloc(sizeof(*cache_global)); + if (!cache_global) { + LOG_ERR("Failed to allocate memory for the IPC cache global data"); + ret = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + goto err_exit; + } + + if (NULL == utils_mutex_init(&(cache_global->cache_lock))) { + LOG_ERR("Failed to initialize mutex for the IPC global cache"); + ret = UMF_RESULT_ERROR_UNKNOWN; + goto err_cache_global_free; + } + + cache_global->cache_allocator = + umf_ba_create(sizeof(ipc_handle_cache_entry_t)); + if (!cache_global->cache_allocator) { + LOG_ERR("Failed to create IPC cache allocator"); + ret = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + goto err_mutex_destroy; + } + + // TODO: make max_size configurable via environment variable + cache_global->max_size = 0; + cache_global->cur_size = 0; + cache_global->lru_list = NULL; + + IPC_MAPPED_CACHE_GLOBAL = cache_global; + goto err_exit; + +err_mutex_destroy: + utils_mutex_destroy_not_free(&(cache_global->cache_lock)); +err_cache_global_free: + umf_ba_global_free(cache_global); +err_exit: + return ret; +} + +static size_t getGlobalLruListSize(lru_list_t lru_list) { + size_t size = 0; + ipc_handle_cache_entry_t *tmp; + DL_COUNT(lru_list, tmp, size); + return size; +} + +void umfIpcCacheGlobalTearDown(void) { + ipc_mapped_handle_cache_global_t *cache_global = IPC_MAPPED_CACHE_GLOBAL; + IPC_MAPPED_CACHE_GLOBAL = NULL; + + if (!cache_global) { + return; + } + + assert(cache_global->cur_size == 0); + assert(getGlobalLruListSize(cache_global->lru_list) == 0); + + umf_ba_destroy(cache_global->cache_allocator); + utils_mutex_destroy_not_free(&(cache_global->cache_lock)); + umf_ba_global_free(cache_global); +} + +ipc_mapped_handle_cache_handle_t umfIpcHandleMappedCacheCreate( + ipc_mapped_handle_cache_eviction_cb_t eviction_cb) { + if (eviction_cb == NULL) { + LOG_ERR("Eviction callback is NULL"); + return NULL; + } + + ipc_mapped_handle_cache_t *cache = umf_ba_global_alloc(sizeof(*cache)); + + if (!cache) { + LOG_ERR("Failed to allocate memory for the IPC cache"); + return NULL; + } + + assert(IPC_MAPPED_CACHE_GLOBAL != NULL); + + cache->global = IPC_MAPPED_CACHE_GLOBAL; + cache->hash_table = NULL; + cache->eviction_cb = eviction_cb; + + return cache; +} + +void umfIpcHandleMappedCacheDestroy(ipc_mapped_handle_cache_handle_t cache) { + ipc_handle_cache_entry_t *entry, *tmp; + HASH_ITER(hh, cache->hash_table, entry, tmp) { + DL_DELETE(cache->global->lru_list, entry); + HASH_DEL(cache->hash_table, entry); + cache->global->cur_size -= 1; + cache->eviction_cb(&entry->key, &entry->value); + utils_mutex_destroy_not_free(&(entry->value.mmap_lock)); + umf_ba_free(cache->global->cache_allocator, entry); + } + HASH_CLEAR(hh, cache->hash_table); + + umf_ba_global_free(cache); +} + +umf_result_t +umfIpcHandleMappedCacheGet(ipc_mapped_handle_cache_handle_t cache, + const ipc_mapped_handle_cache_key_t *key, + uint64_t handle_id, + ipc_mapped_handle_cache_value_t **retEntry) { + ipc_handle_cache_entry_t *entry = NULL; + umf_result_t ret = UMF_RESULT_SUCCESS; + bool evicted = false; + ipc_mapped_handle_cache_value_t evicted_value; + + if (!cache || !key || !retEntry) { + LOG_ERR("Some arguments are NULL, cache=%p, key=%p, retEntry=%p", + (void *)cache, (const void *)key, (void *)retEntry); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + assert(cache->global != NULL); + + utils_mutex_lock(&(cache->global->cache_lock)); + + HASH_FIND(hh, cache->hash_table, key, sizeof(*key), entry); + if (entry && entry->handle_id == handle_id) { // cache hit + // update frequency list + // remove the entry from the current position + DL_DELETE(cache->global->lru_list, entry); + // add the entry to the head of the list + DL_PREPEND(cache->global->lru_list, entry); + } else { //cache miss + // Look for eviction candidate + if (entry == NULL && cache->global->max_size != 0 && + cache->global->cur_size >= cache->global->max_size) { + // If max_size is set and the cache is full, evict the least recently used entry. + entry = cache->global->lru_list->prev; + } + + if (entry) { // we have eviction candidate + // remove the entry from the frequency list + DL_DELETE(cache->global->lru_list, entry); + // remove the entry from the hash table it belongs to + HASH_DEL(*(entry->hash_table), entry); + cache->global->cur_size -= 1; + evicted_value.mapped_base_ptr = entry->value.mapped_base_ptr; + evicted_value.mapped_size = entry->value.mapped_size; + evicted = true; + } else { // allocate the new entry + entry = umf_ba_alloc(cache->global->cache_allocator); + if (!entry) { + ret = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + LOG_ERR("Failed to allocate memory for a new IPC cache entry"); + goto exit; + } + if (NULL == utils_mutex_init(&(entry->value.mmap_lock))) { + LOG_ERR("Failed to initialize mutex for the IPC cache entry"); + umf_ba_global_free(entry); + ret = UMF_RESULT_ERROR_UNKNOWN; + goto exit; + } + } + + entry->key = *key; + entry->ref_count = 0; + entry->handle_id = handle_id; + entry->hash_table = &cache->hash_table; + entry->value.mapped_size = 0; + entry->value.mapped_base_ptr = NULL; + + HASH_ADD(hh, cache->hash_table, key, sizeof(entry->key), entry); + DL_PREPEND(cache->global->lru_list, entry); + cache->global->cur_size += 1; + } + +exit: + if (ret == UMF_RESULT_SUCCESS) { + utils_atomic_increment(&entry->ref_count); + *retEntry = &entry->value; + } + + utils_mutex_unlock(&(cache->global->cache_lock)); + + if (evicted) { + cache->eviction_cb(key, &evicted_value); + } + + return ret; +} diff --git a/src/ipc_cache.h b/src/ipc_cache.h new file mode 100644 index 000000000..59ae28787 --- /dev/null +++ b/src/ipc_cache.h @@ -0,0 +1,52 @@ +/* + * + * Copyright (C) 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_IPC_CACHE_H +#define UMF_IPC_CACHE_H 1 + +#include + +#include "utils_concurrency.h" + +typedef struct ipc_mapped_handle_cache_key_t { + void *remote_base_ptr; + umf_memory_provider_handle_t local_provider; + int remote_pid; +} ipc_mapped_handle_cache_key_t; + +typedef struct ipc_mapped_handle_cache_value_t { + void *mapped_base_ptr; + size_t mapped_size; + utils_mutex_t mmap_lock; +} ipc_mapped_handle_cache_value_t; + +struct ipc_mapped_handle_cache_t; + +typedef struct ipc_mapped_handle_cache_t *ipc_mapped_handle_cache_handle_t; + +umf_result_t umfIpcCacheGlobalInit(void); +void umfIpcCacheGlobalTearDown(void); + +// define pointer to the eviction callback function +typedef void (*ipc_mapped_handle_cache_eviction_cb_t)( + const ipc_mapped_handle_cache_key_t *key, + const ipc_mapped_handle_cache_value_t *value); + +ipc_mapped_handle_cache_handle_t umfIpcHandleMappedCacheCreate( + ipc_mapped_handle_cache_eviction_cb_t eviction_cb); + +void umfIpcHandleMappedCacheDestroy(ipc_mapped_handle_cache_handle_t cache); + +umf_result_t +umfIpcHandleMappedCacheGet(ipc_mapped_handle_cache_handle_t cache, + const ipc_mapped_handle_cache_key_t *key, + uint64_t handle_id, + ipc_mapped_handle_cache_value_t **retEntry); + +#endif /* UMF_IPC_CACHE_H */ diff --git a/src/ipc_internal.h b/src/ipc_internal.h index 0f45b24e2..103214407 100644 --- a/src/ipc_internal.h +++ b/src/ipc_internal.h @@ -21,8 +21,10 @@ extern "C" { // providerIpcData is a Flexible Array Member because its size varies // depending on the provider. typedef struct umf_ipc_data_t { - int pid; // process ID of the process that allocated the memory - size_t baseSize; // size of base (coarse-grain) allocation + uint64_t handle_id; // unique ID of this handle + void *base; // base address of the memory + int pid; // process ID of the process that allocated the memory + size_t baseSize; // size of base (coarse-grain) allocation uint64_t offset; char providerIpcData[]; } umf_ipc_data_t; diff --git a/src/libumf.c b/src/libumf.c index 2fcda07a0..3b69ce396 100644 --- a/src/libumf.c +++ b/src/libumf.c @@ -10,6 +10,7 @@ #include #include "base_alloc_global.h" +#include "ipc_cache.h" #include "memspace_internal.h" #include "provider_tracking.h" #include "utils_log.h" @@ -25,9 +26,18 @@ int umfInit(void) { if (utils_fetch_and_add64(&umfRefCount, 1) == 0) { utils_log_init(); TRACKER = umfMemoryTrackerCreate(); + if (!TRACKER) { + LOG_ERR("Failed to create memory tracker"); + return -1; + } + umf_result_t umf_result = umfIpcCacheGlobalInit(); + if (umf_result != UMF_RESULT_SUCCESS) { + LOG_ERR("Failed to initialize IPC cache"); + return -1; + } } - return (TRACKER) ? 0 : -1; + return 0; } void umfTearDown(void) { @@ -39,6 +49,7 @@ void umfTearDown(void) { umfMemspaceLowestLatencyDestroy(); umfDestroyTopology(); #endif + umfIpcCacheGlobalTearDown(); // make sure TRACKER is not used after being destroyed umf_memory_tracker_handle_t t = TRACKER; TRACKER = NULL; diff --git a/src/provider/provider_tracking.c b/src/provider/provider_tracking.c index d058af271..769ed6a94 100644 --- a/src/provider/provider_tracking.c +++ b/src/provider/provider_tracking.c @@ -10,6 +10,7 @@ #include "provider_tracking.h" #include "base_alloc_global.h" #include "critnib.h" +#include "ipc_cache.h" #include "ipc_internal.h" #include "utils_common.h" #include "utils_concurrency.h" @@ -25,6 +26,8 @@ #include #include +uint64_t IPC_HANDLE_ID = 0; + typedef struct tracker_value_t { umf_memory_pool_handle_t pool; size_t size; @@ -138,6 +141,7 @@ umf_result_t umfMemoryTrackerGetAllocInfo(const void *ptr, // providerIpcData is a Flexible Array Member because its size varies // depending on the provider. typedef struct ipc_cache_value_t { + uint64_t handle_id; uint64_t ipcDataSize; char providerIpcData[]; } ipc_cache_value_t; @@ -147,6 +151,7 @@ typedef struct umf_tracking_memory_provider_t { umf_memory_tracker_handle_t hTracker; umf_memory_pool_handle_t pool; critnib *ipcCache; + ipc_mapped_handle_cache_handle_t hIpcMappedCache; // the upstream provider does not support the free() operation bool upstreamDoesNotFree; @@ -465,6 +470,8 @@ static void trackingFinalize(void *provider) { umf_tracking_memory_provider_t *p = (umf_tracking_memory_provider_t *)provider; + umfIpcHandleMappedCacheDestroy(p->hIpcMappedCache); + critnib_delete(p->ipcCache); // Do not clear the tracker if we are running in the proxy library, @@ -524,6 +531,11 @@ static umf_result_t trackingGetIpcHandleSize(void *provider, size_t *size) { return umfMemoryProviderGetIPCHandleSize(p->hUpstream, size); } +static inline umf_ipc_data_t *getIpcDataFromIpcHandle(void *providerIpcData) { + return (umf_ipc_data_t *)((uint8_t *)providerIpcData - + sizeof(umf_ipc_data_t)); +} + static umf_result_t trackingGetIpcHandle(void *provider, const void *ptr, size_t size, void *providerIpcData) { umf_tracking_memory_provider_t *p = @@ -531,47 +543,39 @@ static umf_result_t trackingGetIpcHandle(void *provider, const void *ptr, umf_result_t ret = UMF_RESULT_SUCCESS; size_t ipcDataSize = 0; int cached = 0; + ipc_cache_value_t *cache_value = NULL; + umf_ipc_data_t *ipcUmfData = getIpcDataFromIpcHandle(providerIpcData); + do { void *value = critnib_get(p->ipcCache, (uintptr_t)ptr); if (value) { //cache hit - ipc_cache_value_t *cache_value = (ipc_cache_value_t *)value; - memcpy(providerIpcData, cache_value->providerIpcData, - cache_value->ipcDataSize); + cache_value = (ipc_cache_value_t *)value; cached = 1; - } else { - ret = umfMemoryProviderGetIPCHandle(p->hUpstream, ptr, size, - providerIpcData); - if (ret != UMF_RESULT_SUCCESS) { - LOG_ERR("upstream provider failed to get IPC handle"); - return ret; - } - + } else { //cache miss ret = umfMemoryProviderGetIPCHandleSize(p->hUpstream, &ipcDataSize); if (ret != UMF_RESULT_SUCCESS) { LOG_ERR("upstream provider failed to get the size of IPC " "handle"); - ret = umfMemoryProviderPutIPCHandle(p->hUpstream, - providerIpcData); - if (ret != UMF_RESULT_SUCCESS) { - LOG_ERR("upstream provider failed to put IPC handle"); - } return ret; } size_t value_size = sizeof(ipc_cache_value_t) + ipcDataSize; - ipc_cache_value_t *cache_value = umf_ba_global_alloc(value_size); + cache_value = umf_ba_global_alloc(value_size); if (!cache_value) { LOG_ERR("failed to allocate cache_value"); - ret = umfMemoryProviderPutIPCHandle(p->hUpstream, - providerIpcData); - if (ret != UMF_RESULT_SUCCESS) { - LOG_ERR("upstream provider failed to put IPC handle"); - } return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; } + ret = umfMemoryProviderGetIPCHandle(p->hUpstream, ptr, size, + cache_value->providerIpcData); + if (ret != UMF_RESULT_SUCCESS) { + LOG_ERR("upstream provider failed to get IPC handle"); + umf_ba_global_free(cache_value); + return ret; + } + + cache_value->handle_id = utils_atomic_increment(&IPC_HANDLE_ID); cache_value->ipcDataSize = ipcDataSize; - memcpy(cache_value->providerIpcData, providerIpcData, ipcDataSize); int insRes = critnib_insert(p->ipcCache, (uintptr_t)ptr, (void *)cache_value, 0 /*update*/); @@ -587,9 +591,9 @@ static umf_result_t trackingGetIpcHandle(void *provider, const void *ptr, // But this case should be rare enough. // 2. critnib failed to allocate memory internally. We need // to cleanup and return corresponding error. + ret = umfMemoryProviderPutIPCHandle( + p->hUpstream, cache_value->providerIpcData); umf_ba_global_free(cache_value); - ret = umfMemoryProviderPutIPCHandle(p->hUpstream, - providerIpcData); if (ret != UMF_RESULT_SUCCESS) { LOG_ERR("upstream provider failed to put IPC handle"); return ret; @@ -602,6 +606,10 @@ static umf_result_t trackingGetIpcHandle(void *provider, const void *ptr, } } while (!cached); + memcpy(providerIpcData, cache_value->providerIpcData, + cache_value->ipcDataSize); + ipcUmfData->handle_id = cache_value->handle_id; + return ret; } @@ -614,17 +622,65 @@ static umf_result_t trackingPutIpcHandle(void *provider, return UMF_RESULT_SUCCESS; } -static size_t getDataSizeFromIpcHandle(const void *providerIpcData) { - // This is hack to get size of memory pointed by IPC handle. - // tracking memory provider gets only provider-specific data - // pointed by providerIpcData, but the size of allocation tracked - // by umf_ipc_data_t. We use this trick to get pointer to - // umf_ipc_data_t data because the providerIpcData is - // the Flexible Array Member of umf_ipc_data_t. - const umf_ipc_data_t *ipcUmfData = - (const umf_ipc_data_t *)((const uint8_t *)providerIpcData - - sizeof(umf_ipc_data_t)); - return ipcUmfData->baseSize; +static void +ipcMappedCacheEvictionCallback(const ipc_mapped_handle_cache_key_t *key, + const ipc_mapped_handle_cache_value_t *value) { + umf_tracking_memory_provider_t *p = + (umf_tracking_memory_provider_t *)key->local_provider; + // umfMemoryTrackerRemove should be called before umfMemoryProviderCloseIPCHandle + // to avoid a race condition. If the order would be different, other thread + // could allocate the memory at address `ptr` before a call to umfMemoryTrackerRemove + // resulting in inconsistent state. + if (value->mapped_base_ptr) { + umf_result_t ret = + umfMemoryTrackerRemove(p->hTracker, value->mapped_base_ptr); + if (ret != UMF_RESULT_SUCCESS) { + // DO NOT return an error here, because the tracking provider + // cannot change behaviour of the upstream provider. + LOG_ERR("failed to remove the region from the tracker, ptr=%p, " + "size=%zu, ret = %d", + value->mapped_base_ptr, value->mapped_size, ret); + } + } + umf_result_t ret = umfMemoryProviderCloseIPCHandle( + p->hUpstream, value->mapped_base_ptr, value->mapped_size); + if (ret != UMF_RESULT_SUCCESS) { + LOG_ERR("provider failed to close IPC handle, ptr=%p, size=%zu", + value->mapped_base_ptr, value->mapped_size); + } +} + +static umf_result_t upstreamOpenIPCHandle(umf_tracking_memory_provider_t *p, + void *providerIpcData, + size_t bufferSize, void **ptr) { + void *mapped_ptr = NULL; + assert(p != NULL); + assert(ptr != NULL); + umf_result_t ret = umfMemoryProviderOpenIPCHandle( + p->hUpstream, providerIpcData, &mapped_ptr); + if (ret != UMF_RESULT_SUCCESS) { + LOG_ERR("upstream provider failed to open IPC handle"); + return ret; + } + assert(mapped_ptr != NULL); + + ret = umfMemoryTrackerAdd(p->hTracker, p->pool, mapped_ptr, bufferSize); + if (ret != UMF_RESULT_SUCCESS) { + LOG_ERR("failed to add IPC region to the tracker, ptr=%p, " + "size=%zu, " + "ret = %d", + mapped_ptr, bufferSize, ret); + if (umfMemoryProviderCloseIPCHandle(p->hUpstream, mapped_ptr, + bufferSize)) { + LOG_ERR("upstream provider failed to close IPC handle, " + "ptr=%p, size=%zu", + mapped_ptr, bufferSize); + } + return ret; + } + + *ptr = mapped_ptr; + return UMF_RESULT_SUCCESS; } static umf_result_t trackingOpenIpcHandle(void *provider, void *providerIpcData, @@ -634,47 +690,67 @@ static umf_result_t trackingOpenIpcHandle(void *provider, void *providerIpcData, umf_result_t ret = UMF_RESULT_SUCCESS; assert(p->hUpstream); + assert(p->hIpcMappedCache); + + umf_ipc_data_t *ipcUmfData = getIpcDataFromIpcHandle(providerIpcData); + + // Compiler may add paddings to the ipc_mapped_handle_cache_key_t structure + // so we need to zero it out to avoid false cache miss. + ipc_mapped_handle_cache_key_t key = {0}; + key.remote_base_ptr = ipcUmfData->base; + key.local_provider = provider; + key.remote_pid = ipcUmfData->pid; - ret = umfMemoryProviderOpenIPCHandle(p->hUpstream, providerIpcData, ptr); + ipc_mapped_handle_cache_value_t *cache_entry = NULL; + ret = umfIpcHandleMappedCacheGet(p->hIpcMappedCache, &key, + ipcUmfData->handle_id, &cache_entry); if (ret != UMF_RESULT_SUCCESS) { - LOG_ERR("upstream provider failed to open IPC handle"); + LOG_ERR("failed to get cache entry"); return ret; } - size_t bufferSize = getDataSizeFromIpcHandle(providerIpcData); - ret = umfMemoryTrackerAdd(p->hTracker, p->pool, *ptr, bufferSize); - if (ret != UMF_RESULT_SUCCESS) { - LOG_ERR("failed to add IPC region to the tracker, ptr=%p, size=%zu, " - "ret = %d", - *ptr, bufferSize, ret); - if (umfMemoryProviderCloseIPCHandle(p->hUpstream, *ptr, bufferSize)) { - LOG_ERR("upstream provider failed to close IPC handle, ptr=%p, " - "size=%zu", - *ptr, bufferSize); + + assert(cache_entry != NULL); + + void *mapped_ptr = NULL; + utils_atomic_load_acquire(&(cache_entry->mapped_base_ptr), &mapped_ptr); + if (mapped_ptr == NULL) { + utils_mutex_lock(&(cache_entry->mmap_lock)); + utils_atomic_load_acquire(&(cache_entry->mapped_base_ptr), &mapped_ptr); + if (mapped_ptr == NULL) { + ret = upstreamOpenIPCHandle(p, providerIpcData, + ipcUmfData->baseSize, &mapped_ptr); + if (ret == UMF_RESULT_SUCCESS) { + // Put to the cache + cache_entry->mapped_size = ipcUmfData->baseSize; + utils_atomic_store_release(&(cache_entry->mapped_base_ptr), + mapped_ptr); + } } + utils_mutex_unlock(&(cache_entry->mmap_lock)); + } + + if (ret == UMF_RESULT_SUCCESS) { + *ptr = mapped_ptr; } + return ret; } static umf_result_t trackingCloseIpcHandle(void *provider, void *ptr, size_t size) { - umf_tracking_memory_provider_t *p = - (umf_tracking_memory_provider_t *)provider; - - // umfMemoryTrackerRemove should be called before umfMemoryProviderCloseIPCHandle - // to avoid a race condition. If the order would be different, other thread - // could allocate the memory at address `ptr` before a call to umfMemoryTrackerRemove - // resulting in inconsistent state. - if (ptr) { - umf_result_t ret = umfMemoryTrackerRemove(p->hTracker, ptr); - if (ret != UMF_RESULT_SUCCESS) { - // DO NOT return an error here, because the tracking provider - // cannot change behaviour of the upstream provider. - LOG_ERR("failed to remove the region from the tracker, ptr=%p, " - "size=%zu, ret = %d", - ptr, size, ret); - } - } - return umfMemoryProviderCloseIPCHandle(p->hUpstream, ptr, size); + (void)provider; + (void)ptr; + (void)size; + // We keep opened IPC handles in the p->hIpcMappedCache. + // IPC handle is closed when it is evicted from the cache + // or when cache is destroyed. + // + // TODO: today the size of the IPC cache is infinite. + // When the threshold for the cache size is implemented + // we need to introduce a reference counting mechanism. + // The trackingOpenIpcHandle will increment the refcount for the corresponding entry. + // The trackingCloseIpcHandle will decrement the refcount for the corresponding cache entry. + return UMF_RESULT_SUCCESS; } umf_memory_provider_ops_t UMF_TRACKING_MEMORY_PROVIDER_OPS = { @@ -716,10 +792,14 @@ umf_result_t umfTrackingMemoryProviderCreate( return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; } + params.hIpcMappedCache = + umfIpcHandleMappedCacheCreate(ipcMappedCacheEvictionCallback); + LOG_DEBUG("upstream=%p, tracker=%p, " - "pool=%p, ipcCache=%p", + "pool=%p, ipcCache=%p, hIpcMappedCache=%p", (void *)params.hUpstream, (void *)params.hTracker, - (void *)params.pool, (void *)params.ipcCache); + (void *)params.pool, (void *)params.ipcCache, + (void *)params.hIpcMappedCache); return umfMemoryProviderCreate(&UMF_TRACKING_MEMORY_PROVIDER_OPS, ¶ms, hTrackingProvider); diff --git a/test/ipcFixtures.hpp b/test/ipcFixtures.hpp index d75e7be7c..9c1f0c8c4 100644 --- a/test/ipcFixtures.hpp +++ b/test/ipcFixtures.hpp @@ -245,8 +245,7 @@ TEST_P(umfIpcTest, BasicFlow) { pool.reset(nullptr); EXPECT_EQ(stat.getCount, 1); EXPECT_EQ(stat.putCount, stat.getCount); - // TODO: enale check below once cache for open IPC handles is implemented - // EXPECT_EQ(stat.openCount, 1); + EXPECT_EQ(stat.openCount, 1); EXPECT_EQ(stat.closeCount, stat.openCount); } @@ -531,8 +530,7 @@ TEST_P(umfIpcTest, ConcurrentOpenCloseHandles) { pool.reset(nullptr); EXPECT_EQ(stat.getCount, stat.allocCount); EXPECT_EQ(stat.putCount, stat.getCount); - // TODO: enale check below once cache for open IPC handles is implemented - // EXPECT_EQ(stat.openCount, stat.allocCount); + EXPECT_EQ(stat.openCount, stat.allocCount); EXPECT_EQ(stat.openCount, stat.closeCount); } From d46530ab305a4a0903b5e8ecf0268c3284a7abc3 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Tue, 5 Nov 2024 14:31:17 +0100 Subject: [PATCH 275/352] Fix umfIpcTest.AllocFreeAllocTest test --- test/ipcFixtures.hpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/test/ipcFixtures.hpp b/test/ipcFixtures.hpp index 9c1f0c8c4..161a84844 100644 --- a/test/ipcFixtures.hpp +++ b/test/ipcFixtures.hpp @@ -357,11 +357,8 @@ TEST_P(umfIpcTest, AllocFreeAllocTest) { get_umf_result_of_free(freeNotSupported, UMF_RESULT_SUCCESS)); pool.reset(nullptr); - // TODO fix it - it does not work in case of IPC cache hit - // EXPECT_EQ(stat.allocCount, stat.getCount); EXPECT_EQ(stat.getCount, stat.putCount); - // TODO fix it - it does not work in case of IPC cache hit - // EXPECT_EQ(stat.openCount, stat.getCount); + EXPECT_EQ(stat.openCount, stat.getCount); EXPECT_EQ(stat.openCount, stat.closeCount); } From 546632c0412f391b3815c7f4d03953141e3f52b5 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Tue, 5 Nov 2024 14:30:32 +0100 Subject: [PATCH 276/352] Enable umfIpcTest for OS provider with jemalloc --- test/CMakeLists.txt | 2 +- test/provider_os_memory.cpp | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index df17d9b2c..d24244ab0 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -242,7 +242,7 @@ if(LINUX AND (NOT UMF_DISABLE_HWLOC)) # OS-specific functions are implemented add_umf_test( NAME provider_os_memory SRCS provider_os_memory.cpp ${BA_SOURCES_FOR_TEST} - LIBS ${UMF_UTILS_FOR_TEST}) + LIBS ${UMF_UTILS_FOR_TEST} ${LIB_JEMALLOC_POOL}) if(UMF_BUILD_LIBUMF_POOL_DISJOINT) target_compile_definitions(umf_test-provider_os_memory PRIVATE UMF_POOL_DISJOINT_ENABLED=1) diff --git a/test/provider_os_memory.cpp b/test/provider_os_memory.cpp index 734ebeec9..03128a6b3 100644 --- a/test/provider_os_memory.cpp +++ b/test/provider_os_memory.cpp @@ -11,6 +11,9 @@ #include #include #include +#ifdef UMF_POOL_JEMALLOC_ENABLED +#include +#endif using umf_test::test; @@ -389,6 +392,10 @@ static std::vector ipcTestParamsList = { {umfDisjointPoolOps(), &disjointParams, umfOsMemoryProviderOps(), &os_params, &hostAccessor, false}, #endif +#ifdef UMF_POOL_JEMALLOC_ENABLED + {umfJemallocPoolOps(), nullptr, umfOsMemoryProviderOps(), &os_params, + &hostAccessor, false}, +#endif }; INSTANTIATE_TEST_SUITE_P(osProviderTest, umfIpcTest, From e1e70f271e02c5406c0d8e6586ef197c74907c1c Mon Sep 17 00:00:00 2001 From: Rafal Rudnicki Date: Fri, 8 Nov 2024 20:11:21 +0100 Subject: [PATCH 277/352] enable CUDA provider on Windows --- .github/workflows/reusable_gpu.yml | 53 ++++++++++++-- cmake/FindCUDA.cmake | 2 +- examples/cmake/FindCUDA.cmake | 2 +- .../cuda_shared_memory/cuda_shared_memory.c | 10 +++ src/provider/provider_cuda.c | 13 +++- test/providers/cuda_helpers.cpp | 70 ++++++++++++++++--- test/providers/cuda_helpers.h | 14 +++- test/providers/provider_cuda.cpp | 17 +++-- 8 files changed, 156 insertions(+), 25 deletions(-) diff --git a/.github/workflows/reusable_gpu.yml b/.github/workflows/reusable_gpu.yml index 1a5d54230..815de5ef9 100644 --- a/.github/workflows/reusable_gpu.yml +++ b/.github/workflows/reusable_gpu.yml @@ -19,7 +19,7 @@ jobs: name: Level-Zero env: VCPKG_PATH: "${{github.workspace}}/../../../../vcpkg/packages/hwloc_x64-windows;${{github.workspace}}/../../../../vcpkg/packages/tbb_x64-windows;${{github.workspace}}/../../../../vcpkg/packages/jemalloc_x64-windows" - COVERAGE_NAME : "exports-coverage-gpu" + COVERAGE_NAME : "exports-coverage-gpu-L0" # run only on upstream; forks will not have the HW if: github.repository == 'oneapi-src/unified-memory-framework' strategy: @@ -130,18 +130,26 @@ jobs: name: CUDA env: COVERAGE_NAME : "exports-coverage-gpu-CUDA" + VCPKG_PATH: "${{github.workspace}}/build/vcpkg/packages/hwloc_x64-windows;${{github.workspace}}/build/vcpkg/packages/tbb_x64-windows;${{github.workspace}}/build/vcpkg/packages/jemalloc_x64-windows;" + CUDA_PATH: "c:/cuda" + # run only on upstream; forks will not have the HW if: github.repository == 'oneapi-src/unified-memory-framework' strategy: matrix: shared_library: ['ON', 'OFF'] build_type: ['Debug', 'Release'] - # TODO add windows - os: ['Ubuntu'] + os: ['Ubuntu', 'Windows'] include: + - os: 'Windows' + compiler: {c: cl, cxx: cl} + number_of_processors: '$Env:NUMBER_OF_PROCESSORS' - os: 'Ubuntu' compiler: {c: gcc, cxx: g++} number_of_processors: '$(nproc)' + exclude: + - os: 'Windows' + build_type: 'Debug' runs-on: ["DSS-CUDA", "DSS-${{matrix.os}}"] steps: @@ -154,10 +162,47 @@ jobs: if: matrix.os == 'Ubuntu' run: .github/scripts/get_system_info.sh + - name: Initialize vcpkg + if: matrix.os == 'Windows' + uses: lukka/run-vcpkg@5e0cab206a5ea620130caf672fce3e4a6b5666a1 # v11.5 + with: + vcpkgGitCommitId: 3dd44b931481d7a8e9ba412621fa810232b66289 + vcpkgDirectory: ${{env.BUILD_DIR}}/vcpkg + vcpkgJsonGlob: '**/vcpkg.json' + + - name: Install dependencies (windows-latest) + if: matrix.os == 'Windows' + run: vcpkg install + shell: pwsh # Specifies PowerShell as the shell for running the script. + + - name: Configure build for Win + if: matrix.os == 'Windows' + run: > + cmake + -DCMAKE_PREFIX_PATH="${{env.VCPKG_PATH}}${{env.CUDA_PATH}}" + -B ${{env.BUILD_DIR}} + -DCMAKE_INSTALL_PREFIX="${{env.INSTL_DIR}}" + -DCMAKE_BUILD_TYPE=${{matrix.build_type}} + -DCMAKE_C_COMPILER=${{matrix.compiler.c}} + -DCMAKE_CXX_COMPILER=${{matrix.compiler.cxx}} + -DUMF_BUILD_SHARED_LIBRARY=${{matrix.shared_library}} + -DUMF_BUILD_BENCHMARKS=ON + -DUMF_BUILD_TESTS=ON + -DUMF_BUILD_GPU_TESTS=ON + -DUMF_BUILD_GPU_EXAMPLES=ON + -DUMF_FORMAT_CODE_STYLE=OFF + -DUMF_DEVELOPER_MODE=ON + -DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON + -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON + -DUMF_BUILD_LEVEL_ZERO_PROVIDER=OFF + -DUMF_BUILD_CUDA_PROVIDER=ON + -DUMF_TESTS_FAIL_ON_SKIP=ON + - name: Configure build for Ubuntu if: matrix.os == 'Ubuntu' run: > - cmake -B ${{env.BUILD_DIR}} + cmake + -B ${{env.BUILD_DIR}} -DCMAKE_INSTALL_PREFIX="${{env.INSTL_DIR}}" -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DCMAKE_C_COMPILER=${{matrix.compiler.c}} diff --git a/cmake/FindCUDA.cmake b/cmake/FindCUDA.cmake index 92ef5c830..5e4e2eead 100644 --- a/cmake/FindCUDA.cmake +++ b/cmake/FindCUDA.cmake @@ -11,7 +11,7 @@ get_filename_component(CUDA_LIB_DIR ${CUDA_LIBRARIES} DIRECTORY) set(CUDA_LIBRARY_DIRS ${CUDA_LIB_DIR}) if(WINDOWS) - find_file(CUDA_DLL NAMES "bin/cuda.dll" "cuda.dll") + find_file(CUDA_DLL NAMES "nvcuda.dll") get_filename_component(CUDA_DLL_DIR ${CUDA_DLL} DIRECTORY) set(CUDA_DLL_DIRS ${CUDA_DLL_DIR}) endif() diff --git a/examples/cmake/FindCUDA.cmake b/examples/cmake/FindCUDA.cmake index 92ef5c830..5e4e2eead 100644 --- a/examples/cmake/FindCUDA.cmake +++ b/examples/cmake/FindCUDA.cmake @@ -11,7 +11,7 @@ get_filename_component(CUDA_LIB_DIR ${CUDA_LIBRARIES} DIRECTORY) set(CUDA_LIBRARY_DIRS ${CUDA_LIB_DIR}) if(WINDOWS) - find_file(CUDA_DLL NAMES "bin/cuda.dll" "cuda.dll") + find_file(CUDA_DLL NAMES "nvcuda.dll") get_filename_component(CUDA_DLL_DIR ${CUDA_DLL} DIRECTORY) set(CUDA_DLL_DIRS ${CUDA_DLL_DIR}) endif() diff --git a/examples/cuda_shared_memory/cuda_shared_memory.c b/examples/cuda_shared_memory/cuda_shared_memory.c index 4b3093522..55a7dd12f 100644 --- a/examples/cuda_shared_memory/cuda_shared_memory.c +++ b/examples/cuda_shared_memory/cuda_shared_memory.c @@ -14,8 +14,18 @@ #include #include +// disable warning 4201: nonstandard extension used: nameless struct/union +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4201) +#endif // _MSC_VER + #include +#if defined(_MSC_VER) +#pragma warning(pop) +#endif // _MSC_VER + int main(void) { // A result object for storing UMF API result status umf_result_t res; diff --git a/src/provider/provider_cuda.c b/src/provider/provider_cuda.c index 715e6e790..a1f9df034 100644 --- a/src/provider/provider_cuda.c +++ b/src/provider/provider_cuda.c @@ -21,8 +21,18 @@ umf_memory_provider_ops_t *umfCUDAMemoryProviderOps(void) { #else // !defined(UMF_NO_CUDA_PROVIDER) +// disable warning 4201: nonstandard extension used: nameless struct/union +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4201) +#endif // _MSC_VER + #include "cuda.h" +#if defined(_MSC_VER) +#pragma warning(pop) +#endif // _MSC_VER + #include "base_alloc_global.h" #include "utils_assert.h" #include "utils_common.h" @@ -100,7 +110,7 @@ static umf_result_t cu2umf_result(CUresult result) { static void init_cu_global_state(void) { #ifdef _WIN32 - const char *lib_name = "cudart.dll"; + const char *lib_name = "nvcuda.dll"; #else const char *lib_name = "libcuda.so"; #endif @@ -159,6 +169,7 @@ static umf_result_t cu_memory_provider_initialize(void *params, if (cu_params->memory_type == UMF_MEMORY_TYPE_UNKNOWN || cu_params->memory_type > UMF_MEMORY_TYPE_SHARED) { + LOG_ERR("Invalid memory type value"); return UMF_RESULT_ERROR_INVALID_ARGUMENT; } diff --git a/test/providers/cuda_helpers.cpp b/test/providers/cuda_helpers.cpp index 734f287e0..37e71bd6a 100644 --- a/test/providers/cuda_helpers.cpp +++ b/test/providers/cuda_helpers.cpp @@ -18,6 +18,7 @@ struct libcu_ops { CUresult (*cuCtxCreate)(CUcontext *pctx, unsigned int flags, CUdevice dev); CUresult (*cuCtxDestroy)(CUcontext ctx); CUresult (*cuCtxGetCurrent)(CUcontext *pctx); + CUresult (*cuCtxSetCurrent)(CUcontext ctx); CUresult (*cuDeviceGet)(CUdevice *device, int ordinal); CUresult (*cuMemAlloc)(CUdeviceptr *dptr, size_t size); CUresult (*cuMemFree)(CUdeviceptr dptr); @@ -34,6 +35,7 @@ struct libcu_ops { CUpointer_attribute *attributes, void **data, CUdeviceptr ptr); CUresult (*cuStreamSynchronize)(CUstream hStream); + CUresult (*cuCtxSynchronize)(void); } libcu_ops; #if USE_DLOPEN @@ -48,7 +50,7 @@ struct DlHandleCloser { std::unique_ptr cuDlHandle = nullptr; int InitCUDAOps() { #ifdef _WIN32 - const char *lib_name = "cudart.dll"; + const char *lib_name = "nvcuda.dll"; #else const char *lib_name = "libcuda.so"; #endif @@ -84,6 +86,12 @@ int InitCUDAOps() { fprintf(stderr, "cuCtxGetCurrent symbol not found in %s\n", lib_name); return -1; } + *(void **)&libcu_ops.cuCtxSetCurrent = + utils_get_symbol_addr(cuDlHandle.get(), "cuCtxSetCurrent", lib_name); + if (libcu_ops.cuCtxSetCurrent == nullptr) { + fprintf(stderr, "cuCtxSetCurrent symbol not found in %s\n", lib_name); + return -1; + } *(void **)&libcu_ops.cuDeviceGet = utils_get_symbol_addr(cuDlHandle.get(), "cuDeviceGet", lib_name); if (libcu_ops.cuDeviceGet == nullptr) { @@ -153,6 +161,12 @@ int InitCUDAOps() { lib_name); return -1; } + *(void **)&libcu_ops.cuCtxSynchronize = + utils_get_symbol_addr(cuDlHandle.get(), "cuCtxSynchronize", lib_name); + if (libcu_ops.cuCtxSynchronize == nullptr) { + fprintf(stderr, "cuCtxSynchronize symbol not found in %s\n", lib_name); + return -1; + } return 0; } @@ -165,6 +179,7 @@ int InitCUDAOps() { libcu_ops.cuCtxCreate = cuCtxCreate; libcu_ops.cuCtxDestroy = cuCtxDestroy; libcu_ops.cuCtxGetCurrent = cuCtxGetCurrent; + libcu_ops.cuCtxSetCurrent = cuCtxSetCurrent; libcu_ops.cuDeviceGet = cuDeviceGet; libcu_ops.cuMemAlloc = cuMemAlloc; libcu_ops.cuMemAllocHost = cuMemAllocHost; @@ -176,11 +191,31 @@ int InitCUDAOps() { libcu_ops.cuPointerGetAttribute = cuPointerGetAttribute; libcu_ops.cuPointerGetAttributes = cuPointerGetAttributes; libcu_ops.cuStreamSynchronize = cuStreamSynchronize; + libcu_ops.cuCtxSynchronize = cuCtxSynchronize; return 0; } #endif // USE_DLOPEN +static CUresult set_context(CUcontext required_ctx, CUcontext *restore_ctx) { + CUcontext current_ctx = NULL; + CUresult cu_result = libcu_ops.cuCtxGetCurrent(¤t_ctx); + if (cu_result != CUDA_SUCCESS) { + fprintf(stderr, "cuCtxGetCurrent() failed.\n"); + return cu_result; + } + + *restore_ctx = current_ctx; + if (current_ctx != required_ctx) { + cu_result = libcu_ops.cuCtxSetCurrent(required_ctx); + if (cu_result != CUDA_SUCCESS) { + fprintf(stderr, "cuCtxSetCurrent() failed.\n"); + } + } + + return cu_result; +} + static int init_cuda_lib(void) { CUresult result = libcu_ops.cuInit(0); if (result != CUDA_SUCCESS) { @@ -191,8 +226,6 @@ static int init_cuda_lib(void) { int cuda_fill(CUcontext context, CUdevice device, void *ptr, size_t size, const void *pattern, size_t pattern_size) { - - (void)context; (void)device; (void)pattern_size; @@ -202,23 +235,40 @@ int cuda_fill(CUcontext context, CUdevice device, void *ptr, size_t size, return -1; } + // set required context + CUcontext curr_context = nullptr; + set_context(context, &curr_context); + int ret = 0; CUresult res = libcu_ops.cuMemsetD32((CUdeviceptr)ptr, *(unsigned int *)pattern, size / sizeof(unsigned int)); if (res != CUDA_SUCCESS) { - fprintf(stderr, "cuMemsetD32() failed!\n"); + fprintf(stderr, "cuMemsetD32(%llu, %u, %zu) failed!\n", + (CUdeviceptr)ptr, *(unsigned int *)pattern, + size / pattern_size); + return -1; + } + + res = libcu_ops.cuCtxSynchronize(); + if (res != CUDA_SUCCESS) { + fprintf(stderr, "cuCtxSynchronize() failed!\n"); return -1; } + // restore context + set_context(curr_context, &curr_context); return ret; } -int cuda_copy(CUcontext context, CUdevice device, void *dst_ptr, void *src_ptr, - size_t size) { - (void)context; +int cuda_copy(CUcontext context, CUdevice device, void *dst_ptr, + const void *src_ptr, size_t size) { (void)device; + // set required context + CUcontext curr_context = nullptr; + set_context(context, &curr_context); + int ret = 0; CUresult res = libcu_ops.cuMemcpy((CUdeviceptr)dst_ptr, (CUdeviceptr)src_ptr, size); @@ -227,12 +277,14 @@ int cuda_copy(CUcontext context, CUdevice device, void *dst_ptr, void *src_ptr, return -1; } - res = libcu_ops.cuStreamSynchronize(0); + res = libcu_ops.cuCtxSynchronize(); if (res != CUDA_SUCCESS) { - fprintf(stderr, "cuStreamSynchronize() failed!\n"); + fprintf(stderr, "cuCtxSynchronize() failed!\n"); return -1; } + // restore context + set_context(curr_context, &curr_context); return ret; } diff --git a/test/providers/cuda_helpers.h b/test/providers/cuda_helpers.h index 5e42153bb..fc349fc14 100644 --- a/test/providers/cuda_helpers.h +++ b/test/providers/cuda_helpers.h @@ -10,8 +10,18 @@ #include +// disable warning 4201: nonstandard extension used: nameless struct/union +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4201) +#endif // _MSC_VER + #include "cuda.h" +#if defined(_MSC_VER) +#pragma warning(pop) +#endif // _MSC_VER + #ifdef __cplusplus extern "C" { #endif @@ -21,8 +31,8 @@ int destroy_context(CUcontext context); int cuda_fill(CUcontext context, CUdevice device, void *ptr, size_t size, const void *pattern, size_t pattern_size); -int cuda_copy(CUcontext context, CUdevice device, void *dst_ptr, void *src_ptr, - size_t size); +int cuda_copy(CUcontext context, CUdevice device, void *dst_ptr, + const void *src_ptr, size_t size); umf_usm_memory_type_t get_mem_type(CUcontext context, void *ptr); diff --git a/test/providers/provider_cuda.cpp b/test/providers/provider_cuda.cpp index c0173bb82..58e3beb9e 100644 --- a/test/providers/provider_cuda.cpp +++ b/test/providers/provider_cuda.cpp @@ -114,7 +114,7 @@ TEST_P(umfCUDAProviderTest, basic) { // check if the pattern was successfully applied uint32_t *hostMemory = (uint32_t *)calloc(1, size); memAccessor->copy(hostMemory, ptr, size); - for (size_t i = 0; i < size / sizeof(int); i++) { + for (size_t i = 0; i < size / sizeof(uint32_t); i++) { ASSERT_EQ(hostMemory[i], pattern); } free(hostMemory); @@ -171,15 +171,18 @@ TEST_P(umfCUDAProviderTest, allocInvalidSize) { ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(provider, nullptr); - // try to alloc (int)-1 void *ptr = nullptr; - umf_result = umfMemoryProviderAlloc(provider, -1, 0, &ptr); - ASSERT_EQ(umf_result, UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY); - // in case of size == 0 we should got INVALID_ARGUMENT error - // NOTE: this is invalid only for the DEVICE or SHARED allocations - if (params.memory_type != UMF_MEMORY_TYPE_HOST) { + // NOTE: some scenarios are invalid only for the DEVICE allocations + if (params.memory_type == UMF_MEMORY_TYPE_DEVICE) { + // try to alloc SIZE_MAX + umf_result = umfMemoryProviderAlloc(provider, SIZE_MAX, 0, &ptr); + ASSERT_EQ(ptr, nullptr); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY); + + // in case of size == 0 we should got INVALID_ARGUMENT error umf_result = umfMemoryProviderAlloc(provider, 0, 0, &ptr); + ASSERT_EQ(ptr, nullptr); ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); } From d776beaa4777e4a412739fd3502a8eadb8293d60 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Tue, 12 Nov 2024 23:10:32 +0100 Subject: [PATCH 278/352] Suppress drd and helgrind false-positive in trackingOpenIpcHandle function --- test/supp/drd-umf_test-provider_devdax_memory_ipc.supp | 8 ++++++++ test/supp/drd-umf_test-provider_file_memory_ipc.supp | 9 +++++++++ test/supp/drd-umf_test-provider_os_memory.supp | 8 ++++++++ .../helgrind-umf_test-provider_devdax_memory_ipc.supp | 8 ++++++++ .../supp/helgrind-umf_test-provider_file_memory_ipc.supp | 8 ++++++++ test/supp/helgrind-umf_test-provider_os_memory.supp | 8 ++++++++ 6 files changed, 49 insertions(+) create mode 100644 test/supp/drd-umf_test-provider_devdax_memory_ipc.supp create mode 100644 test/supp/drd-umf_test-provider_os_memory.supp create mode 100644 test/supp/helgrind-umf_test-provider_devdax_memory_ipc.supp create mode 100644 test/supp/helgrind-umf_test-provider_file_memory_ipc.supp create mode 100644 test/supp/helgrind-umf_test-provider_os_memory.supp diff --git a/test/supp/drd-umf_test-provider_devdax_memory_ipc.supp b/test/supp/drd-umf_test-provider_devdax_memory_ipc.supp new file mode 100644 index 000000000..cd44bb49a --- /dev/null +++ b/test/supp/drd-umf_test-provider_devdax_memory_ipc.supp @@ -0,0 +1,8 @@ +{ + [false-positive] Double check locking pattern in trackingOpenIpcHandle + drd:ConflictingAccess + fun:trackingOpenIpcHandle + fun:umfMemoryProviderOpenIPCHandle + fun:umfOpenIPCHandle + ... +} diff --git a/test/supp/drd-umf_test-provider_file_memory_ipc.supp b/test/supp/drd-umf_test-provider_file_memory_ipc.supp index 76844585d..7fce24116 100644 --- a/test/supp/drd-umf_test-provider_file_memory_ipc.supp +++ b/test/supp/drd-umf_test-provider_file_memory_ipc.supp @@ -5,3 +5,12 @@ fun:pthread_cond_destroy@* ... } + +{ + [false-positive] Double check locking pattern in trackingOpenIpcHandle + drd:ConflictingAccess + fun:trackingOpenIpcHandle + fun:umfMemoryProviderOpenIPCHandle + fun:umfOpenIPCHandle + ... +} diff --git a/test/supp/drd-umf_test-provider_os_memory.supp b/test/supp/drd-umf_test-provider_os_memory.supp new file mode 100644 index 000000000..cd44bb49a --- /dev/null +++ b/test/supp/drd-umf_test-provider_os_memory.supp @@ -0,0 +1,8 @@ +{ + [false-positive] Double check locking pattern in trackingOpenIpcHandle + drd:ConflictingAccess + fun:trackingOpenIpcHandle + fun:umfMemoryProviderOpenIPCHandle + fun:umfOpenIPCHandle + ... +} diff --git a/test/supp/helgrind-umf_test-provider_devdax_memory_ipc.supp b/test/supp/helgrind-umf_test-provider_devdax_memory_ipc.supp new file mode 100644 index 000000000..4fcd2786c --- /dev/null +++ b/test/supp/helgrind-umf_test-provider_devdax_memory_ipc.supp @@ -0,0 +1,8 @@ +{ + [false-positive] Double check locking pattern in trackingOpenIpcHandle + Helgrind:Race + fun:trackingOpenIpcHandle + fun:umfMemoryProviderOpenIPCHandle + fun:umfOpenIPCHandle + ... +} diff --git a/test/supp/helgrind-umf_test-provider_file_memory_ipc.supp b/test/supp/helgrind-umf_test-provider_file_memory_ipc.supp new file mode 100644 index 000000000..4fcd2786c --- /dev/null +++ b/test/supp/helgrind-umf_test-provider_file_memory_ipc.supp @@ -0,0 +1,8 @@ +{ + [false-positive] Double check locking pattern in trackingOpenIpcHandle + Helgrind:Race + fun:trackingOpenIpcHandle + fun:umfMemoryProviderOpenIPCHandle + fun:umfOpenIPCHandle + ... +} diff --git a/test/supp/helgrind-umf_test-provider_os_memory.supp b/test/supp/helgrind-umf_test-provider_os_memory.supp new file mode 100644 index 000000000..4fcd2786c --- /dev/null +++ b/test/supp/helgrind-umf_test-provider_os_memory.supp @@ -0,0 +1,8 @@ +{ + [false-positive] Double check locking pattern in trackingOpenIpcHandle + Helgrind:Race + fun:trackingOpenIpcHandle + fun:umfMemoryProviderOpenIPCHandle + fun:umfOpenIPCHandle + ... +} From 2a7a22943584842bfc5e4f54e208e19fb469fa0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Wed, 23 Oct 2024 16:03:45 +0200 Subject: [PATCH 279/352] [CI] Move MultiNuma workflow right after FastBuild It's running rather quickly and on self hosted runners. Enable also more builds in this workflow. --- .github/workflows/pr_push.yml | 6 +++--- .github/workflows/reusable_multi_numa.yml | 14 ++++++++------ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/.github/workflows/pr_push.yml b/.github/workflows/pr_push.yml index 8b78ce3d0..4c590e575 100644 --- a/.github/workflows/pr_push.yml +++ b/.github/workflows/pr_push.yml @@ -31,6 +31,9 @@ jobs: DevDax: needs: [FastBuild] uses: ./.github/workflows/reusable_dax.yml + MultiNuma: + needs: [FastBuild] + uses: ./.github/workflows/reusable_multi_numa.yml Sanitizers: needs: [FastBuild] uses: ./.github/workflows/reusable_sanitizers.yml @@ -49,9 +52,6 @@ jobs: Valgrind: needs: [Build] uses: ./.github/workflows/reusable_valgrind.yml - MultiNuma: - needs: [Build] - uses: ./.github/workflows/reusable_multi_numa.yml Coverage: # total coverage (on upstream only) if: github.repository == 'oneapi-src/unified-memory-framework' diff --git a/.github/workflows/reusable_multi_numa.yml b/.github/workflows/reusable_multi_numa.yml index df00af181..c012f3e19 100644 --- a/.github/workflows/reusable_multi_numa.yml +++ b/.github/workflows/reusable_multi_numa.yml @@ -13,13 +13,15 @@ env: jobs: multi_numa: - name: ${{matrix.os}} + name: "${{matrix.os}}, ${{matrix.build_type}}, shared=${{matrix.shared_library}}" # run only on upstream; forks will not have the HW if: github.repository == 'oneapi-src/unified-memory-framework' strategy: matrix: os: [ubuntu-22.04, rhel-9.1] + build_type: [Debug, Release] + shared_library: ['ON', 'OFF'] runs-on: ["DSS-MULTI-NUMA", "DSS-${{matrix.os}}"] steps: @@ -35,17 +37,17 @@ jobs: run: > cmake -B ${{github.workspace}}/build - -DCMAKE_BUILD_TYPE=Debug + -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ - -DUMF_BUILD_SHARED_LIBRARY=OFF + -DUMF_BUILD_SHARED_LIBRARY=${{matrix.shared_library}} -DUMF_BUILD_BENCHMARKS=OFF -DUMF_BUILD_TESTS=ON -DUMF_DEVELOPER_MODE=ON -DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON -DUMF_TESTS_FAIL_ON_SKIP=ON - ${{ matrix.os == 'ubuntu-22.04' && '-DUMF_USE_COVERAGE=ON' || '' }} + ${{ matrix.build_type == 'Debug' && matrix.os == 'ubuntu-22.04' && '-DUMF_USE_COVERAGE=ON' || '' }} - name: Build UMF run: cmake --build ${{github.workspace}}/build -j $(nproc) @@ -70,7 +72,7 @@ jobs: if: matrix.os == 'ubuntu-22.04' working-directory: ${{env.BUILD_DIR}} run: | - export COVERAGE_FILE_NAME=${{env.COVERAGE_NAME}}-os-${{matrix.os}} + export COVERAGE_FILE_NAME=${{env.COVERAGE_NAME}}-${{matrix.os}}-shared-${{matrix.shared_library}} echo "COVERAGE_FILE_NAME: $COVERAGE_FILE_NAME" ../scripts/coverage/coverage_capture.sh $COVERAGE_FILE_NAME mkdir -p ${{env.COVERAGE_DIR}} @@ -79,5 +81,5 @@ jobs: - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 if: matrix.os == 'ubuntu-22.04' with: - name: ${{env.COVERAGE_NAME}}-os-${{matrix.os}} + name: ${{env.COVERAGE_NAME}}-${{matrix.os}}-${{matrix.build_type}}-shared-${{matrix.shared_library}} path: ${{env.COVERAGE_DIR}} From 9d23a57a799458d22ccc6ee31ba937ee6fc3f6c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Wed, 23 Oct 2024 22:05:13 +0200 Subject: [PATCH 280/352] [CI] Clean GPU builds up Use it actually as reusable workflow - enable limited scope in PR/push and full scope in Nightly workflow. Now, each provider have its own, separate job in PR/push. --- .github/workflows/nightly.yml | 9 ++ .github/workflows/pr_push.yml | 17 ++- .github/workflows/reusable_gpu.yml | 223 +++++++---------------------- 3 files changed, 73 insertions(+), 176 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index bfb544ada..b6d6ee78f 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -175,3 +175,12 @@ jobs: call "C:\Program Files (x86)\Intel\oneAPI\setvars.bat" call "C:\Program Files (x86)\Intel\oneAPI\setvars-vcvarsall.bat" ctest -C ${{matrix.build_type}} --output-on-failure --test-dir test + + L0: + uses: ./.github/workflows/reusable_gpu.yml + with: + name: "LEVEL_ZERO" + CUDA: + uses: ./.github/workflows/reusable_gpu.yml + with: + name: "CUDA" \ No newline at end of file diff --git a/.github/workflows/pr_push.yml b/.github/workflows/pr_push.yml index 4c590e575..c1bc6053e 100644 --- a/.github/workflows/pr_push.yml +++ b/.github/workflows/pr_push.yml @@ -34,6 +34,18 @@ jobs: MultiNuma: needs: [FastBuild] uses: ./.github/workflows/reusable_multi_numa.yml + L0: + needs: [Build] + uses: ./.github/workflows/reusable_gpu.yml + with: + name: "LEVEL_ZERO" + shared_lib: "['ON']" + CUDA: + needs: [Build] + uses: ./.github/workflows/reusable_gpu.yml + with: + name: "CUDA" + shared_lib: "['ON']" Sanitizers: needs: [FastBuild] uses: ./.github/workflows/reusable_sanitizers.yml @@ -46,16 +58,13 @@ jobs: ProxyLib: needs: [Build] uses: ./.github/workflows/reusable_proxy_lib.yml - GPU: - needs: [Build] - uses: ./.github/workflows/reusable_gpu.yml Valgrind: needs: [Build] uses: ./.github/workflows/reusable_valgrind.yml Coverage: # total coverage (on upstream only) if: github.repository == 'oneapi-src/unified-memory-framework' - needs: [Build, DevDax, GPU, MultiNuma, Qemu, ProxyLib] + needs: [Build, DevDax, L0, CUDA, MultiNuma, Qemu, ProxyLib] uses: ./.github/workflows/reusable_coverage.yml secrets: inherit with: diff --git a/.github/workflows/reusable_gpu.yml b/.github/workflows/reusable_gpu.yml index 815de5ef9..a09f43e6d 100644 --- a/.github/workflows/reusable_gpu.yml +++ b/.github/workflows/reusable_gpu.yml @@ -1,10 +1,26 @@ -# This workflow builds and tests providers using GPU memory. It requires -# appropriately labelled self-hosted runners installed on systems with the -# correct GPU and drivers - +# This workflow builds and tests providers using GPU memory. It requires properly +# labelled self-hosted runners on systems with the correct GPU and drivers. name: GPU -on: [workflow_call] +on: + workflow_call: + inputs: + name: + description: Provider name + type: string + required: true + os: + description: A list of OSes + type: string + default: "['Ubuntu', 'Windows']" + build_type: + description: A list of build types + type: string + default: "['Debug', 'Release']" + shared_lib: + description: A list of options for building shared library + type: string + default: "['ON', 'OFF']" permissions: contents: read @@ -15,18 +31,20 @@ env: COVERAGE_DIR : "${{github.workspace}}/coverage" jobs: - gpu-Level-Zero: - name: Level-Zero + gpu: + name: "${{matrix.os}}, ${{matrix.build_type}}, shared=${{matrix.shared_library}}" env: - VCPKG_PATH: "${{github.workspace}}/../../../../vcpkg/packages/hwloc_x64-windows;${{github.workspace}}/../../../../vcpkg/packages/tbb_x64-windows;${{github.workspace}}/../../../../vcpkg/packages/jemalloc_x64-windows" - COVERAGE_NAME : "exports-coverage-gpu-L0" + VCPKG_PATH: "${{github.workspace}}/build/vcpkg/packages/hwloc_x64-windows;${{github.workspace}}/build/vcpkg/packages/tbb_x64-windows;${{github.workspace}}/build/vcpkg/packages/jemalloc_x64-windows;" + CUDA_PATH: "C:/cuda" + COVERAGE_NAME : "exports-coverage-${{inputs.name}}" # run only on upstream; forks will not have the HW if: github.repository == 'oneapi-src/unified-memory-framework' strategy: + fail-fast: false matrix: - shared_library: ['ON', 'OFF'] - os: ['Ubuntu', 'Windows'] - build_type: ['Debug', 'Release'] + shared_library: ${{ fromJSON(inputs.shared_lib)}} + os: ${{ fromJSON(inputs.os)}} + build_type: ${{ fromJSON(inputs.build_type)}} include: - os: 'Ubuntu' compiler: {c: gcc, cxx: g++} @@ -34,11 +52,8 @@ jobs: - os: 'Windows' compiler: {c: cl, cxx: cl} number_of_processors: '$Env:NUMBER_OF_PROCESSORS' - exclude: - - os: 'Windows' - build_type: 'Debug' - runs-on: ["DSS-LEVEL_ZERO", "DSS-${{matrix.os}}"] + runs-on: ["DSS-${{inputs.name}}", "DSS-${{matrix.os}}"] steps: - name: Checkout uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 @@ -49,33 +64,23 @@ jobs: if: matrix.os == 'Ubuntu' run: .github/scripts/get_system_info.sh - - name: Configure build for Win + - name: "[Win] Initialize vcpkg" if: matrix.os == 'Windows' + uses: lukka/run-vcpkg@5e0cab206a5ea620130caf672fce3e4a6b5666a1 # v11.5 + with: + vcpkgGitCommitId: 3dd44b931481d7a8e9ba412621fa810232b66289 + vcpkgDirectory: ${{env.BUILD_DIR}}/vcpkg + vcpkgJsonGlob: '**/vcpkg.json' + + - name: "[Win] Install dependencies" + if: matrix.os == 'Windows' + run: vcpkg install + + # note: disable all providers except the one being tested + - name: Configure build run: > cmake - -DCMAKE_PREFIX_PATH="${{env.VCPKG_PATH}}" - -B ${{env.BUILD_DIR}} - -DCMAKE_INSTALL_PREFIX="${{env.INSTL_DIR}}" - -DCMAKE_BUILD_TYPE=${{matrix.build_type}} - -DCMAKE_C_COMPILER=${{matrix.compiler.c}} - -DCMAKE_CXX_COMPILER=${{matrix.compiler.cxx}} - -DUMF_BUILD_SHARED_LIBRARY=${{matrix.shared_library}} - -DUMF_BUILD_BENCHMARKS=ON - -DUMF_BUILD_TESTS=ON - -DUMF_BUILD_GPU_TESTS=ON - -DUMF_BUILD_GPU_EXAMPLES=ON - -DUMF_FORMAT_CODE_STYLE=OFF - -DUMF_DEVELOPER_MODE=ON - -DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON - -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON - -DUMF_BUILD_LEVEL_ZERO_PROVIDER=ON - -DUMF_BUILD_CUDA_PROVIDER=OFF - -DUMF_TESTS_FAIL_ON_SKIP=ON - - - name: Configure build for Ubuntu - if: matrix.os == 'Ubuntu' - run: > - cmake + -DCMAKE_PREFIX_PATH="${{env.VCPKG_PATH}}${{env.CUDA_PATH}}" -B ${{env.BUILD_DIR}} -DCMAKE_INSTALL_PREFIX="${{env.INSTL_DIR}}" -DCMAKE_BUILD_TYPE=${{matrix.build_type}} @@ -86,14 +91,14 @@ jobs: -DUMF_BUILD_TESTS=ON -DUMF_BUILD_GPU_TESTS=ON -DUMF_BUILD_GPU_EXAMPLES=ON - -DUMF_FORMAT_CODE_STYLE=OFF -DUMF_DEVELOPER_MODE=ON -DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON - -DUMF_BUILD_LEVEL_ZERO_PROVIDER=ON -DUMF_BUILD_CUDA_PROVIDER=OFF + -DUMF_BUILD_LEVEL_ZERO_PROVIDER=OFF + -DUMF_BUILD_${{inputs.name}}_PROVIDER=ON -DUMF_TESTS_FAIL_ON_SKIP=ON - ${{ matrix.build_type == 'Debug' && '-DUMF_USE_COVERAGE=ON' || '' }} + ${{ matrix.os == 'Ubuntu' && matrix.build_type == 'Debug' && '-DUMF_USE_COVERAGE=ON' || '' }} - name: Build UMF run: cmake --build ${{env.BUILD_DIR}} --config ${{matrix.build_type}} -j ${{matrix.number_of_processors}} @@ -111,7 +116,7 @@ jobs: run: ctest --output-on-failure --test-dir benchmark -C ${{matrix.build_type}} --exclude-regex umf-bench-multithreaded - name: Check coverage - if: ${{ matrix.build_type == 'Debug' && matrix.os == 'Ubuntu' }} + if: ${{ matrix.build_type == 'Debug' && matrix.os == 'Ubuntu' }} working-directory: ${{env.BUILD_DIR}} run: | export COVERAGE_FILE_NAME=${{env.COVERAGE_NAME}}-shared-${{matrix.shared_library}} @@ -121,133 +126,7 @@ jobs: mv ./$COVERAGE_FILE_NAME ${{env.COVERAGE_DIR}} - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 - if: ${{ matrix.build_type == 'Debug' && matrix.os == 'Ubuntu' }} + if: ${{ matrix.build_type == 'Debug' && matrix.os == 'Ubuntu' }} with: - name: ${{env.COVERAGE_NAME}}-shared-${{matrix.shared_library}} + name: ${{env.COVERAGE_NAME}}-${{matrix.os}}-${{matrix.build_type}}-shared-${{matrix.shared_library}} path: ${{env.COVERAGE_DIR}} - - gpu-CUDA: - name: CUDA - env: - COVERAGE_NAME : "exports-coverage-gpu-CUDA" - VCPKG_PATH: "${{github.workspace}}/build/vcpkg/packages/hwloc_x64-windows;${{github.workspace}}/build/vcpkg/packages/tbb_x64-windows;${{github.workspace}}/build/vcpkg/packages/jemalloc_x64-windows;" - CUDA_PATH: "c:/cuda" - - # run only on upstream; forks will not have the HW - if: github.repository == 'oneapi-src/unified-memory-framework' - strategy: - matrix: - shared_library: ['ON', 'OFF'] - build_type: ['Debug', 'Release'] - os: ['Ubuntu', 'Windows'] - include: - - os: 'Windows' - compiler: {c: cl, cxx: cl} - number_of_processors: '$Env:NUMBER_OF_PROCESSORS' - - os: 'Ubuntu' - compiler: {c: gcc, cxx: g++} - number_of_processors: '$(nproc)' - exclude: - - os: 'Windows' - build_type: 'Debug' - - runs-on: ["DSS-CUDA", "DSS-${{matrix.os}}"] - steps: - - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - fetch-depth: 0 - - - name: Get information about platform - if: matrix.os == 'Ubuntu' - run: .github/scripts/get_system_info.sh - - - name: Initialize vcpkg - if: matrix.os == 'Windows' - uses: lukka/run-vcpkg@5e0cab206a5ea620130caf672fce3e4a6b5666a1 # v11.5 - with: - vcpkgGitCommitId: 3dd44b931481d7a8e9ba412621fa810232b66289 - vcpkgDirectory: ${{env.BUILD_DIR}}/vcpkg - vcpkgJsonGlob: '**/vcpkg.json' - - - name: Install dependencies (windows-latest) - if: matrix.os == 'Windows' - run: vcpkg install - shell: pwsh # Specifies PowerShell as the shell for running the script. - - - name: Configure build for Win - if: matrix.os == 'Windows' - run: > - cmake - -DCMAKE_PREFIX_PATH="${{env.VCPKG_PATH}}${{env.CUDA_PATH}}" - -B ${{env.BUILD_DIR}} - -DCMAKE_INSTALL_PREFIX="${{env.INSTL_DIR}}" - -DCMAKE_BUILD_TYPE=${{matrix.build_type}} - -DCMAKE_C_COMPILER=${{matrix.compiler.c}} - -DCMAKE_CXX_COMPILER=${{matrix.compiler.cxx}} - -DUMF_BUILD_SHARED_LIBRARY=${{matrix.shared_library}} - -DUMF_BUILD_BENCHMARKS=ON - -DUMF_BUILD_TESTS=ON - -DUMF_BUILD_GPU_TESTS=ON - -DUMF_BUILD_GPU_EXAMPLES=ON - -DUMF_FORMAT_CODE_STYLE=OFF - -DUMF_DEVELOPER_MODE=ON - -DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON - -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON - -DUMF_BUILD_LEVEL_ZERO_PROVIDER=OFF - -DUMF_BUILD_CUDA_PROVIDER=ON - -DUMF_TESTS_FAIL_ON_SKIP=ON - - - name: Configure build for Ubuntu - if: matrix.os == 'Ubuntu' - run: > - cmake - -B ${{env.BUILD_DIR}} - -DCMAKE_INSTALL_PREFIX="${{env.INSTL_DIR}}" - -DCMAKE_BUILD_TYPE=${{matrix.build_type}} - -DCMAKE_C_COMPILER=${{matrix.compiler.c}} - -DCMAKE_CXX_COMPILER=${{matrix.compiler.cxx}} - -DUMF_BUILD_SHARED_LIBRARY=${{matrix.shared_library}} - -DUMF_BUILD_BENCHMARKS=ON - -DUMF_BUILD_TESTS=ON - -DUMF_BUILD_GPU_TESTS=ON - -DUMF_BUILD_GPU_EXAMPLES=ON - -DUMF_FORMAT_CODE_STYLE=OFF - -DUMF_DEVELOPER_MODE=ON - -DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON - -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON - -DUMF_BUILD_LEVEL_ZERO_PROVIDER=OFF - -DUMF_BUILD_CUDA_PROVIDER=ON - -DUMF_TESTS_FAIL_ON_SKIP=ON - ${{ matrix.build_type == 'Debug' && '-DUMF_USE_COVERAGE=ON' || '' }} - - - name: Build UMF - run: cmake --build ${{env.BUILD_DIR}} --config ${{matrix.build_type}} -j ${{matrix.number_of_processors}} - - - name: Run tests - working-directory: ${{env.BUILD_DIR}} - run: ctest -C ${{matrix.build_type}} --output-on-failure --test-dir test - - - name: Run examples - working-directory: ${{env.BUILD_DIR}} - run: ctest --output-on-failure --test-dir examples -C ${{matrix.build_type}} - - - name: Run benchmarks - working-directory: ${{env.BUILD_DIR}} - run: ctest --output-on-failure --test-dir benchmark -C ${{matrix.build_type}} --exclude-regex umf-bench-multithreaded - - - name: Check coverage - if: ${{ matrix.build_type == 'Debug' && matrix.os == 'Ubuntu' }} - working-directory: ${{env.BUILD_DIR}} - run: | - export COVERAGE_FILE_NAME=${{env.COVERAGE_NAME}}-shared-${{matrix.shared_library}} - echo "COVERAGE_FILE_NAME: $COVERAGE_FILE_NAME" - ../scripts/coverage/coverage_capture.sh $COVERAGE_FILE_NAME - mkdir -p ${{env.COVERAGE_DIR}} - mv ./$COVERAGE_FILE_NAME ${{env.COVERAGE_DIR}} - - - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 - if: ${{ matrix.build_type == 'Debug' && matrix.os == 'Ubuntu' }} - with: - name: ${{env.COVERAGE_NAME}}-shared-${{matrix.shared_library}} - path: ${{env.COVERAGE_DIR}} From 32ab8c3e338dc5bbd58e8060ee25284f8763126e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Thu, 24 Oct 2024 16:21:11 +0200 Subject: [PATCH 281/352] [CI] Enable short run of QEMU in PR/push workflow Run full QEMU suite in nightly workflow only. Enable more Ubuntu OSes along. --- .github/workflows/nightly.yml | 9 +++++- .github/workflows/pr_push.yml | 8 +++-- .github/workflows/reusable_qemu.yml | 50 +++++++++++++++++++++++------ scripts/qemu/run-tests.sh | 16 ++++++--- scripts/qemu/start_qemu.sh | 2 +- 5 files changed, 66 insertions(+), 19 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index b6d6ee78f..9fa036118 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -183,4 +183,11 @@ jobs: CUDA: uses: ./.github/workflows/reusable_gpu.yml with: - name: "CUDA" \ No newline at end of file + name: "CUDA" + + # Full exeuction of QEMU tests + QEMU: + uses: ./.github/workflows/reusable_qemu.yml + with: + short_run: false + os: "['ubuntu-23.04', 'ubuntu-24.04']" diff --git a/.github/workflows/pr_push.yml b/.github/workflows/pr_push.yml index c1bc6053e..9623b69f1 100644 --- a/.github/workflows/pr_push.yml +++ b/.github/workflows/pr_push.yml @@ -49,9 +49,11 @@ jobs: Sanitizers: needs: [FastBuild] uses: ./.github/workflows/reusable_sanitizers.yml - Qemu: + QEMU: needs: [FastBuild] uses: ./.github/workflows/reusable_qemu.yml + with: + short_run: true Benchmarks: needs: [Build] uses: ./.github/workflows/reusable_benchmarks.yml @@ -64,7 +66,7 @@ jobs: Coverage: # total coverage (on upstream only) if: github.repository == 'oneapi-src/unified-memory-framework' - needs: [Build, DevDax, L0, CUDA, MultiNuma, Qemu, ProxyLib] + needs: [Build, DevDax, L0, CUDA, MultiNuma, QEMU, ProxyLib] uses: ./.github/workflows/reusable_coverage.yml secrets: inherit with: @@ -72,7 +74,7 @@ jobs: Coverage_partial: # partial coverage (on forks) if: github.repository != 'oneapi-src/unified-memory-framework' - needs: [Build, Qemu, ProxyLib] + needs: [Build, QEMU, ProxyLib] uses: ./.github/workflows/reusable_coverage.yml CodeQL: needs: [Build] diff --git a/.github/workflows/reusable_qemu.yml b/.github/workflows/reusable_qemu.yml index 7d6724cdd..8d9e00d64 100644 --- a/.github/workflows/reusable_qemu.yml +++ b/.github/workflows/reusable_qemu.yml @@ -1,14 +1,29 @@ # Builds project on qemu with custom hmat settings name: Qemu -on: workflow_call +on: + workflow_call: + inputs: + short_run: + description: Should the workflow run only basic tests? + type: boolean + default: false + os: + description: List of OSes + type: string + default: '["ubuntu-23.04"]' permissions: contents: read jobs: qemu-build: - name: Qemu + name: QEMU + strategy: + matrix: + os: ${{ fromJson(inputs.os) }} + + # Host QEMU on any Linux platform runs-on: ubuntu-22.04 steps: @@ -79,11 +94,26 @@ jobs: sudo -Sk genisoimage -output ubuntu-cloud-init.iso -volid cidata -joliet -rock ./user-data ./meta-data - - name: Download ubuntu image - run: wget https://cloud-images.ubuntu.com/releases/lunar/release/ubuntu-23.04-server-cloudimg-amd64.img + - name: Set vars if short run + if: ${{ inputs.short_run == true }} + run: | + echo "SHORT_RUN=true" >> $GITHUB_ENV + declare -a short_configs=("default.xml" "sock_2_var3.xml" "sock_4_var1_hmat.xml") + echo "CONFIG_OPTIONS=${short_configs[@]}" >> $GITHUB_ENV + + - name: Set vars if long run + if: ${{ inputs.short_run == false }} + run: | + echo "SHORT_RUN=false" >> $GITHUB_ENV + echo "CONFIG_OPTIONS=umf/scripts/qemu/configs/*.xml" >> $GITHUB_ENV + + - name: Download Ubuntu image + run: | + OS_VER=$(echo ${{matrix.os}} | cut -d'-' -f2) + wget https://cloud-images.ubuntu.com/releases/${OS_VER}/release/${{matrix.os}}-server-cloudimg-amd64.img -O qemu_image.img - name: Resize image - run: qemu-img resize ./ubuntu-23.04-server-cloudimg-amd64.img +4G + run: qemu-img resize ./qemu_image.img +4G - name: Build UMF in QEMU run: | @@ -98,7 +128,9 @@ jobs: - name: Run tests in QEMU run: | - for config_file in umf/scripts/qemu/configs/*.xml; do + echo "Running tests for: ${CONFIG_OPTIONS}" + + for config_file in ${CONFIG_OPTIONS}; do config_name=$(basename $config_file) while ps -aux | grep qemu-system-x86_64 | grep -q -v grep; do @@ -106,10 +138,10 @@ jobs: sleep 5 done - echo "\n ### Testing ${config_name} ###" + echo "### Testing ${config_name} ###" umf/scripts/qemu/start_qemu.sh ${config_name} - ssh testuser@127.0.0.1 -p 2222 -t "bash /home/testuser/scripts/qemu/run-tests.sh COVERAGE ${config_name}" + ssh testuser@127.0.0.1 -p 2222 -t "export SHORT_RUN=${SHORT_RUN} OS_FULL_NAME=${{matrix.os}} && /home/testuser/scripts/qemu/run-tests.sh COVERAGE ${config_name}" scp -r -P 2222 testuser@127.0.0.1:/home/testuser/coverage ./ ssh testuser@127.0.0.1 -p 2222 -t "sudo shutdown -h now" done @@ -117,5 +149,5 @@ jobs: - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 with: - name: exports-coverage-qemu-all + name: exports-coverage-qemu-${{matrix.os}} path: coverage diff --git a/scripts/qemu/run-tests.sh b/scripts/qemu/run-tests.sh index 69f187990..9d855590b 100755 --- a/scripts/qemu/run-tests.sh +++ b/scripts/qemu/run-tests.sh @@ -3,6 +3,9 @@ # Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# If env var SHORT_RUN is set to true, part of the tests are skipped here. +# For coverage, OS_FULL_NAME env variable has to be set to the name of the OS. + set -e COVERAGE=$1 @@ -26,19 +29,22 @@ echo password | sudo bash -c "echo 0 > /proc/sys/kernel/yama/ptrace_scope" numactl -H cd build +echo "## Running all tests ..." ctest --verbose -# run tests bound to a numa node +echo "## Running tests bound to a numa node 0 and node 1 ..." numactl -N 0 ctest --output-on-failure numactl -N 1 ctest --output-on-failure if [ "$COVERAGE" = "COVERAGE" ]; then - COVERAGE_FILE_NAME=exports-coverage-qemu-$CONFIG_NAME + COVERAGE_FILE_NAME=exports-coverage-qemu-${OS_FULL_NAME}-${CONFIG_NAME} echo "COVERAGE_FILE_NAME: $COVERAGE_FILE_NAME" ../scripts/coverage/coverage_capture.sh $COVERAGE_FILE_NAME mv ./$COVERAGE_FILE_NAME $COVERAGE_DIR fi -# run tests under valgrind -echo "Running tests under valgrind memcheck ..." -../test/test_valgrind.sh .. . memcheck +# run tests under valgrind only on long run or for default configuration +if [ "${SHORT_RUN}" != "true" ] || [ "${CONFIG_NAME}" == "default" ]; then + echo "## Running tests under valgrind memcheck ..." + ../test/test_valgrind.sh .. . memcheck +fi diff --git a/scripts/qemu/start_qemu.sh b/scripts/qemu/start_qemu.sh index 8c1791d7e..c4758ac17 100755 --- a/scripts/qemu/start_qemu.sh +++ b/scripts/qemu/start_qemu.sh @@ -14,7 +14,7 @@ parsed_config=$(python3 "$(dirname $0)/parse_config.py" "$(dirname $0)/configs/$ set -x sudo qemu-system-x86_64 \ - -drive file=./ubuntu-23.04-server-cloudimg-amd64.img,format=qcow2,index=0,media=disk,id=hd \ + -drive file=./qemu_image.img,format=qcow2,index=0,media=disk,id=hd \ -cdrom ./ubuntu-cloud-init.iso \ -enable-kvm \ -net nic -net user,hostfwd=tcp::2222-:22 \ From cace4ecca54a8b659418784e990afbc23c6d1d53 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Sat, 9 Nov 2024 10:54:35 +0100 Subject: [PATCH 282/352] Make utils_mmap_file() detect DAX using MAP_SYNC flag Make utils_mmap_file() detect DAX using MAP_SYNC flag. Add bool *map_sync argument to utils_mmap_file(). map_sync is set to true only if memory was mapped with MAP_SYNC, what means it is a DAX file/device. Signed-off-by: Lukasz Dorau --- src/provider/provider_devdax_memory.c | 8 ++-- src/provider/provider_file_memory.c | 6 +-- src/utils/utils_common.h | 3 +- src/utils/utils_linux_common.c | 66 ++++++++++++++------------- src/utils/utils_macosx_common.c | 4 +- src/utils/utils_windows_common.c | 3 +- 6 files changed, 49 insertions(+), 41 deletions(-) diff --git a/src/provider/provider_devdax_memory.c b/src/provider/provider_devdax_memory.c index bae968a1d..ad9f4be3f 100644 --- a/src/provider/provider_devdax_memory.c +++ b/src/provider/provider_devdax_memory.c @@ -143,9 +143,9 @@ static umf_result_t devdax_initialize(void *params, void **provider) { utils_translate_mem_visibility_flag(UMF_MEM_MAP_SYNC, &map_sync_flag); // mmap /dev/dax with the MAP_SYNC xor MAP_SHARED flag (if MAP_SYNC fails) - devdax_provider->base = utils_mmap_file(NULL, devdax_provider->size, - devdax_provider->protection, - map_sync_flag, fd, 0 /* offset */); + devdax_provider->base = utils_mmap_file( + NULL, devdax_provider->size, devdax_provider->protection, map_sync_flag, + fd, 0 /* offset */, NULL); utils_close_fd(fd); if (devdax_provider->base == NULL) { LOG_PDEBUG("devdax memory mapping failed (path=%s, size=%zu)", @@ -455,7 +455,7 @@ static umf_result_t devdax_open_ipc_handle(void *provider, // mmap /dev/dax with the MAP_SYNC xor MAP_SHARED flag (if MAP_SYNC fails) char *addr = utils_mmap_file(NULL, length_aligned, devdax_ipc_data->protection, - map_sync_flag, fd, offset_aligned); + map_sync_flag, fd, offset_aligned, NULL); if (addr == NULL) { devdax_store_last_native_error(UMF_DEVDAX_RESULT_ERROR_ALLOC_FAILED, errno); diff --git a/src/provider/provider_file_memory.c b/src/provider/provider_file_memory.c index 7086fe45c..039620f8d 100644 --- a/src/provider/provider_file_memory.c +++ b/src/provider/provider_file_memory.c @@ -293,8 +293,8 @@ static umf_result_t file_mmap_aligned(file_memory_provider_t *file_provider, ASSERT_IS_ALIGNED(extended_size, page_size); ASSERT_IS_ALIGNED(aligned_offset_fd, page_size); - void *ptr = - utils_mmap_file(NULL, extended_size, prot, flag, fd, aligned_offset_fd); + void *ptr = utils_mmap_file(NULL, extended_size, prot, flag, fd, + aligned_offset_fd, NULL); if (ptr == NULL) { LOG_PERR("memory mapping failed"); return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; @@ -683,7 +683,7 @@ static umf_result_t file_open_ipc_handle(void *provider, void *providerIpcData, char *addr = utils_mmap_file( NULL, file_ipc_data->size, file_ipc_data->protection, - file_ipc_data->visibility, fd, file_ipc_data->offset_fd); + file_ipc_data->visibility, fd, file_ipc_data->offset_fd, NULL); (void)utils_close_fd(fd); if (addr == NULL) { file_store_last_native_error(UMF_FILE_RESULT_ERROR_ALLOC_FAILED, errno); diff --git a/src/utils/utils_common.h b/src/utils/utils_common.h index eebc461f6..c25fda2ab 100644 --- a/src/utils/utils_common.h +++ b/src/utils/utils_common.h @@ -11,6 +11,7 @@ #define UMF_COMMON_H 1 #include +#include #include #include @@ -136,7 +137,7 @@ void *utils_mmap(void *hint_addr, size_t length, int prot, int flag, int fd, size_t fd_offset); void *utils_mmap_file(void *hint_addr, size_t length, int prot, int flags, - int fd, size_t fd_offset); + int fd, size_t fd_offset, bool *map_sync); int utils_munmap(void *addr, size_t length); diff --git a/src/utils/utils_linux_common.c b/src/utils/utils_linux_common.c index 1a44a2b64..e19ad52ae 100644 --- a/src/utils/utils_linux_common.c +++ b/src/utils/utils_linux_common.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -40,69 +41,72 @@ utils_translate_mem_visibility_flag(umf_memory_visibility_t in_flag, /* * Map given file into memory. - * If (flags & MAP_PRIVATE) it uses just mmap. Otherwise, if (flags & MAP_SYNC) - * it tries to mmap with (flags | MAP_SHARED_VALIDATE | MAP_SYNC) - * which allows flushing from the user-space. If MAP_SYNC fails and the user - * did not specify it by himself it tries to mmap with (flags | MAP_SHARED). + * If (flags & MAP_PRIVATE) it uses just mmap. Otherwise, it tries to mmap + * with (flags | MAP_SHARED_VALIDATE | MAP_SYNC) which allows flushing + * from the user-space. If MAP_SYNC fails and if the user did not specify + * this flag by himself, it falls back to the mmap with (flags | MAP_SHARED). */ void *utils_mmap_file(void *hint_addr, size_t length, int prot, int flags, - int fd, size_t fd_offset) { + int fd, size_t fd_offset, bool *map_sync) { void *addr; + if (map_sync) { + *map_sync = false; + } + /* * MAP_PRIVATE and MAP_SHARED are mutually exclusive, * therefore mmap with MAP_PRIVATE is executed separately. */ if (flags & MAP_PRIVATE) { addr = utils_mmap(hint_addr, length, prot, flags, fd, fd_offset); - if (addr == MAP_FAILED) { + if (addr == NULL) { LOG_PERR("mapping file with the MAP_PRIVATE flag failed (fd=%i, " - "offset=%zu, length=%zu)", - fd, fd_offset, length); + "offset=%zu, length=%zu, flags=%i)", + fd, fd_offset, length, flags); return NULL; } LOG_DEBUG("file mapped with the MAP_PRIVATE flag (fd=%i, offset=%zu, " - "length=%zu)", - fd, fd_offset, length); + "length=%zu, flags=%i)", + fd, fd_offset, length, flags); return addr; } errno = 0; - if (flags & MAP_SYNC) { - /* try to mmap with MAP_SYNC flag */ - const int sync_flags = MAP_SHARED_VALIDATE | MAP_SYNC; - addr = utils_mmap(hint_addr, length, prot, flags | sync_flags, fd, - fd_offset); - if (addr) { - LOG_DEBUG("file mapped with the MAP_SYNC flag (fd=%i, offset=%zu, " - "length=%zu)", - fd, fd_offset, length); - return addr; + /* try to mmap with MAP_SYNC flag */ + const int sync_flags = flags | MAP_SHARED_VALIDATE | MAP_SYNC; + addr = utils_mmap(hint_addr, length, prot, sync_flags, fd, fd_offset); + if (addr) { + LOG_DEBUG("file mapped with the MAP_SYNC flag (fd=%i, offset=%zu, " + "length=%zu, flags=%i)", + fd, fd_offset, length, sync_flags); + if (map_sync) { + *map_sync = true; } - - LOG_PERR("mapping file with the MAP_SYNC flag failed (fd=%i, " - "offset=%zu, length=%zu)", - fd, fd_offset, length); + return addr; } - if ((!(flags & MAP_SYNC)) || errno == EINVAL || errno == ENOTSUP || - errno == EOPNOTSUPP) { - /* try to mmap with MAP_SHARED flag (without MAP_SYNC) */ + LOG_PERR("mapping file with the MAP_SYNC flag failed (fd=%i, offset=%zu, " + "length=%zu, flags=%i)", + fd, fd_offset, length, sync_flags); + + /* try to mmap with MAP_SHARED flag (without MAP_SYNC) */ + if (errno == EINVAL || errno == ENOTSUP || errno == EOPNOTSUPP) { const int shared_flags = (flags & (~MAP_SYNC)) | MAP_SHARED; addr = utils_mmap(hint_addr, length, prot, shared_flags, fd, fd_offset); if (addr) { LOG_DEBUG("file mapped with the MAP_SHARED flag (fd=%i, " - "offset=%zu, length=%zu)", - fd, fd_offset, length); + "offset=%zu, length=%zu, flags=%i)", + fd, fd_offset, length, shared_flags); return addr; } LOG_PERR("mapping file with the MAP_SHARED flag failed (fd=%i, " - "offset=%zu, length=%zu)", - fd, fd_offset, length); + "offset=%zu, length=%zu, flags=%i)", + fd, fd_offset, length, shared_flags); } return NULL; diff --git a/src/utils/utils_macosx_common.c b/src/utils/utils_macosx_common.c index 1356a2ef9..c949fd527 100644 --- a/src/utils/utils_macosx_common.c +++ b/src/utils/utils_macosx_common.c @@ -12,6 +12,7 @@ #include #include +#include "utils_common.h" #include "utils_log.h" umf_result_t @@ -30,13 +31,14 @@ utils_translate_mem_visibility_flag(umf_memory_visibility_t in_flag, } void *utils_mmap_file(void *hint_addr, size_t length, int prot, int flags, - int fd, size_t fd_offset) { + int fd, size_t fd_offset, bool *map_sync) { (void)hint_addr; // unused (void)length; // unused (void)prot; // unused (void)flags; // unused (void)fd; // unused (void)fd_offset; // unused + (void)map_sync; // unused return NULL; // not supported } diff --git a/src/utils/utils_windows_common.c b/src/utils/utils_windows_common.c index 4646b6f55..8d5f4e940 100644 --- a/src/utils/utils_windows_common.c +++ b/src/utils/utils_windows_common.c @@ -148,13 +148,14 @@ void *utils_mmap(void *hint_addr, size_t length, int prot, int flag, int fd, } void *utils_mmap_file(void *hint_addr, size_t length, int prot, int flags, - int fd, size_t fd_offset) { + int fd, size_t fd_offset, bool *map_sync) { (void)hint_addr; // unused (void)length; // unused (void)prot; // unused (void)flags; // unused (void)fd; // unused (void)fd_offset; // unused + (void)map_sync; // unused return NULL; // not supported } From 199e754022bdf2c40eea42f78002c8c81b02721e Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 13 Nov 2024 12:40:59 +0100 Subject: [PATCH 283/352] Remove the UMF_MEM_MAP_SYNC flag Remove the UMF_MEM_MAP_SYNC flag, UMF_MEM_MAP_SHARED should be used instead. Verify if /dev/dax was mapped with MAP_SYNC. Signed-off-by: Lukasz Dorau --- README.md | 4 +- examples/dram_and_fsdax/dram_and_fsdax.c | 4 +- include/umf/memory_provider.h | 1 - src/provider/provider_devdax_memory.c | 55 ++++++++++++++++-------- src/provider/provider_file_memory.c | 22 ++++------ src/utils/utils_linux_common.c | 5 +-- src/utils/utils_macosx_common.c | 2 - src/utils/utils_windows_common.c | 2 - test/ipc_file_prov_consumer.c | 18 +------- test/ipc_file_prov_fsdax.sh | 4 +- test/ipc_file_prov_producer.c | 18 +------- test/provider_file_memory.cpp | 2 +- 12 files changed, 56 insertions(+), 81 deletions(-) diff --git a/README.md b/README.md index 923db6f2c..b31e349f0 100644 --- a/README.md +++ b/README.md @@ -207,10 +207,10 @@ so it should be used with a pool manager that will take over the managing of the provided memory - for example the jemalloc pool with the `disable_provider_free` parameter set to true. -IPC API requires the `UMF_MEM_MAP_SHARED` or `UMF_MEM_MAP_SYNC` memory `visibility` mode +IPC API requires the `UMF_MEM_MAP_SHARED` memory `visibility` mode (`UMF_RESULT_ERROR_INVALID_ARGUMENT` is returned otherwise). -The memory visibility mode parameter must be set to `UMF_MEM_MAP_SYNC` in case of FSDAX. +The memory visibility mode parameter must be set to `UMF_MEM_MAP_SHARED` in case of FSDAX. ##### Requirements diff --git a/examples/dram_and_fsdax/dram_and_fsdax.c b/examples/dram_and_fsdax/dram_and_fsdax.c index bc985692f..ac7b0434c 100644 --- a/examples/dram_and_fsdax/dram_and_fsdax.c +++ b/examples/dram_and_fsdax/dram_and_fsdax.c @@ -50,8 +50,8 @@ static umf_memory_pool_handle_t create_fsdax_pool(const char *path) { umf_file_memory_provider_params_t params_fsdax = umfFileMemoryProviderParamsDefault(path); - // FSDAX requires mapping the UMF_MEM_MAP_SYNC flag - params_fsdax.visibility = UMF_MEM_MAP_SYNC; + // FSDAX requires mapping the UMF_MEM_MAP_SHARED flag + params_fsdax.visibility = UMF_MEM_MAP_SHARED; umf_result = umfMemoryProviderCreate(umfFileMemoryProviderOps(), ¶ms_fsdax, &provider_fsdax); diff --git a/include/umf/memory_provider.h b/include/umf/memory_provider.h index 073b04efb..cff6f9eec 100644 --- a/include/umf/memory_provider.h +++ b/include/umf/memory_provider.h @@ -21,7 +21,6 @@ extern "C" { typedef enum umf_memory_visibility_t { UMF_MEM_MAP_PRIVATE = 1, ///< private memory mapping UMF_MEM_MAP_SHARED, ///< shared memory mapping (Linux only) - UMF_MEM_MAP_SYNC, ///< direct mapping of persistent memory (supported only for files supporting DAX, Linux only) } umf_memory_visibility_t; /// @brief Protection of the memory allocations diff --git a/src/provider/provider_devdax_memory.c b/src/provider/provider_devdax_memory.c index ad9f4be3f..c7f644db3 100644 --- a/src/provider/provider_devdax_memory.c +++ b/src/provider/provider_devdax_memory.c @@ -139,21 +139,31 @@ static umf_result_t devdax_initialize(void *params, void **provider) { goto err_free_devdax_provider; } - unsigned map_sync_flag = 0; - utils_translate_mem_visibility_flag(UMF_MEM_MAP_SYNC, &map_sync_flag); + bool is_dax = false; - // mmap /dev/dax with the MAP_SYNC xor MAP_SHARED flag (if MAP_SYNC fails) + // mmap /dev/dax with the MAP_SYNC devdax_provider->base = utils_mmap_file( - NULL, devdax_provider->size, devdax_provider->protection, map_sync_flag, - fd, 0 /* offset */, NULL); + NULL, devdax_provider->size, devdax_provider->protection, 0 /* flags */, + fd, 0 /* offset */, &is_dax); utils_close_fd(fd); if (devdax_provider->base == NULL) { - LOG_PDEBUG("devdax memory mapping failed (path=%s, size=%zu)", + LOG_PDEBUG("mapping the devdax failed (path=%s, size=%zu)", in_params->path, devdax_provider->size); ret = UMF_RESULT_ERROR_UNKNOWN; goto err_free_devdax_provider; } + if (!is_dax) { + LOG_ERR("mapping the devdax with MAP_SYNC failed: %s", in_params->path); + ret = UMF_RESULT_ERROR_UNKNOWN; + + if (devdax_provider->base) { + utils_munmap(devdax_provider->base, devdax_provider->size); + } + + goto err_free_devdax_provider; + } + LOG_DEBUG("devdax memory mapped (path=%s, size=%zu, addr=%p)", in_params->path, devdax_provider->size, devdax_provider->base); @@ -433,6 +443,8 @@ static umf_result_t devdax_open_ipc_handle(void *provider, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } + *ptr = NULL; + devdax_ipc_data_t *devdax_ipc_data = (devdax_ipc_data_t *)providerIpcData; int fd = utils_devdax_open(devdax_ipc_data->path); @@ -441,9 +453,6 @@ static umf_result_t devdax_open_ipc_handle(void *provider, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - unsigned map_sync_flag = 0; - utils_translate_mem_visibility_flag(UMF_MEM_MAP_SYNC, &map_sync_flag); - // It is just a workaround for case when // devdax_alloc() was called with the size argument // that is not a multiplier of DEVDAX_PAGE_SIZE_2MB. @@ -452,25 +461,35 @@ static umf_result_t devdax_open_ipc_handle(void *provider, utils_align_ptr_down_size_up((void **)&offset_aligned, &length_aligned, DEVDAX_PAGE_SIZE_2MB); - // mmap /dev/dax with the MAP_SYNC xor MAP_SHARED flag (if MAP_SYNC fails) + bool is_dax = false; + + // mmap /dev/dax with the MAP_SYNC char *addr = utils_mmap_file(NULL, length_aligned, devdax_ipc_data->protection, - map_sync_flag, fd, offset_aligned, NULL); + 0 /* flags */, fd, offset_aligned, &is_dax); + (void)utils_close_fd(fd); if (addr == NULL) { - devdax_store_last_native_error(UMF_DEVDAX_RESULT_ERROR_ALLOC_FAILED, - errno); - LOG_PERR("devdax mapping failed (path: %s, size: %zu, protection: %i, " "fd: %i, offset: %zu)", devdax_ipc_data->path, length_aligned, devdax_ipc_data->protection, fd, offset_aligned); - *ptr = NULL; - (void)utils_close_fd(fd); - + devdax_store_last_native_error(UMF_DEVDAX_RESULT_ERROR_ALLOC_FAILED, + errno); return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; } + if (!is_dax) { + LOG_ERR("mapping the devdax with MAP_SYNC failed: %s", + devdax_ipc_data->path); + + if (addr) { + utils_munmap(addr, length_aligned); + } + + return UMF_RESULT_ERROR_UNKNOWN; + } + LOG_DEBUG("devdax mapped (path: %s, size: %zu, protection: %i, fd: %i, " "offset: %zu) to address %p", devdax_ipc_data->path, length_aligned, @@ -478,8 +497,6 @@ static umf_result_t devdax_open_ipc_handle(void *provider, *ptr = addr; - (void)utils_close_fd(fd); - return UMF_RESULT_SUCCESS; } diff --git a/src/provider/provider_file_memory.c b/src/provider/provider_file_memory.c index 039620f8d..ec3cd25cd 100644 --- a/src/provider/provider_file_memory.c +++ b/src/provider/provider_file_memory.c @@ -51,7 +51,7 @@ typedef struct file_memory_provider_t { unsigned visibility; // memory visibility mode size_t page_size; // minimum page size - // IPC is enabled only for UMF_MEM_MAP_SHARED or UMF_MEM_MAP_SYNC visibility + // IPC is enabled only for the UMF_MEM_MAP_SHARED visibility bool IPC_enabled; critnib *mmaps; // a critnib map storing mmap mappings (addr, size) @@ -114,9 +114,8 @@ file_translate_params(umf_file_memory_provider_params_t *in_params, return result; } - // IPC is enabled only for UMF_MEM_MAP_SHARED or UMF_MEM_MAP_SYNC visibility - provider->IPC_enabled = (in_params->visibility == UMF_MEM_MAP_SHARED || - in_params->visibility == UMF_MEM_MAP_SYNC); + // IPC is enabled only for the UMF_MEM_MAP_SHARED visibility + provider->IPC_enabled = (in_params->visibility == UMF_MEM_MAP_SHARED); return UMF_RESULT_SUCCESS; } @@ -594,8 +593,7 @@ static umf_result_t file_get_ipc_handle_size(void *provider, size_t *size) { file_memory_provider_t *file_provider = (file_memory_provider_t *)provider; if (!file_provider->IPC_enabled) { - LOG_ERR("memory visibility mode is not UMF_MEM_MAP_SHARED nor " - "UMF_MEM_MAP_SYNC") + LOG_ERR("memory visibility mode is not UMF_MEM_MAP_SHARED") return UMF_RESULT_ERROR_INVALID_ARGUMENT; } @@ -612,8 +610,7 @@ static umf_result_t file_get_ipc_handle(void *provider, const void *ptr, file_memory_provider_t *file_provider = (file_memory_provider_t *)provider; if (!file_provider->IPC_enabled) { - LOG_ERR("memory visibility mode is not UMF_MEM_MAP_SHARED nor " - "UMF_MEM_MAP_SYNC") + LOG_ERR("memory visibility mode is not UMF_MEM_MAP_SHARED") return UMF_RESULT_ERROR_INVALID_ARGUMENT; } @@ -643,8 +640,7 @@ static umf_result_t file_put_ipc_handle(void *provider, void *providerIpcData) { file_memory_provider_t *file_provider = (file_memory_provider_t *)provider; if (!file_provider->IPC_enabled) { - LOG_ERR("memory visibility mode is not UMF_MEM_MAP_SHARED nor " - "UMF_MEM_MAP_SYNC") + LOG_ERR("memory visibility mode is not UMF_MEM_MAP_SHARED") return UMF_RESULT_ERROR_INVALID_ARGUMENT; } @@ -665,8 +661,7 @@ static umf_result_t file_open_ipc_handle(void *provider, void *providerIpcData, file_memory_provider_t *file_provider = (file_memory_provider_t *)provider; if (!file_provider->IPC_enabled) { - LOG_ERR("memory visibility mode is not UMF_MEM_MAP_SHARED nor " - "UMF_MEM_MAP_SYNC") + LOG_ERR("memory visibility mode is not UMF_MEM_MAP_SHARED") return UMF_RESULT_ERROR_INVALID_ARGUMENT; } @@ -712,8 +707,7 @@ static umf_result_t file_close_ipc_handle(void *provider, void *ptr, file_memory_provider_t *file_provider = (file_memory_provider_t *)provider; if (!file_provider->IPC_enabled) { - LOG_ERR("memory visibility mode is not UMF_MEM_MAP_SHARED nor " - "UMF_MEM_MAP_SYNC") + LOG_ERR("memory visibility mode is not UMF_MEM_MAP_SHARED") return UMF_RESULT_ERROR_INVALID_ARGUMENT; } diff --git a/src/utils/utils_linux_common.c b/src/utils/utils_linux_common.c index e19ad52ae..b97880ffd 100644 --- a/src/utils/utils_linux_common.c +++ b/src/utils/utils_linux_common.c @@ -32,9 +32,6 @@ utils_translate_mem_visibility_flag(umf_memory_visibility_t in_flag, case UMF_MEM_MAP_SHARED: *out_flag = MAP_SHARED; return UMF_RESULT_SUCCESS; - case UMF_MEM_MAP_SYNC: - *out_flag = MAP_SYNC; - return UMF_RESULT_SUCCESS; } return UMF_RESULT_ERROR_INVALID_ARGUMENT; } @@ -95,7 +92,7 @@ void *utils_mmap_file(void *hint_addr, size_t length, int prot, int flags, /* try to mmap with MAP_SHARED flag (without MAP_SYNC) */ if (errno == EINVAL || errno == ENOTSUP || errno == EOPNOTSUPP) { - const int shared_flags = (flags & (~MAP_SYNC)) | MAP_SHARED; + const int shared_flags = flags | MAP_SHARED; addr = utils_mmap(hint_addr, length, prot, shared_flags, fd, fd_offset); if (addr) { LOG_DEBUG("file mapped with the MAP_SHARED flag (fd=%i, " diff --git a/src/utils/utils_macosx_common.c b/src/utils/utils_macosx_common.c index c949fd527..ad1de12fd 100644 --- a/src/utils/utils_macosx_common.c +++ b/src/utils/utils_macosx_common.c @@ -24,8 +24,6 @@ utils_translate_mem_visibility_flag(umf_memory_visibility_t in_flag, return UMF_RESULT_SUCCESS; case UMF_MEM_MAP_SHARED: return UMF_RESULT_ERROR_NOT_SUPPORTED; // not supported on MacOSX - case UMF_MEM_MAP_SYNC: - return UMF_RESULT_ERROR_NOT_SUPPORTED; // not supported on MacOSX } return UMF_RESULT_ERROR_INVALID_ARGUMENT; } diff --git a/src/utils/utils_windows_common.c b/src/utils/utils_windows_common.c index 8d5f4e940..50a7b6ed5 100644 --- a/src/utils/utils_windows_common.c +++ b/src/utils/utils_windows_common.c @@ -96,8 +96,6 @@ utils_translate_mem_visibility_flag(umf_memory_visibility_t in_flag, return UMF_RESULT_SUCCESS; case UMF_MEM_MAP_SHARED: return UMF_RESULT_ERROR_NOT_SUPPORTED; // not supported on Windows yet - case UMF_MEM_MAP_SYNC: - return UMF_RESULT_ERROR_NOT_SUPPORTED; // not supported on Windows yet } return UMF_RESULT_ERROR_INVALID_ARGUMENT; } diff --git a/test/ipc_file_prov_consumer.c b/test/ipc_file_prov_consumer.c index 6c53ad320..6333552a2 100644 --- a/test/ipc_file_prov_consumer.c +++ b/test/ipc_file_prov_consumer.c @@ -18,30 +18,16 @@ int main(int argc, char *argv[]) { if (argc < 3) { - fprintf(stderr, "usage: %s \n", argv[0]); - fprintf(stderr, " should be \"FSDAX\" or \"fsdax\" if " - " is located on FSDAX \n"); + fprintf(stderr, "usage: %s \n", argv[0]); return -1; } int port = atoi(argv[1]); char *file_name = argv[2]; - bool is_fsdax = false; - - if (argc >= 4) { - if (strncasecmp(argv[3], "FSDAX", strlen("FSDAX")) == 0) { - is_fsdax = true; - } - } umf_file_memory_provider_params_t file_params; - file_params = umfFileMemoryProviderParamsDefault(file_name); - if (is_fsdax) { - file_params.visibility = UMF_MEM_MAP_SYNC; - } else { - file_params.visibility = UMF_MEM_MAP_SHARED; - } + file_params.visibility = UMF_MEM_MAP_SHARED; void *pool_params = NULL; diff --git a/test/ipc_file_prov_fsdax.sh b/test/ipc_file_prov_fsdax.sh index 6f8d75541..4e908869b 100755 --- a/test/ipc_file_prov_fsdax.sh +++ b/test/ipc_file_prov_fsdax.sh @@ -31,13 +31,13 @@ UMF_LOG_VAL="level:debug;flush:debug;output:stderr;pid:yes" rm -f ${FILE_NAME} echo "Starting ipc_file_prov_fsdax CONSUMER on port $PORT ..." -UMF_LOG=$UMF_LOG_VAL ./umf_test-ipc_file_prov_consumer $PORT $FILE_NAME "FSDAX" & +UMF_LOG=$UMF_LOG_VAL ./umf_test-ipc_file_prov_consumer $PORT $FILE_NAME & echo "Waiting 1 sec ..." sleep 1 echo "Starting ipc_file_prov_fsdax PRODUCER on port $PORT ..." -UMF_LOG=$UMF_LOG_VAL ./umf_test-ipc_file_prov_producer $PORT $FILE_NAME_2 "FSDAX" +UMF_LOG=$UMF_LOG_VAL ./umf_test-ipc_file_prov_producer $PORT $FILE_NAME_2 # remove the SHM file rm -f ${FILE_NAME} diff --git a/test/ipc_file_prov_producer.c b/test/ipc_file_prov_producer.c index ee9d96f1e..efcbdd3bf 100644 --- a/test/ipc_file_prov_producer.c +++ b/test/ipc_file_prov_producer.c @@ -18,30 +18,16 @@ int main(int argc, char *argv[]) { if (argc < 3) { - fprintf(stderr, "usage: %s \n", argv[0]); - fprintf(stderr, " should be \"FSDAX\" or \"fsdax\" if " - " is located on FSDAX \n"); + fprintf(stderr, "usage: %s \n", argv[0]); return -1; } int port = atoi(argv[1]); char *file_name = argv[2]; - bool is_fsdax = false; - - if (argc >= 4) { - if (strncasecmp(argv[3], "FSDAX", strlen("FSDAX")) == 0) { - is_fsdax = true; - } - } umf_file_memory_provider_params_t file_params; - file_params = umfFileMemoryProviderParamsDefault(file_name); - if (is_fsdax) { - file_params.visibility = UMF_MEM_MAP_SYNC; - } else { - file_params.visibility = UMF_MEM_MAP_SHARED; - } + file_params.visibility = UMF_MEM_MAP_SHARED; void *pool_params = NULL; diff --git a/test/provider_file_memory.cpp b/test/provider_file_memory.cpp index b2c71635d..eba7e8205 100644 --- a/test/provider_file_memory.cpp +++ b/test/provider_file_memory.cpp @@ -137,7 +137,7 @@ TEST_F(test, test_if_mapped_with_MAP_SYNC) { } auto params = umfFileMemoryProviderParamsDefault(path); - params.visibility = UMF_MEM_MAP_SYNC; + params.visibility = UMF_MEM_MAP_SHARED; umf_result = umfMemoryProviderCreate(umfFileMemoryProviderOps(), ¶ms, &hProvider); From 21e0126102728af04525126918656b52599c5e5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Wed, 13 Nov 2024 13:45:39 +0100 Subject: [PATCH 284/352] Fix misspells in the repo Partially found with aspell. --- scripts/docs_config/api.rst | 2 +- scripts/docs_config/introduction.rst | 2 +- src/ipc.c | 2 +- src/pool/pool_disjoint.cpp | 2 +- src/pool/pool_jemalloc.c | 2 +- src/pool/pool_scalable.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/docs_config/api.rst b/scripts/docs_config/api.rst index 6f8feb1fc..7f734cad2 100644 --- a/scripts/docs_config/api.rst +++ b/scripts/docs_config/api.rst @@ -148,7 +148,7 @@ Mempolicy Memtarget ========================================== -TODO: Add general information about memtarges. +TODO: Add general information about memtargets. Memtarget ------------------------------------------ diff --git a/scripts/docs_config/introduction.rst b/scripts/docs_config/introduction.rst index d47439047..f90b26b41 100644 --- a/scripts/docs_config/introduction.rst +++ b/scripts/docs_config/introduction.rst @@ -99,7 +99,7 @@ defined pool allocators if they implement the UMF interface. Memory Pools ============ -A memory pool consists of a pool allocator and a memory provider instancies +A memory pool consists of a pool allocator and a memory provider instances along with their properties and allocation policies. Memory pools are used by the :ref:`allocation API ` as a first argument. There is also a possibility to retrieve a memory pool from an existing memory pointer that points to a memory diff --git a/src/ipc.c b/src/ipc.c index 45e098619..5df755876 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -109,7 +109,7 @@ umf_result_t umfPutIPCHandle(umf_ipc_handle_t umfIPCHandle) { // implementation does nothing in Put function. Tracking memory // provider relies on IPC cache and actually Put IPC handle back // to upstream memory provider when umfMemoryProviderFree is called. - // To support incapsulation we should not take into account + // To support encapsulation we should not take into account // implementation details of tracking memory provider and find the // appropriate pool, get memory provider of that pool and call // umfMemoryProviderPutIPCHandle(hProvider, diff --git a/src/pool/pool_disjoint.cpp b/src/pool/pool_disjoint.cpp index edb5fc649..2cf8df7a4 100644 --- a/src/pool/pool_disjoint.cpp +++ b/src/pool/pool_disjoint.cpp @@ -237,7 +237,7 @@ class Bucket { // When a slab becomes entirely free we have to decide whether to return it // to the provider or keep it allocated. A simple check for size of the // Available list is not sufficient to check whether any slab has been - // pooled yet.We would have to traverse the entire Available listand check + // pooled yet. We would have to traverse the entire Available list and check // if any of them is entirely free. Instead we keep a counter of entirely // empty slabs within the Available list to speed up the process of checking // if a slab in this bucket is already pooled. diff --git a/src/pool/pool_jemalloc.c b/src/pool/pool_jemalloc.c index 094ceeaf7..fa1022e83 100644 --- a/src/pool/pool_jemalloc.c +++ b/src/pool/pool_jemalloc.c @@ -203,7 +203,7 @@ static bool arena_extent_decommit(extent_hooks_t *extent_hooks, void *addr, // physical pages within the virtual memory mapping associated with an extent at given addr and size // at offset bytes, extending for length on behalf of arena arena_ind. A lazy extent purge function // (e.g. implemented via madvise(...MADV_FREE)) can delay purging indefinitely and leave the pages -// within the purged virtual memory range in an indeterminite state, whereas a forced extent purge +// within the purged virtual memory range in an indeterminate state, whereas a forced extent purge // function immediately purges, and the pages within the virtual memory range will be zero-filled // the next time they are accessed. If the function returns true, this indicates failure to purge. // (from https://jemalloc.net/jemalloc.3.html) diff --git a/src/pool/pool_scalable.c b/src/pool/pool_scalable.c index 26ab7ad63..8e92d8758 100644 --- a/src/pool/pool_scalable.c +++ b/src/pool/pool_scalable.c @@ -183,7 +183,7 @@ umfScalablePoolParamsCreate(umf_scalable_pool_params_handle_t *params) { umf_scalable_pool_params_t *params_data = umf_ba_global_alloc(sizeof(umf_scalable_pool_params_t)); if (!params_data) { - LOG_ERR("cannot allocate memory for scalable poolparams"); + LOG_ERR("cannot allocate memory for scalable pool params"); return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; } From a512783d2337b14399549601b864df7d3779c007 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Wed, 13 Nov 2024 13:49:51 +0100 Subject: [PATCH 285/352] [Readme] Add missing info how to enable proxy_lib --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 923db6f2c..4b33e363c 100644 --- a/README.md +++ b/README.md @@ -241,6 +241,8 @@ This memory pool is distributed as part of libumf. It forwards all requests to t memory provider. Currently umfPoolRealloc, umfPoolCalloc and umfPoolMallocUsableSize functions are not supported by the proxy pool. +To enable this feature, the `UMF_BUILD_SHARED_LIBRARY` option needs to be turned `ON`. + #### Disjoint pool TODO: Add a description From 07878588a3e75e37397df8a2e9006363ad2a563b Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Fri, 8 Nov 2024 13:27:17 +0100 Subject: [PATCH 286/352] Check if file is located on FSDAX Signed-off-by: Lukasz Dorau --- src/provider/provider_file_memory.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/provider/provider_file_memory.c b/src/provider/provider_file_memory.c index ec3cd25cd..06621394b 100644 --- a/src/provider/provider_file_memory.c +++ b/src/provider/provider_file_memory.c @@ -33,12 +33,15 @@ umf_memory_provider_ops_t *umfFileMemoryProviderOps(void) { #include "utils_concurrency.h" #include "utils_log.h" +#define FSDAX_PAGE_SIZE_2MB ((size_t)(2 * 1024 * 1024)) // == 2 MB + #define TLS_MSG_BUF_LEN 1024 typedef struct file_memory_provider_t { utils_mutex_t lock; // lock for file parameters (size and offsets) char path[PATH_MAX]; // a path to the file + bool is_fsdax; // true if file is located on FSDAX int fd; // file descriptor for memory mapping size_t size_fd; // size of the file used for memory mappings size_t offset_fd; // offset in the file used for memory mappings @@ -163,17 +166,28 @@ static umf_result_t file_initialize(void *params, void **provider) { goto err_free_file_provider; } - if (utils_set_file_size(file_provider->fd, page_size)) { + if (utils_set_file_size(file_provider->fd, FSDAX_PAGE_SIZE_2MB)) { LOG_ERR("cannot set size of the file: %s", in_params->path); ret = UMF_RESULT_ERROR_UNKNOWN; goto err_close_fd; } - file_provider->size_fd = page_size; + file_provider->size_fd = FSDAX_PAGE_SIZE_2MB; LOG_DEBUG("size of the file %s is: %zu", in_params->path, file_provider->size_fd); + if (!(in_params->visibility & UMF_MEM_MAP_PRIVATE)) { + // check if file is located on FSDAX + void *addr = utils_mmap_file( + NULL, file_provider->size_fd, file_provider->protection, + file_provider->visibility, file_provider->fd, 0, + &file_provider->is_fsdax); + if (addr) { + utils_munmap(addr, file_provider->size_fd); + } + } + if (utils_mutex_init(&file_provider->lock) == NULL) { LOG_ERR("lock init failed"); ret = UMF_RESULT_ERROR_UNKNOWN; From 95f3b951105f0d0bdcac5fe7c08818de054b7eb3 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Sat, 9 Nov 2024 11:30:40 +0100 Subject: [PATCH 287/352] Fix setting page size in file provider Signed-off-by: Lukasz Dorau --- src/provider/provider_file_memory.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/provider/provider_file_memory.c b/src/provider/provider_file_memory.c index 06621394b..baeb06733 100644 --- a/src/provider/provider_file_memory.c +++ b/src/provider/provider_file_memory.c @@ -133,8 +133,6 @@ static umf_result_t file_initialize(void *params, void **provider) { umf_file_memory_provider_params_t *in_params = (umf_file_memory_provider_params_t *)params; - size_t page_size = utils_get_page_size(); - if (in_params->path == NULL) { LOG_ERR("file path is missing"); return UMF_RESULT_ERROR_INVALID_ARGUMENT; @@ -148,8 +146,6 @@ static umf_result_t file_initialize(void *params, void **provider) { memset(file_provider, 0, sizeof(*file_provider)); - file_provider->page_size = page_size; - ret = file_translate_params(in_params, file_provider); if (ret != UMF_RESULT_SUCCESS) { goto err_free_file_provider; @@ -188,6 +184,12 @@ static umf_result_t file_initialize(void *params, void **provider) { } } + if (file_provider->is_fsdax) { + file_provider->page_size = FSDAX_PAGE_SIZE_2MB; + } else { + file_provider->page_size = utils_get_page_size(); + } + if (utils_mutex_init(&file_provider->lock) == NULL) { LOG_ERR("lock init failed"); ret = UMF_RESULT_ERROR_UNKNOWN; @@ -494,7 +496,8 @@ static umf_result_t file_get_recommended_page_size(void *provider, size_t size, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - *page_size = utils_get_page_size(); + file_memory_provider_t *file_provider = (file_memory_provider_t *)provider; + *page_size = file_provider->page_size; return UMF_RESULT_SUCCESS; } From c01f25b10103fc86f9ec9109fe4980bf048f72cd Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Thu, 7 Nov 2024 14:50:07 +0100 Subject: [PATCH 288/352] Enable IPC API for FSDAX FSDAX requires 2 MB page size. Signed-off-by: Lukasz Dorau --- src/provider/provider_file_memory.c | 32 ++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/provider/provider_file_memory.c b/src/provider/provider_file_memory.c index baeb06733..99c9744e5 100644 --- a/src/provider/provider_file_memory.c +++ b/src/provider/provider_file_memory.c @@ -686,6 +686,17 @@ static umf_result_t file_open_ipc_handle(void *provider, void *providerIpcData, umf_result_t ret = UMF_RESULT_SUCCESS; int fd; + size_t offset_aligned = file_ipc_data->offset_fd; + size_t size_aligned = file_ipc_data->size; + + if (file_provider->is_fsdax) { + // It is just a workaround for case when + // file_alloc() was called with the size argument + // that is not a multiplier of FSDAX_PAGE_SIZE_2MB. + utils_align_ptr_down_size_up((void **)&offset_aligned, &size_aligned, + FSDAX_PAGE_SIZE_2MB); + } + fd = utils_file_open(file_ipc_data->path); if (fd == -1) { LOG_PERR("opening the file to be mapped (%s) failed", @@ -693,23 +704,23 @@ static umf_result_t file_open_ipc_handle(void *provider, void *providerIpcData, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - char *addr = utils_mmap_file( - NULL, file_ipc_data->size, file_ipc_data->protection, - file_ipc_data->visibility, fd, file_ipc_data->offset_fd, NULL); + char *addr = + utils_mmap_file(NULL, size_aligned, file_ipc_data->protection, + file_ipc_data->visibility, fd, offset_aligned, NULL); (void)utils_close_fd(fd); if (addr == NULL) { file_store_last_native_error(UMF_FILE_RESULT_ERROR_ALLOC_FAILED, errno); LOG_PERR("file mapping failed (path: %s, size: %zu, protection: %i, " "fd: %i, offset: %zu)", - file_ipc_data->path, file_ipc_data->size, - file_ipc_data->protection, fd, file_ipc_data->offset_fd); + file_ipc_data->path, size_aligned, file_ipc_data->protection, + fd, offset_aligned); return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; } LOG_DEBUG("file mapped (path: %s, size: %zu, protection: %i, fd: %i, " "offset: %zu) at address %p", - file_ipc_data->path, file_ipc_data->size, - file_ipc_data->protection, fd, file_ipc_data->offset_fd, addr); + file_ipc_data->path, size_aligned, file_ipc_data->protection, fd, + offset_aligned, addr); *ptr = addr; @@ -728,6 +739,13 @@ static umf_result_t file_close_ipc_handle(void *provider, void *ptr, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } + if (file_provider->is_fsdax) { + // It is just a workaround for case when + // file_alloc() was called with the size argument + // that is not a multiplier of FSDAX_PAGE_SIZE_2MB. + utils_align_ptr_down_size_up(&ptr, &size, FSDAX_PAGE_SIZE_2MB); + } + errno = 0; int ret = utils_munmap(ptr, size); // ignore error when size == 0 From f97b6b19ecd44a9e5d72e26dd4e5470a80b57f0d Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Thu, 7 Nov 2024 14:59:42 +0100 Subject: [PATCH 289/352] Print out also visibility in file_open_ipc_handle() Signed-off-by: Lukasz Dorau --- src/provider/provider_file_memory.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/provider/provider_file_memory.c b/src/provider/provider_file_memory.c index 99c9744e5..cdc84d080 100644 --- a/src/provider/provider_file_memory.c +++ b/src/provider/provider_file_memory.c @@ -710,17 +710,17 @@ static umf_result_t file_open_ipc_handle(void *provider, void *providerIpcData, (void)utils_close_fd(fd); if (addr == NULL) { file_store_last_native_error(UMF_FILE_RESULT_ERROR_ALLOC_FAILED, errno); - LOG_PERR("file mapping failed (path: %s, size: %zu, protection: %i, " - "fd: %i, offset: %zu)", + LOG_PERR("file mapping failed (path: %s, size: %zu, protection: %u, " + "visibility: %u, fd: %i, offset: %zu)", file_ipc_data->path, size_aligned, file_ipc_data->protection, - fd, offset_aligned); + file_ipc_data->visibility, fd, offset_aligned); return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; } - LOG_DEBUG("file mapped (path: %s, size: %zu, protection: %i, fd: %i, " - "offset: %zu) at address %p", - file_ipc_data->path, size_aligned, file_ipc_data->protection, fd, - offset_aligned, addr); + LOG_DEBUG("file mapped (path: %s, size: %zu, protection: %u, visibility: " + "%u, fd: %i, offset: %zu) at address %p", + file_ipc_data->path, size_aligned, file_ipc_data->protection, + file_ipc_data->visibility, fd, offset_aligned, addr); *ptr = addr; From 55534c58a986a29c237da3232f20eb84e0514c76 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 13 Nov 2024 12:42:13 +0100 Subject: [PATCH 290/352] Fix warnings about format specifies type Fix warnings about format specifies type: warning: format specifies type 'void *' but the argument \ has type 'char *' [-Wformat-pedantic] Signed-off-by: Lukasz Dorau --- src/provider/provider_devdax_memory.c | 2 +- src/provider/provider_file_memory.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/provider/provider_devdax_memory.c b/src/provider/provider_devdax_memory.c index c7f644db3..9602f5354 100644 --- a/src/provider/provider_devdax_memory.c +++ b/src/provider/provider_devdax_memory.c @@ -493,7 +493,7 @@ static umf_result_t devdax_open_ipc_handle(void *provider, LOG_DEBUG("devdax mapped (path: %s, size: %zu, protection: %i, fd: %i, " "offset: %zu) to address %p", devdax_ipc_data->path, length_aligned, - devdax_ipc_data->protection, fd, offset_aligned, addr); + devdax_ipc_data->protection, fd, offset_aligned, (void *)addr); *ptr = addr; diff --git a/src/provider/provider_file_memory.c b/src/provider/provider_file_memory.c index cdc84d080..7ecf979ba 100644 --- a/src/provider/provider_file_memory.c +++ b/src/provider/provider_file_memory.c @@ -720,7 +720,7 @@ static umf_result_t file_open_ipc_handle(void *provider, void *providerIpcData, LOG_DEBUG("file mapped (path: %s, size: %zu, protection: %u, visibility: " "%u, fd: %i, offset: %zu) at address %p", file_ipc_data->path, size_aligned, file_ipc_data->protection, - file_ipc_data->visibility, fd, offset_aligned, addr); + file_ipc_data->visibility, fd, offset_aligned, (void *)addr); *ptr = addr; From ff40db8cdf81645446420121c57583126b06d4a8 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 13 Nov 2024 18:30:07 +0100 Subject: [PATCH 291/352] Add IPC tests for FSDAX Signed-off-by: Lukasz Dorau --- test/provider_file_memory_ipc.cpp | 39 +++++++++++++++++++ test/supp/helgrind-umf_test-ipc.supp | 16 ++++++++ ...ind-umf_test-provider_file_memory_ipc.supp | 17 ++++++++ 3 files changed, 72 insertions(+) create mode 100644 test/supp/helgrind-umf_test-ipc.supp diff --git a/test/provider_file_memory_ipc.cpp b/test/provider_file_memory_ipc.cpp index 619c13b05..5bba5de50 100644 --- a/test/provider_file_memory_ipc.cpp +++ b/test/provider_file_memory_ipc.cpp @@ -27,6 +27,16 @@ umf_file_memory_provider_params_t get_file_params_shared(char *path) { umf_file_memory_provider_params_t file_params_shared = get_file_params_shared(FILE_PATH); +umf_file_memory_provider_params_t get_file_params_fsdax(char *path) { + umf_file_memory_provider_params_t file_params = + umfFileMemoryProviderParamsDefault(path); + file_params.visibility = UMF_MEM_MAP_SHARED; + return file_params; +} + +umf_file_memory_provider_params_t file_params_fsdax = + get_file_params_fsdax(getenv("UMF_TESTS_FSDAX_PATH")); + HostMemoryAccessor hostAccessor; static std::vector ipcManyPoolsTestParamsList = { @@ -43,7 +53,36 @@ static std::vector ipcManyPoolsTestParamsList = { #endif }; +static std::vector getIpcFsDaxTestParamsList(void) { + std::vector ipcFsDaxTestParamsList = {}; + + char *path = getenv("UMF_TESTS_FSDAX_PATH"); + if (path == nullptr || path[0] == 0) { + // skipping the test, UMF_TESTS_FSDAX_PATH is not set + return ipcFsDaxTestParamsList; + } + + ipcFsDaxTestParamsList = { +// TODO: enable it when sizes of allocations in ipcFixtures.hpp are fixed +// {umfProxyPoolOps(), nullptr, umfFileMemoryProviderOps(), +// &file_params_fsdax, &hostAccessor, true}, +#ifdef UMF_POOL_JEMALLOC_ENABLED + {umfJemallocPoolOps(), nullptr, umfFileMemoryProviderOps(), + &file_params_fsdax, &hostAccessor, false}, +#endif +#ifdef UMF_POOL_SCALABLE_ENABLED + {umfScalablePoolOps(), nullptr, umfFileMemoryProviderOps(), + &file_params_fsdax, &hostAccessor, false}, +#endif + }; + + return ipcFsDaxTestParamsList; +} + GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(umfIpcTest); INSTANTIATE_TEST_SUITE_P(FileProviderDifferentPoolsTest, umfIpcTest, ::testing::ValuesIn(ipcManyPoolsTestParamsList)); + +INSTANTIATE_TEST_SUITE_P(FileProviderDifferentPoolsFSDAXTest, umfIpcTest, + ::testing::ValuesIn(getIpcFsDaxTestParamsList())); diff --git a/test/supp/helgrind-umf_test-ipc.supp b/test/supp/helgrind-umf_test-ipc.supp new file mode 100644 index 000000000..e46140c19 --- /dev/null +++ b/test/supp/helgrind-umf_test-ipc.supp @@ -0,0 +1,16 @@ +{ + False-positive race in critnib_insert (lack of instrumentation) + Helgrind:Race + fun:store + fun:critnib_insert + ... +} + +{ + False-positive race in critnib_find (lack of instrumentation) + Helgrind:Race + fun:find_predecessor + fun:find_le + fun:critnib_find + ... +} diff --git a/test/supp/helgrind-umf_test-provider_file_memory_ipc.supp b/test/supp/helgrind-umf_test-provider_file_memory_ipc.supp index 4fcd2786c..4194f4847 100644 --- a/test/supp/helgrind-umf_test-provider_file_memory_ipc.supp +++ b/test/supp/helgrind-umf_test-provider_file_memory_ipc.supp @@ -6,3 +6,20 @@ fun:umfOpenIPCHandle ... } + +{ + False-positive race in critnib_insert (lack of instrumentation) + Helgrind:Race + fun:store + fun:critnib_insert + ... +} + +{ + False-positive race in critnib_find (lack of instrumentation) + Helgrind:Race + fun:find_predecessor + fun:find_le + fun:critnib_find + ... +} From 56a7c1deff4221aa6b5f013785623a6ef8c88b59 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Thu, 14 Nov 2024 11:18:50 +0100 Subject: [PATCH 292/352] Add missing checks to memory_provider.c Add missing checks to memory_provider.c. Unify checks of parameters. Signed-off-by: Lukasz Dorau --- src/memory_provider.c | 50 ++++++++++++++++++++++---------------- test/memoryProviderAPI.cpp | 23 ++++++++++-------- 2 files changed, 42 insertions(+), 31 deletions(-) diff --git a/src/memory_provider.c b/src/memory_provider.c index 3d823a4a8..883f1be26 100644 --- a/src/memory_provider.c +++ b/src/memory_provider.c @@ -226,6 +226,7 @@ checkErrorAndSetLastProvider(umf_result_t result, umf_result_t umfMemoryProviderAlloc(umf_memory_provider_handle_t hProvider, size_t size, size_t alignment, void **ptr) { UMF_CHECK((hProvider != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); + UMF_CHECK((ptr != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); umf_result_t res = hProvider->ops.alloc(hProvider->provider_priv, size, alignment, ptr); checkErrorAndSetLastProvider(res, hProvider); @@ -258,6 +259,7 @@ umf_result_t umfMemoryProviderGetRecommendedPageSize(umf_memory_provider_handle_t hProvider, size_t size, size_t *pageSize) { UMF_CHECK((hProvider != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); + UMF_CHECK((pageSize != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); umf_result_t res = hProvider->ops.get_recommended_page_size( hProvider->provider_priv, size, pageSize); checkErrorAndSetLastProvider(res, hProvider); @@ -268,6 +270,7 @@ umf_result_t umfMemoryProviderGetMinPageSize(umf_memory_provider_handle_t hProvider, void *ptr, size_t *pageSize) { UMF_CHECK((hProvider != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); + UMF_CHECK((pageSize != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); umf_result_t res = hProvider->ops.get_min_page_size( hProvider->provider_priv, ptr, pageSize); checkErrorAndSetLastProvider(res, hProvider); @@ -282,6 +285,7 @@ const char *umfMemoryProviderGetName(umf_memory_provider_handle_t hProvider) { umf_result_t umfMemoryProviderPurgeLazy(umf_memory_provider_handle_t hProvider, void *ptr, size_t size) { UMF_CHECK((hProvider != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); + UMF_CHECK((ptr != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); umf_result_t res = hProvider->ops.ext.purge_lazy(hProvider->provider_priv, ptr, size); checkErrorAndSetLastProvider(res, hProvider); @@ -291,6 +295,7 @@ umf_result_t umfMemoryProviderPurgeLazy(umf_memory_provider_handle_t hProvider, umf_result_t umfMemoryProviderPurgeForce(umf_memory_provider_handle_t hProvider, void *ptr, size_t size) { UMF_CHECK((hProvider != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); + UMF_CHECK((ptr != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); umf_result_t res = hProvider->ops.ext.purge_force(hProvider->provider_priv, ptr, size); checkErrorAndSetLastProvider(res, hProvider); @@ -305,15 +310,11 @@ umf_result_t umfMemoryProviderAllocationSplit(umf_memory_provider_handle_t hProvider, void *ptr, size_t totalSize, size_t firstSize) { - if (!ptr) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - if (firstSize == 0 || totalSize == 0) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - if (firstSize >= totalSize) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } + UMF_CHECK((hProvider != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); + UMF_CHECK((ptr != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); + UMF_CHECK((firstSize != 0 && totalSize != 0), + UMF_RESULT_ERROR_INVALID_ARGUMENT); + UMF_CHECK((firstSize < totalSize), UMF_RESULT_ERROR_INVALID_ARGUMENT); umf_result_t res = hProvider->ops.ext.allocation_split( hProvider->provider_priv, ptr, totalSize, firstSize); @@ -325,18 +326,13 @@ umf_result_t umfMemoryProviderAllocationMerge(umf_memory_provider_handle_t hProvider, void *lowPtr, void *highPtr, size_t totalSize) { - if (!lowPtr || !highPtr) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - if (totalSize == 0) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - if ((uintptr_t)lowPtr >= (uintptr_t)highPtr) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - if ((uintptr_t)highPtr - (uintptr_t)lowPtr > totalSize) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } + UMF_CHECK((hProvider != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); + UMF_CHECK((lowPtr && highPtr), UMF_RESULT_ERROR_INVALID_ARGUMENT); + UMF_CHECK((totalSize != 0), UMF_RESULT_ERROR_INVALID_ARGUMENT); + UMF_CHECK(((uintptr_t)lowPtr < (uintptr_t)highPtr), + UMF_RESULT_ERROR_INVALID_ARGUMENT); + UMF_CHECK(((uintptr_t)highPtr - (uintptr_t)lowPtr < totalSize), + UMF_RESULT_ERROR_INVALID_ARGUMENT); umf_result_t res = hProvider->ops.ext.allocation_merge( hProvider->provider_priv, lowPtr, highPtr, totalSize); @@ -347,6 +343,8 @@ umfMemoryProviderAllocationMerge(umf_memory_provider_handle_t hProvider, umf_result_t umfMemoryProviderGetIPCHandleSize(umf_memory_provider_handle_t hProvider, size_t *size) { + UMF_CHECK((hProvider != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); + UMF_CHECK((size != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); return hProvider->ops.ipc.get_ipc_handle_size(hProvider->provider_priv, size); } @@ -355,6 +353,9 @@ umf_result_t umfMemoryProviderGetIPCHandle(umf_memory_provider_handle_t hProvider, const void *ptr, size_t size, void *providerIpcData) { + UMF_CHECK((hProvider != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); + UMF_CHECK((ptr != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); + UMF_CHECK((providerIpcData != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); return hProvider->ops.ipc.get_ipc_handle(hProvider->provider_priv, ptr, size, providerIpcData); } @@ -362,6 +363,8 @@ umfMemoryProviderGetIPCHandle(umf_memory_provider_handle_t hProvider, umf_result_t umfMemoryProviderPutIPCHandle(umf_memory_provider_handle_t hProvider, void *providerIpcData) { + UMF_CHECK((hProvider != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); + UMF_CHECK((providerIpcData != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); return hProvider->ops.ipc.put_ipc_handle(hProvider->provider_priv, providerIpcData); } @@ -369,6 +372,9 @@ umfMemoryProviderPutIPCHandle(umf_memory_provider_handle_t hProvider, umf_result_t umfMemoryProviderOpenIPCHandle(umf_memory_provider_handle_t hProvider, void *providerIpcData, void **ptr) { + UMF_CHECK((hProvider != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); + UMF_CHECK((providerIpcData != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); + UMF_CHECK((ptr != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); return hProvider->ops.ipc.open_ipc_handle(hProvider->provider_priv, providerIpcData, ptr); } @@ -376,6 +382,8 @@ umfMemoryProviderOpenIPCHandle(umf_memory_provider_handle_t hProvider, umf_result_t umfMemoryProviderCloseIPCHandle(umf_memory_provider_handle_t hProvider, void *ptr, size_t size) { + UMF_CHECK((hProvider != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); + UMF_CHECK((ptr != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); return hProvider->ops.ipc.close_ipc_handle(hProvider->provider_priv, ptr, size); } diff --git a/test/memoryProviderAPI.cpp b/test/memoryProviderAPI.cpp index 5208f8157..866ae6dae 100644 --- a/test/memoryProviderAPI.cpp +++ b/test/memoryProviderAPI.cpp @@ -43,14 +43,15 @@ TEST_F(test, memoryProviderTrace) { ASSERT_EQ(calls["get_last_native_error"], 1); ASSERT_EQ(calls.size(), ++call_count); + size_t page_size; ret = umfMemoryProviderGetRecommendedPageSize(tracingProvider.get(), 0, - nullptr); + &page_size); ASSERT_EQ(ret, UMF_RESULT_SUCCESS); ASSERT_EQ(calls["get_recommended_page_size"], 1); ASSERT_EQ(calls.size(), ++call_count); ret = umfMemoryProviderGetMinPageSize(tracingProvider.get(), nullptr, - nullptr); + &page_size); ASSERT_EQ(ret, UMF_RESULT_SUCCESS); ASSERT_EQ(calls["get_min_page_size"], 1); ASSERT_EQ(calls.size(), ++call_count); @@ -60,12 +61,14 @@ TEST_F(test, memoryProviderTrace) { ASSERT_EQ(calls.size(), ++call_count); ASSERT_EQ(std::string(pName), std::string("null")); - ret = umfMemoryProviderPurgeLazy(tracingProvider.get(), nullptr, 0); + ret = umfMemoryProviderPurgeLazy(tracingProvider.get(), &page_size, + sizeof(page_size)); ASSERT_EQ(ret, UMF_RESULT_SUCCESS); ASSERT_EQ(calls["purge_lazy"], 1); ASSERT_EQ(calls.size(), ++call_count); - ret = umfMemoryProviderPurgeForce(tracingProvider.get(), nullptr, 0); + ret = umfMemoryProviderPurgeForce(tracingProvider.get(), &page_size, + sizeof(page_size)); ASSERT_EQ(ret, UMF_RESULT_SUCCESS); ASSERT_EQ(calls["purge_force"], 1); ASSERT_EQ(calls.size(), ++call_count); @@ -107,7 +110,7 @@ TEST_F(test, memoryProviderOpsNullPurgeLazyField) { ASSERT_EQ(ret, UMF_RESULT_SUCCESS); ret = umfMemoryProviderPurgeLazy(hProvider, nullptr, 0); - ASSERT_EQ(ret, UMF_RESULT_ERROR_NOT_SUPPORTED); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); umfMemoryProviderDestroy(hProvider); } @@ -120,7 +123,7 @@ TEST_F(test, memoryProviderOpsNullPurgeForceField) { ASSERT_EQ(ret, UMF_RESULT_SUCCESS); ret = umfMemoryProviderPurgeForce(hProvider, nullptr, 0); - ASSERT_EQ(ret, UMF_RESULT_ERROR_NOT_SUPPORTED); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); umfMemoryProviderDestroy(hProvider); } @@ -165,16 +168,16 @@ TEST_F(test, memoryProviderOpsNullAllIPCFields) { void *ptr = nullptr; void *providerIpcData = nullptr; ret = umfMemoryProviderGetIPCHandle(hProvider, ptr, size, providerIpcData); - ASSERT_EQ(ret, UMF_RESULT_ERROR_NOT_SUPPORTED); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); ret = umfMemoryProviderPutIPCHandle(hProvider, providerIpcData); - ASSERT_EQ(ret, UMF_RESULT_ERROR_NOT_SUPPORTED); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); ret = umfMemoryProviderOpenIPCHandle(hProvider, providerIpcData, &ptr); - ASSERT_EQ(ret, UMF_RESULT_ERROR_NOT_SUPPORTED); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); ret = umfMemoryProviderCloseIPCHandle(hProvider, ptr, size); - ASSERT_EQ(ret, UMF_RESULT_ERROR_NOT_SUPPORTED); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); umfMemoryProviderDestroy(hProvider); } From ac2389bf63f228126ccffd014f455b3dacb80010 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Thu, 14 Nov 2024 11:21:10 +0100 Subject: [PATCH 293/352] Remove dead code Remove dead code - remove checks run always earlier in src/memory_provider.c. Signed-off-by: Lukasz Dorau --- .../custom_file_provider.c | 18 +------ src/provider/provider_coarse.c | 19 ------- src/provider/provider_cuda.c | 47 ++-------------- src/provider/provider_devdax_memory.c | 53 +++---------------- src/provider/provider_file_memory.c | 42 ++------------- src/provider/provider_level_zero.c | 45 ++-------------- src/provider/provider_os_memory.c | 50 ++--------------- 7 files changed, 28 insertions(+), 246 deletions(-) diff --git a/examples/custom_file_provider/custom_file_provider.c b/examples/custom_file_provider/custom_file_provider.c index b0f1bc062..ffa61d63f 100644 --- a/examples/custom_file_provider/custom_file_provider.c +++ b/examples/custom_file_provider/custom_file_provider.c @@ -113,10 +113,6 @@ static void file_deinit(void *provider) { // Function to allocate memory from the file provider static umf_result_t file_alloc(void *provider, size_t size, size_t alignment, void **ptr) { - if (provider == NULL || ptr == NULL) { - fprintf(stderr, "Provider or ptr cannot be null\n"); - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } file_provider_t *file_provider = (file_provider_t *)provider; size_t page_size = file_provider->page_size; @@ -165,8 +161,8 @@ static umf_result_t file_alloc(void *provider, size_t size, size_t alignment, // Function to free allocated memory from the file provider static umf_result_t file_free(void *provider, void *ptr, size_t size) { - if (provider == NULL || ptr == NULL) { - fprintf(stderr, "Provider or ptr cannot be null\n"); + if (ptr == NULL) { + fprintf(stderr, "ptr cannot be null\n"); return UMF_RESULT_ERROR_INVALID_ARGUMENT; } file_provider_t *file_provider = (file_provider_t *)provider; @@ -221,11 +217,6 @@ static void file_get_last_native_error(void *provider, const char **ppMessage, static umf_result_t file_get_recommended_page_size(void *provider, size_t size, size_t *pageSize) { (void)size; // Unused parameter - if (provider == NULL || pageSize == NULL) { - fprintf(stderr, "Provider or pageSize cannot be null\n"); - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - file_provider_t *file_provider = (file_provider_t *)provider; *pageSize = file_provider->page_size; return UMF_RESULT_SUCCESS; @@ -235,11 +226,6 @@ static umf_result_t file_get_recommended_page_size(void *provider, size_t size, static umf_result_t file_get_min_page_size(void *provider, void *ptr, size_t *pageSize) { (void)ptr; // Unused parameter - if (provider == NULL || pageSize == NULL) { - fprintf(stderr, "Provider or pageSize cannot be null\n"); - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - file_provider_t *file_provider = (file_provider_t *)provider; *pageSize = file_provider->page_size; return UMF_RESULT_SUCCESS; diff --git a/src/provider/provider_coarse.c b/src/provider/provider_coarse.c index ed7bb1cba..c3027b91d 100644 --- a/src/provider/provider_coarse.c +++ b/src/provider/provider_coarse.c @@ -1478,10 +1478,6 @@ coarse_memory_provider_get_stats(void *provider, static umf_result_t coarse_memory_provider_purge_lazy(void *provider, void *ptr, size_t size) { - if (provider == NULL || ptr == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - coarse_memory_provider_t *coarse_provider = (struct coarse_memory_provider_t *)provider; if (coarse_provider->upstream_memory_provider == NULL) { @@ -1495,10 +1491,6 @@ static umf_result_t coarse_memory_provider_purge_lazy(void *provider, void *ptr, static umf_result_t coarse_memory_provider_purge_force(void *provider, void *ptr, size_t size) { - if (provider == NULL || ptr == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - coarse_memory_provider_t *coarse_provider = (struct coarse_memory_provider_t *)provider; if (coarse_provider->upstream_memory_provider == NULL) { @@ -1514,11 +1506,6 @@ static umf_result_t coarse_memory_provider_allocation_split(void *provider, void *ptr, size_t totalSize, size_t firstSize) { - if (provider == NULL || ptr == NULL || (firstSize >= totalSize) || - firstSize == 0) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - umf_result_t umf_result; coarse_memory_provider_t *coarse_provider = @@ -1578,12 +1565,6 @@ static umf_result_t coarse_memory_provider_allocation_merge(void *provider, void *lowPtr, void *highPtr, size_t totalSize) { - if (provider == NULL || lowPtr == NULL || highPtr == NULL || - ((uintptr_t)highPtr <= (uintptr_t)lowPtr) || - ((uintptr_t)highPtr - (uintptr_t)lowPtr >= totalSize)) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - umf_result_t umf_result; coarse_memory_provider_t *coarse_provider = diff --git a/src/provider/provider_cuda.c b/src/provider/provider_cuda.c index a1f9df034..db0016c44 100644 --- a/src/provider/provider_cuda.c +++ b/src/provider/provider_cuda.c @@ -160,7 +160,7 @@ static void init_cu_global_state(void) { static umf_result_t cu_memory_provider_initialize(void *params, void **provider) { - if (provider == NULL || params == NULL) { + if (params == NULL) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; } @@ -214,11 +214,6 @@ static umf_result_t cu_memory_provider_initialize(void *params, } static void cu_memory_provider_finalize(void *provider) { - if (provider == NULL) { - ASSERT(0); - return; - } - umf_ba_global_free(provider); } @@ -250,10 +245,6 @@ static inline umf_result_t set_context(CUcontext required_ctx, static umf_result_t cu_memory_provider_alloc(void *provider, size_t size, size_t alignment, void **resultPtr) { - if (provider == NULL || resultPtr == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - cu_memory_provider_t *cu_provider = (cu_memory_provider_t *)provider; if (alignment > cu_provider->min_alignment) { @@ -318,10 +309,6 @@ static umf_result_t cu_memory_provider_free(void *provider, void *ptr, size_t bytes) { (void)bytes; - if (provider == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - if (ptr == NULL) { return UMF_RESULT_SUCCESS; } @@ -385,10 +372,6 @@ static umf_result_t cu_memory_provider_get_min_page_size(void *provider, size_t *pageSize) { (void)ptr; - if (provider == NULL || pageSize == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - cu_memory_provider_t *cu_provider = (cu_memory_provider_t *)provider; CUmemAllocationProp allocProps = {0}; @@ -407,10 +390,6 @@ cu_memory_provider_get_recommended_page_size(void *provider, size_t size, size_t *pageSize) { (void)size; - if (provider == NULL || pageSize == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - cu_memory_provider_t *cu_provider = (cu_memory_provider_t *)provider; CUmemAllocationProp allocProps = {0}; @@ -431,10 +410,7 @@ static const char *cu_memory_provider_get_name(void *provider) { static umf_result_t cu_memory_provider_get_ipc_handle_size(void *provider, size_t *size) { - if (provider == NULL || size == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - + (void)provider; *size = sizeof(cu_ipc_data_t); return UMF_RESULT_SUCCESS; } @@ -443,12 +419,9 @@ static umf_result_t cu_memory_provider_get_ipc_handle(void *provider, const void *ptr, size_t size, void *providerIpcData) { + (void)provider; (void)size; - if (provider == NULL || ptr == NULL || providerIpcData == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - CUresult cu_result; cu_ipc_data_t *cu_ipc_data = (cu_ipc_data_t *)providerIpcData; @@ -463,20 +436,14 @@ static umf_result_t cu_memory_provider_get_ipc_handle(void *provider, static umf_result_t cu_memory_provider_put_ipc_handle(void *provider, void *providerIpcData) { - if (provider == NULL || providerIpcData == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - + (void)provider; + (void)providerIpcData; return UMF_RESULT_SUCCESS; } static umf_result_t cu_memory_provider_open_ipc_handle(void *provider, void *providerIpcData, void **ptr) { - if (provider == NULL || ptr == NULL || providerIpcData == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - cu_memory_provider_t *cu_provider = (cu_memory_provider_t *)provider; CUresult cu_result; @@ -505,10 +472,6 @@ static umf_result_t cu_memory_provider_close_ipc_handle(void *provider, void *ptr, size_t size) { (void)size; - if (provider == NULL || ptr == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - CUresult cu_result; cu_result = g_cu_ops.cuIpcCloseMemHandle((CUdeviceptr)ptr); diff --git a/src/provider/provider_devdax_memory.c b/src/provider/provider_devdax_memory.c index c7f644db3..f4996fa0d 100644 --- a/src/provider/provider_devdax_memory.c +++ b/src/provider/provider_devdax_memory.c @@ -97,7 +97,7 @@ devdax_translate_params(umf_devdax_memory_provider_params_t *in_params, static umf_result_t devdax_initialize(void *params, void **provider) { umf_result_t ret; - if (provider == NULL || params == NULL) { + if (params == NULL) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; } @@ -185,11 +185,6 @@ static umf_result_t devdax_initialize(void *params, void **provider) { } static void devdax_finalize(void *provider) { - if (provider == NULL) { - assert(0); - return; - } - devdax_memory_provider_t *devdax_provider = provider; utils_mutex_destroy_not_free(&devdax_provider->lock); utils_munmap(devdax_provider->base, devdax_provider->size); @@ -234,10 +229,6 @@ static umf_result_t devdax_alloc(void *provider, size_t size, size_t alignment, void **resultPtr) { int ret; - if (provider == NULL || resultPtr == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - // alignment must be a power of two and a multiple or a divider of the page size if (alignment && ((alignment & (alignment - 1)) || ((alignment % DEVDAX_PAGE_SIZE_2MB) && @@ -309,11 +300,8 @@ static void devdax_get_last_native_error(void *provider, const char **ppMessage, static umf_result_t devdax_get_recommended_page_size(void *provider, size_t size, size_t *page_size) { - (void)size; // unused - - if (provider == NULL || page_size == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } + (void)provider; // unused + (void)size; // unused *page_size = DEVDAX_PAGE_SIZE_2MB; @@ -338,10 +326,6 @@ static umf_result_t devdax_purge_lazy(void *provider, void *ptr, size_t size) { } static umf_result_t devdax_purge_force(void *provider, void *ptr, size_t size) { - if (provider == NULL || ptr == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - errno = 0; if (utils_purge(ptr, size, UMF_PURGE_FORCE)) { devdax_store_last_native_error( @@ -364,18 +348,15 @@ static umf_result_t devdax_allocation_split(void *provider, void *ptr, (void)ptr; (void)totalSize; (void)firstSize; - return UMF_RESULT_SUCCESS; } static umf_result_t devdax_allocation_merge(void *provider, void *lowPtr, void *highPtr, size_t totalSize) { - if (provider == NULL || lowPtr == NULL || highPtr == NULL || - ((uintptr_t)highPtr <= (uintptr_t)lowPtr) || - ((uintptr_t)highPtr - (uintptr_t)lowPtr >= totalSize)) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - + (void)provider; + (void)lowPtr; + (void)highPtr; + (void)totalSize; return UMF_RESULT_SUCCESS; } @@ -388,9 +369,7 @@ typedef struct devdax_ipc_data_t { } devdax_ipc_data_t; static umf_result_t devdax_get_ipc_handle_size(void *provider, size_t *size) { - if (provider == NULL || size == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } + (void)provider; *size = sizeof(devdax_ipc_data_t); @@ -399,10 +378,6 @@ static umf_result_t devdax_get_ipc_handle_size(void *provider, size_t *size) { static umf_result_t devdax_get_ipc_handle(void *provider, const void *ptr, size_t size, void *providerIpcData) { - if (provider == NULL || ptr == NULL || providerIpcData == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - devdax_memory_provider_t *devdax_provider = (devdax_memory_provider_t *)provider; @@ -419,10 +394,6 @@ static umf_result_t devdax_get_ipc_handle(void *provider, const void *ptr, static umf_result_t devdax_put_ipc_handle(void *provider, void *providerIpcData) { - if (provider == NULL || providerIpcData == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - devdax_memory_provider_t *devdax_provider = (devdax_memory_provider_t *)provider; devdax_ipc_data_t *devdax_ipc_data = (devdax_ipc_data_t *)providerIpcData; @@ -439,10 +410,6 @@ static umf_result_t devdax_put_ipc_handle(void *provider, static umf_result_t devdax_open_ipc_handle(void *provider, void *providerIpcData, void **ptr) { - if (provider == NULL || providerIpcData == NULL || ptr == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - *ptr = NULL; devdax_ipc_data_t *devdax_ipc_data = (devdax_ipc_data_t *)providerIpcData; @@ -502,10 +469,6 @@ static umf_result_t devdax_open_ipc_handle(void *provider, static umf_result_t devdax_close_ipc_handle(void *provider, void *ptr, size_t size) { - if (provider == NULL || ptr == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - size = ALIGN_UP(size, DEVDAX_PAGE_SIZE_2MB); errno = 0; diff --git a/src/provider/provider_file_memory.c b/src/provider/provider_file_memory.c index ec3cd25cd..67f7dc924 100644 --- a/src/provider/provider_file_memory.c +++ b/src/provider/provider_file_memory.c @@ -123,7 +123,7 @@ file_translate_params(umf_file_memory_provider_params_t *in_params, static umf_result_t file_initialize(void *params, void **provider) { umf_result_t ret; - if (provider == NULL || params == NULL) { + if (params == NULL) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; } @@ -210,11 +210,6 @@ static umf_result_t file_initialize(void *params, void **provider) { } static void file_finalize(void *provider) { - if (provider == NULL) { - assert(0); - return; - } - file_memory_provider_t *file_provider = provider; uintptr_t key = 0; @@ -392,10 +387,6 @@ static umf_result_t file_alloc(void *provider, size_t size, size_t alignment, umf_result_t umf_result; int ret; - if (provider == NULL || resultPtr == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - file_memory_provider_t *file_provider = (file_memory_provider_t *)provider; // alignment must be a power of two and a multiple or a divider of the page size @@ -474,11 +465,8 @@ static void file_get_last_native_error(void *provider, const char **ppMessage, static umf_result_t file_get_recommended_page_size(void *provider, size_t size, size_t *page_size) { - (void)size; // unused - - if (provider == NULL || page_size == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } + (void)provider; // unused + (void)size; // unused *page_size = utils_get_page_size(); @@ -503,9 +491,7 @@ static umf_result_t file_purge_lazy(void *provider, void *ptr, size_t size) { } static umf_result_t file_purge_force(void *provider, void *ptr, size_t size) { - if (provider == NULL || ptr == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } + (void)provider; // unused errno = 0; if (utils_purge(ptr, size, UMF_PURGE_FORCE)) { @@ -587,10 +573,6 @@ typedef struct file_ipc_data_t { } file_ipc_data_t; static umf_result_t file_get_ipc_handle_size(void *provider, size_t *size) { - if (provider == NULL || size == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - file_memory_provider_t *file_provider = (file_memory_provider_t *)provider; if (!file_provider->IPC_enabled) { LOG_ERR("memory visibility mode is not UMF_MEM_MAP_SHARED") @@ -604,10 +586,6 @@ static umf_result_t file_get_ipc_handle_size(void *provider, size_t *size) { static umf_result_t file_get_ipc_handle(void *provider, const void *ptr, size_t size, void *providerIpcData) { - if (provider == NULL || ptr == NULL || providerIpcData == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - file_memory_provider_t *file_provider = (file_memory_provider_t *)provider; if (!file_provider->IPC_enabled) { LOG_ERR("memory visibility mode is not UMF_MEM_MAP_SHARED") @@ -634,10 +612,6 @@ static umf_result_t file_get_ipc_handle(void *provider, const void *ptr, } static umf_result_t file_put_ipc_handle(void *provider, void *providerIpcData) { - if (provider == NULL || providerIpcData == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - file_memory_provider_t *file_provider = (file_memory_provider_t *)provider; if (!file_provider->IPC_enabled) { LOG_ERR("memory visibility mode is not UMF_MEM_MAP_SHARED") @@ -655,10 +629,6 @@ static umf_result_t file_put_ipc_handle(void *provider, void *providerIpcData) { static umf_result_t file_open_ipc_handle(void *provider, void *providerIpcData, void **ptr) { - if (provider == NULL || providerIpcData == NULL || ptr == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - file_memory_provider_t *file_provider = (file_memory_provider_t *)provider; if (!file_provider->IPC_enabled) { LOG_ERR("memory visibility mode is not UMF_MEM_MAP_SHARED") @@ -701,10 +671,6 @@ static umf_result_t file_open_ipc_handle(void *provider, void *providerIpcData, static umf_result_t file_close_ipc_handle(void *provider, void *ptr, size_t size) { - if (provider == NULL || ptr == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - file_memory_provider_t *file_provider = (file_memory_provider_t *)provider; if (!file_provider->IPC_enabled) { LOG_ERR("memory visibility mode is not UMF_MEM_MAP_SHARED") diff --git a/src/provider/provider_level_zero.c b/src/provider/provider_level_zero.c index 3f122cd6a..3339042ce 100644 --- a/src/provider/provider_level_zero.c +++ b/src/provider/provider_level_zero.c @@ -136,7 +136,7 @@ static void init_ze_global_state(void) { static umf_result_t ze_memory_provider_initialize(void *params, void **provider) { - if (provider == NULL || params == NULL) { + if (params == NULL) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; } @@ -211,11 +211,6 @@ static umf_result_t ze_memory_provider_initialize(void *params, } static void ze_memory_provider_finalize(void *provider) { - if (provider == NULL) { - ASSERT(0); - return; - } - ze_memory_provider_t *ze_provider = (ze_memory_provider_t *)provider; umf_ba_global_free(ze_provider->resident_device_handles); @@ -239,10 +234,6 @@ static ze_relaxed_allocation_limits_exp_desc_t relaxed_device_allocation_desc = static umf_result_t ze_memory_provider_alloc(void *provider, size_t size, size_t alignment, void **resultPtr) { - if (provider == NULL || resultPtr == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - ze_memory_provider_t *ze_provider = (ze_memory_provider_t *)provider; ze_result_t ze_result = ZE_RESULT_SUCCESS; @@ -315,10 +306,6 @@ static umf_result_t ze_memory_provider_free(void *provider, void *ptr, size_t bytes) { (void)bytes; - if (provider == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - if (ptr == NULL) { return UMF_RESULT_SUCCESS; } @@ -344,12 +331,9 @@ static void ze_memory_provider_get_last_native_error(void *provider, static umf_result_t ze_memory_provider_get_min_page_size(void *provider, void *ptr, size_t *pageSize) { + (void)provider; (void)ptr; - if (provider == NULL || pageSize == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - // TODO *pageSize = 1024 * 64; return UMF_RESULT_SUCCESS; @@ -378,12 +362,9 @@ static umf_result_t ze_memory_provider_purge_force(void *provider, void *ptr, static umf_result_t ze_memory_provider_get_recommended_page_size(void *provider, size_t size, size_t *pageSize) { + (void)provider; (void)size; - if (provider == NULL || pageSize == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - // TODO *pageSize = 1024 * 64; return UMF_RESULT_SUCCESS; @@ -427,9 +408,7 @@ typedef struct ze_ipc_data_t { static umf_result_t ze_memory_provider_get_ipc_handle_size(void *provider, size_t *size) { - if (provider == NULL || size == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } + (void)provider; *size = sizeof(ze_ipc_data_t); return UMF_RESULT_SUCCESS; @@ -441,10 +420,6 @@ static umf_result_t ze_memory_provider_get_ipc_handle(void *provider, void *providerIpcData) { (void)size; - if (provider == NULL || ptr == NULL || providerIpcData == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - ze_result_t ze_result; ze_ipc_data_t *ze_ipc_data = (ze_ipc_data_t *)providerIpcData; struct ze_memory_provider_t *ze_provider = @@ -464,10 +439,6 @@ static umf_result_t ze_memory_provider_get_ipc_handle(void *provider, static umf_result_t ze_memory_provider_put_ipc_handle(void *provider, void *providerIpcData) { - if (provider == NULL || providerIpcData == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - ze_result_t ze_result; struct ze_memory_provider_t *ze_provider = (struct ze_memory_provider_t *)provider; @@ -492,10 +463,6 @@ static umf_result_t ze_memory_provider_put_ipc_handle(void *provider, static umf_result_t ze_memory_provider_open_ipc_handle(void *provider, void *providerIpcData, void **ptr) { - if (provider == NULL || ptr == NULL || providerIpcData == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - ze_result_t ze_result; ze_ipc_data_t *ze_ipc_data = (ze_ipc_data_t *)providerIpcData; struct ze_memory_provider_t *ze_provider = @@ -532,10 +499,6 @@ static umf_result_t ze_memory_provider_close_ipc_handle(void *provider, void *ptr, size_t size) { (void)size; - if (provider == NULL || ptr == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - ze_result_t ze_result; struct ze_memory_provider_t *ze_provider = (struct ze_memory_provider_t *)provider; diff --git a/src/provider/provider_os_memory.c b/src/provider/provider_os_memory.c index 8c5a9dc46..3ea5cf220 100644 --- a/src/provider/provider_os_memory.c +++ b/src/provider/provider_os_memory.c @@ -478,7 +478,7 @@ static umf_result_t translate_params(umf_os_memory_provider_params_t *in_params, static umf_result_t os_initialize(void *params, void **provider) { umf_result_t ret; - if (provider == NULL || params == NULL) { + if (params == NULL) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; } @@ -572,11 +572,6 @@ static umf_result_t os_initialize(void *params, void **provider) { } static void os_finalize(void *provider) { - if (provider == NULL) { - assert(0); - return; - } - os_memory_provider_t *os_provider = provider; if (os_provider->fd > 0) { @@ -900,10 +895,6 @@ static umf_result_t os_alloc(void *provider, size_t size, size_t alignment, void **resultPtr) { int ret; - if (provider == NULL || resultPtr == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - os_memory_provider_t *os_provider = (os_memory_provider_t *)provider; size_t page_size; @@ -1004,10 +995,6 @@ static umf_result_t os_alloc(void *provider, size_t size, size_t alignment, } static umf_result_t os_free(void *provider, void *ptr, size_t size) { - if (provider == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - if (ptr == NULL) { return UMF_RESULT_SUCCESS; } @@ -1067,11 +1054,8 @@ static void os_get_last_native_error(void *provider, const char **ppMessage, static umf_result_t os_get_recommended_page_size(void *provider, size_t size, size_t *page_size) { - (void)size; // unused - - if (provider == NULL || page_size == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } + (void)provider; // unused + (void)size; // unused *page_size = utils_get_page_size(); @@ -1086,9 +1070,7 @@ static umf_result_t os_get_min_page_size(void *provider, void *ptr, } static umf_result_t os_purge_lazy(void *provider, void *ptr, size_t size) { - if (provider == NULL || ptr == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } + (void)provider; // unused errno = 0; if (utils_purge(ptr, size, UMF_PURGE_LAZY)) { @@ -1102,9 +1084,7 @@ static umf_result_t os_purge_lazy(void *provider, void *ptr, size_t size) { } static umf_result_t os_purge_force(void *provider, void *ptr, size_t size) { - if (provider == NULL || ptr == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } + (void)provider; // unused errno = 0; if (utils_purge(ptr, size, UMF_PURGE_FORCE)) { @@ -1191,10 +1171,6 @@ typedef struct os_ipc_data_t { } os_ipc_data_t; static umf_result_t os_get_ipc_handle_size(void *provider, size_t *size) { - if (provider == NULL || size == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - os_memory_provider_t *os_provider = (os_memory_provider_t *)provider; if (!os_provider->IPC_enabled) { LOG_ERR("memory visibility mode is not UMF_MEM_MAP_SHARED") @@ -1209,10 +1185,6 @@ static umf_result_t os_get_ipc_handle_size(void *provider, size_t *size) { static umf_result_t os_get_ipc_handle(void *provider, const void *ptr, size_t size, void *providerIpcData) { - if (provider == NULL || ptr == NULL || providerIpcData == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - os_memory_provider_t *os_provider = (os_memory_provider_t *)provider; if (!os_provider->IPC_enabled) { LOG_ERR("memory visibility mode is not UMF_MEM_MAP_SHARED") @@ -1245,10 +1217,6 @@ static umf_result_t os_get_ipc_handle(void *provider, const void *ptr, } static umf_result_t os_put_ipc_handle(void *provider, void *providerIpcData) { - if (provider == NULL || providerIpcData == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - os_memory_provider_t *os_provider = (os_memory_provider_t *)provider; if (!os_provider->IPC_enabled) { LOG_ERR("memory visibility mode is not UMF_MEM_MAP_SHARED") @@ -1280,10 +1248,6 @@ static umf_result_t os_put_ipc_handle(void *provider, void *providerIpcData) { static umf_result_t os_open_ipc_handle(void *provider, void *providerIpcData, void **ptr) { - if (provider == NULL || providerIpcData == NULL || ptr == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - os_memory_provider_t *os_provider = (os_memory_provider_t *)provider; if (!os_provider->IPC_enabled) { LOG_ERR("memory visibility mode is not UMF_MEM_MAP_SHARED") @@ -1326,10 +1290,6 @@ static umf_result_t os_open_ipc_handle(void *provider, void *providerIpcData, static umf_result_t os_close_ipc_handle(void *provider, void *ptr, size_t size) { - if (provider == NULL || ptr == NULL) { - return UMF_RESULT_ERROR_INVALID_ARGUMENT; - } - os_memory_provider_t *os_provider = (os_memory_provider_t *)provider; if (!os_provider->IPC_enabled) { LOG_ERR("memory visibility mode is not UMF_MEM_MAP_SHARED") From d39a1e506ba9913373a31ff25b335c6169e2aeef Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Thu, 14 Nov 2024 12:13:55 +0100 Subject: [PATCH 294/352] Fix location of printing out error message in utils_mmap_file() It was printed out in a wrong place. Signed-off-by: Lukasz Dorau --- src/utils/utils_linux_common.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/utils/utils_linux_common.c b/src/utils/utils_linux_common.c index b97880ffd..cd0fefd2a 100644 --- a/src/utils/utils_linux_common.c +++ b/src/utils/utils_linux_common.c @@ -86,10 +86,6 @@ void *utils_mmap_file(void *hint_addr, size_t length, int prot, int flags, return addr; } - LOG_PERR("mapping file with the MAP_SYNC flag failed (fd=%i, offset=%zu, " - "length=%zu, flags=%i)", - fd, fd_offset, length, sync_flags); - /* try to mmap with MAP_SHARED flag (without MAP_SYNC) */ if (errno == EINVAL || errno == ENOTSUP || errno == EOPNOTSUPP) { const int shared_flags = flags | MAP_SHARED; @@ -104,6 +100,11 @@ void *utils_mmap_file(void *hint_addr, size_t length, int prot, int flags, LOG_PERR("mapping file with the MAP_SHARED flag failed (fd=%i, " "offset=%zu, length=%zu, flags=%i)", fd, fd_offset, length, shared_flags); + } else { + LOG_PERR( + "mapping file with the MAP_SYNC flag failed (fd=%i, offset=%zu, " + "length=%zu, flags=%i)", + fd, fd_offset, length, sync_flags); } return NULL; From af9f761ddbfaa3af92415cfa641a822efc508c9d Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Thu, 14 Nov 2024 12:34:05 +0100 Subject: [PATCH 295/352] Fix Coverity issues in scalable_pool.cpp --- test/pools/scalable_pool.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/pools/scalable_pool.cpp b/test/pools/scalable_pool.cpp index 68409b4bb..0066f75e3 100644 --- a/test/pools/scalable_pool.cpp +++ b/test/pools/scalable_pool.cpp @@ -29,16 +29,16 @@ struct umfScalablePoolParamsTest struct provider_validator : public umf_test::provider_ba_global { using base_provider = umf_test::provider_ba_global; - umf_result_t initialize(validation_params_t *params) noexcept { + umf_result_t initialize(validation_params_t *params) { EXPECT_NE(params, nullptr); expected_params = params; return UMF_RESULT_SUCCESS; } - umf_result_t alloc(size_t size, size_t align, void **ptr) noexcept { + umf_result_t alloc(size_t size, size_t align, void **ptr) { EXPECT_EQ(size, expected_params->granularity); return base_provider::alloc(size, align, ptr); } - umf_result_t free(void *ptr, size_t size) noexcept { + umf_result_t free(void *ptr, size_t size) { EXPECT_EQ(expected_params->keep_all_memory, false); return base_provider::free(ptr, size); } @@ -49,7 +49,7 @@ struct umfScalablePoolParamsTest static constexpr umf_memory_provider_ops_t VALIDATOR_PROVIDER_OPS = umf::providerMakeCOps(); - umfScalablePoolParamsTest() {} + umfScalablePoolParamsTest() : expected_params{0, false}, params(nullptr) {} void SetUp() override { test::SetUp(); auto [granularity, keep_all_memory] = this->GetParam(); From a14134c3f3e3284f36ce8a28f75a05127467f984 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Thu, 14 Nov 2024 12:34:56 +0100 Subject: [PATCH 296/352] Cosmetic changes in scalable pool params implementation --- src/pool/pool_scalable.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/pool/pool_scalable.c b/src/pool/pool_scalable.c index 8e92d8758..7f355161c 100644 --- a/src/pool/pool_scalable.c +++ b/src/pool/pool_scalable.c @@ -174,8 +174,8 @@ static void tbb_raw_free_wrapper(intptr_t pool_id, void *ptr, size_t bytes) { } umf_result_t -umfScalablePoolParamsCreate(umf_scalable_pool_params_handle_t *params) { - if (!params) { +umfScalablePoolParamsCreate(umf_scalable_pool_params_handle_t *hParams) { + if (!hParams) { LOG_ERR("scalable pool params handle is NULL"); return UMF_RESULT_ERROR_INVALID_ARGUMENT; } @@ -190,28 +190,28 @@ umfScalablePoolParamsCreate(umf_scalable_pool_params_handle_t *params) { params_data->granularity = DEFAULT_GRANULARITY; params_data->keep_all_memory = false; - *params = (umf_scalable_pool_params_handle_t)params_data; + *hParams = (umf_scalable_pool_params_handle_t)params_data; return UMF_RESULT_SUCCESS; } umf_result_t -umfScalablePoolParamsDestroy(umf_scalable_pool_params_handle_t params) { - if (!params) { - LOG_ERR("params is NULL"); +umfScalablePoolParamsDestroy(umf_scalable_pool_params_handle_t hParams) { + if (!hParams) { + LOG_ERR("scalable pool params handle is NULL"); return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - umf_ba_global_free(params); + umf_ba_global_free(hParams); return UMF_RESULT_SUCCESS; } umf_result_t -umfScalablePoolParamsSetGranularity(umf_scalable_pool_params_handle_t params, +umfScalablePoolParamsSetGranularity(umf_scalable_pool_params_handle_t hParams, size_t granularity) { - if (!params) { - LOG_ERR("params is NULL"); + if (!hParams) { + LOG_ERR("scalable pool params handle is NULL"); return UMF_RESULT_ERROR_INVALID_ARGUMENT; } @@ -220,20 +220,20 @@ umfScalablePoolParamsSetGranularity(umf_scalable_pool_params_handle_t params, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - params->granularity = granularity; + hParams->granularity = granularity; return UMF_RESULT_SUCCESS; } umf_result_t -umfScalablePoolParamsSetKeepAllMemory(umf_scalable_pool_params_handle_t params, - bool keep_all_memory) { - if (!params) { - LOG_ERR("params is NULL"); +umfScalablePoolParamsSetKeepAllMemory(umf_scalable_pool_params_handle_t hParams, + bool keepAllMemory) { + if (!hParams) { + LOG_ERR("scalable pool params handle is NULL"); return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - params->keep_all_memory = keep_all_memory; + hParams->keep_all_memory = keepAllMemory; return UMF_RESULT_SUCCESS; } From 467be1753b0274169666da6dc15c21ede8b1286d Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 18 Nov 2024 18:23:52 +0100 Subject: [PATCH 297/352] Temporarily disable failing windows-2022 clang CI job Signed-off-by: Lukasz Dorau --- .github/workflows/reusable_basic.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/reusable_basic.yml b/.github/workflows/reusable_basic.yml index 807fd14f0..1c13a771b 100644 --- a/.github/workflows/reusable_basic.yml +++ b/.github/workflows/reusable_basic.yml @@ -227,13 +227,14 @@ jobs: level_zero_provider: ['ON'] cuda_provider: ['ON'] include: - - os: 'windows-2022' - build_type: Release - compiler: {c: clang-cl, cxx: clang-cl} - shared_library: 'ON' - level_zero_provider: 'ON' - cuda_provider: 'ON' - toolset: "-T ClangCL" + # temporarily disable failing CI job + #- os: 'windows-2022' + # build_type: Release + # compiler: {c: clang-cl, cxx: clang-cl} + # shared_library: 'ON' + # level_zero_provider: 'ON' + # cuda_provider: 'ON' + # toolset: "-T ClangCL" - os: 'windows-2022' build_type: Release compiler: {c: cl, cxx: cl} From 2e504544b7ac31b8a27445693be2349e8b70335b Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Tue, 12 Nov 2024 12:01:49 +0100 Subject: [PATCH 298/352] Fix format string Signed-off-by: Lukasz Dorau --- test/ipc_os_prov_proxy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ipc_os_prov_proxy.c b/test/ipc_os_prov_proxy.c index a17518658..0a4b64442 100644 --- a/test/ipc_os_prov_proxy.c +++ b/test/ipc_os_prov_proxy.c @@ -220,7 +220,7 @@ int main(int argc, char *argv[]) { fprintf( stderr, "[producer] ERROR: The consumer did NOT write the correct value " - "(the old one / 2 = %llu) to my shared memory: %llu\n", + "(the old one / 2 = %zu) to my shared memory: %llu\n", expected_val, new_val); } From ee1400d51e75d73b33aa699f7d4a4dc4c0f97fb6 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Sun, 10 Nov 2024 18:26:07 +0100 Subject: [PATCH 299/352] Do not assert(ptr) in umfMemoryTrackerGetAllocInfo() Do not assert(ptr) in umfMemoryTrackerGetAllocInfo(), return UMF_RESULT_ERROR_INVALID_ARGUMENT instead. Replace LOG_WARN() with LOG_DEBUG(). --- src/provider/provider_tracking.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/provider/provider_tracking.c b/src/provider/provider_tracking.c index 769ed6a94..e726feefb 100644 --- a/src/provider/provider_tracking.c +++ b/src/provider/provider_tracking.c @@ -106,16 +106,19 @@ umf_memory_pool_handle_t umfMemoryTrackerGetPool(const void *ptr) { umf_result_t umfMemoryTrackerGetAllocInfo(const void *ptr, umf_alloc_info_t *pAllocInfo) { - assert(ptr); assert(pAllocInfo); + if (ptr == NULL) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + if (TRACKER == NULL) { - LOG_ERR("tracker is not created"); + LOG_ERR("tracker does not exist"); return UMF_RESULT_ERROR_NOT_SUPPORTED; } if (TRACKER->map == NULL) { - LOG_ERR("tracker's map is not created"); + LOG_ERR("tracker's map does not exist"); return UMF_RESULT_ERROR_NOT_SUPPORTED; } @@ -124,9 +127,8 @@ umf_result_t umfMemoryTrackerGetAllocInfo(const void *ptr, int found = critnib_find(TRACKER->map, (uintptr_t)ptr, FIND_LE, (void *)&rkey, (void **)&rvalue); if (!found || (uintptr_t)ptr >= rkey + rvalue->size) { - LOG_WARN("pointer %p not found in the " - "tracker, TRACKER=%p", - ptr, (void *)TRACKER); + LOG_DEBUG("pointer %p not found in the tracker, TRACKER=%p", ptr, + (void *)TRACKER); return UMF_RESULT_ERROR_INVALID_ARGUMENT; } From 865ccbf28eeebdc99133a9a280b826435975c52c Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 11 Nov 2024 10:30:45 +0100 Subject: [PATCH 300/352] Add utils_env_var_get_str() to utils_common Add utils_env_var_get_str() to utils_common. Use utils_env_var_get_str() inside utils_env_var_has_str() and utils_is_running_in_proxy_lib(). Signed-off-by: Lukasz Dorau --- src/utils/utils_common.c | 13 ++----------- src/utils/utils_common.h | 15 +++++++++++---- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/utils/utils_common.c b/src/utils/utils_common.c index 25169f6cf..bffc9f355 100644 --- a/src/utils/utils_common.c +++ b/src/utils/utils_common.c @@ -53,18 +53,9 @@ void utils_align_ptr_down_size_up(void **ptr, size_t *size, size_t alignment) { *size = s; } -int utils_env_var_has_str(const char *envvar, const char *str) { +char *utils_env_var_get_str(const char *envvar, const char *str) { char *value = getenv(envvar); - if (value && strstr(value, str)) { - return 1; - } - - return 0; -} - -// check if we are running in the proxy library -int utils_is_running_in_proxy_lib(void) { - return utils_env_var_has_str("LD_PRELOAD", "libumf_proxy.so"); + return value ? strstr(value, str) : NULL; } const char *utils_parse_var(const char *var, const char *option, diff --git a/src/utils/utils_common.h b/src/utils/utils_common.h index c25fda2ab..7751a2ac9 100644 --- a/src/utils/utils_common.h +++ b/src/utils/utils_common.h @@ -62,8 +62,18 @@ typedef enum umf_purge_advise_t { #endif /* _WIN32 */ +// get the address of the given string in the environment variable (or NULL) +char *utils_env_var_get_str(const char *envvar, const char *str); + // Check if the environment variable contains the given string. -int utils_env_var_has_str(const char *envvar, const char *str); +static inline int utils_env_var_has_str(const char *envvar, const char *str) { + return utils_env_var_get_str(envvar, str) ? 1 : 0; +} + +// check if we are running in the proxy library +static inline int utils_is_running_in_proxy_lib(void) { + return utils_env_var_get_str("LD_PRELOAD", "libumf_proxy.so") ? 1 : 0; +} // utils_parse_var - Parses var for a prefix, // optionally identifying a following argument. @@ -82,9 +92,6 @@ int utils_env_var_has_str(const char *envvar, const char *str); const char *utils_parse_var(const char *var, const char *option, const char **extraArg); -// check if we are running in the proxy library -int utils_is_running_in_proxy_lib(void); - size_t utils_get_page_size(void); // align a pointer up and a size down From bddbffd8aa12f5a2be131016c383776e94d2e9a3 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Tue, 12 Nov 2024 09:22:10 +0100 Subject: [PATCH 301/352] Do not destroy tracker in umfTearDown() under the proxy library Signed-off-by: Lukasz Dorau --- src/base_alloc/base_alloc_global.c | 2 ++ src/libumf.c | 24 ++++++++++++++++++++++++ src/utils/utils_common.h | 8 ++++++++ 3 files changed, 34 insertions(+) diff --git a/src/base_alloc/base_alloc_global.c b/src/base_alloc/base_alloc_global.c index 11d88b731..2aca5d29c 100644 --- a/src/base_alloc/base_alloc_global.c +++ b/src/base_alloc/base_alloc_global.c @@ -67,6 +67,8 @@ static void umf_ba_create_global(void) { size_t smallestSize = BASE_ALLOC.ac_sizes[0]; BASE_ALLOC.smallest_ac_size_log2 = log2Utils(smallestSize); + + LOG_DEBUG("UMF base allocator created"); } // returns index of the allocation class for a given size diff --git a/src/libumf.c b/src/libumf.c index 3b69ce396..b89e5c844 100644 --- a/src/libumf.c +++ b/src/libumf.c @@ -13,6 +13,7 @@ #include "ipc_cache.h" #include "memspace_internal.h" #include "provider_tracking.h" +#include "utils_common.h" #include "utils_log.h" #if !defined(UMF_NO_HWLOC) #include "topology.h" @@ -30,11 +31,20 @@ int umfInit(void) { LOG_ERR("Failed to create memory tracker"); return -1; } + + LOG_DEBUG("UMF tracker created"); + umf_result_t umf_result = umfIpcCacheGlobalInit(); if (umf_result != UMF_RESULT_SUCCESS) { LOG_ERR("Failed to initialize IPC cache"); return -1; } + + LOG_DEBUG("UMF IPC cache initialized"); + } + + if (TRACKER) { + LOG_DEBUG("UMF library initialized"); } return 0; @@ -50,12 +60,26 @@ void umfTearDown(void) { umfDestroyTopology(); #endif umfIpcCacheGlobalTearDown(); + + if (utils_is_running_in_proxy_lib_with_size_threshold()) { + // We cannot destroy the TRACKER nor the base allocator + // when we are running in the proxy library with a size threshold, + // because it could result in calling the system free() + // with an invalid pointer and a segfault. + goto fini_umfTearDown; + } + // make sure TRACKER is not used after being destroyed umf_memory_tracker_handle_t t = TRACKER; TRACKER = NULL; umfMemoryTrackerDestroy(t); + LOG_DEBUG("UMF tracker destroyed"); umf_ba_destroy_global(); + LOG_DEBUG("UMF base allocator destroyed"); + + fini_umfTearDown: + LOG_DEBUG("UMF library finalized"); } } diff --git a/src/utils/utils_common.h b/src/utils/utils_common.h index 7751a2ac9..90b95e3ba 100644 --- a/src/utils/utils_common.h +++ b/src/utils/utils_common.h @@ -75,6 +75,14 @@ static inline int utils_is_running_in_proxy_lib(void) { return utils_env_var_get_str("LD_PRELOAD", "libumf_proxy.so") ? 1 : 0; } +// check if we are running in the proxy library with a size threshold +static inline int utils_is_running_in_proxy_lib_with_size_threshold(void) { + return (utils_env_var_get_str("LD_PRELOAD", "libumf_proxy.so") && + utils_env_var_get_str("UMF_PROXY", "size.threshold=")) + ? 1 + : 0; +} + // utils_parse_var - Parses var for a prefix, // optionally identifying a following argument. // Parameters: From 1dd43b2534350e793a0a0e5d7a86e1f6d7664726 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 18 Nov 2024 14:23:50 +0100 Subject: [PATCH 302/352] Add size threshold to proxy lib to call system allocator (Linux only) Add a size threshold to proxy lib to call system allocator when the size is less than the given threshold (Linux only yet). Signed-off-by: Lukasz Dorau --- README.md | 7 ++ src/proxy_lib/proxy_lib.c | 159 +++++++++++++++++++++++++++---- src/utils/utils_common.h | 2 + src/utils/utils_posix_common.c | 25 +++++ src/utils/utils_windows_common.c | 7 ++ test/utils/utils_linux.cpp | 14 +++ 6 files changed, 198 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index f0c98c112..6f1233c63 100644 --- a/README.md +++ b/README.md @@ -317,6 +317,13 @@ The memory used by the proxy memory allocator is mmap'ed: - `page.disposition=shared-shm` - IPC uses the named shared memory. An SHM name is generated using the `umf_proxy_lib_shm_pid_$PID` pattern, where `$PID` is the PID of the process. It creates the `/dev/shm/umf_proxy_lib_shm_pid_$PID` file. - `page.disposition=shared-fd` - IPC uses the file descriptor duplication. It requires using `pidfd_getfd(2)` to obtain a duplicate of another process's file descriptor. Permission to duplicate another process's file descriptor is governed by a ptrace access mode `PTRACE_MODE_ATTACH_REALCREDS` check (see `ptrace(2)`) that can be changed using the `/proc/sys/kernel/yama/ptrace_scope` interface. `pidfd_getfd(2)` is supported since Linux 5.6. +**Size threshold** + +The **size threshold** feature (Linux only) causes that all allocations of size less than the given threshold value go to the default system allocator instead of the proxy library. +It can be enabled by adding the `size.threshold=` string to the `UMF_PROXY` environment variable (with `';'` as a separator), for example: `UMF_PROXY="page.disposition=shared-shm;size.threshold=64"`. + +**Remark:** changing a size of allocation (using `realloc()` ) does not change the allocator (`realloc(malloc(threshold - 1), threshold + 1)` still belongs to the default system allocator and `realloc(malloc(threshold + 1), threshold - 1)` still belongs to the proxy library pool allocator). + #### Windows In case of Windows it requires: diff --git a/src/proxy_lib/proxy_lib.c b/src/proxy_lib/proxy_lib.c index 5a5912b13..d687598bb 100644 --- a/src/proxy_lib/proxy_lib.c +++ b/src/proxy_lib/proxy_lib.c @@ -27,6 +27,12 @@ * - _aligned_offset_recalloc() */ +#ifndef _WIN32 +#define _GNU_SOURCE // for RTLD_NEXT +#include +#undef _GNU_SOURCE +#endif /* _WIN32 */ + #if (defined PROXY_LIB_USES_JEMALLOC_POOL) #include #define umfPoolManagerOps umfJemallocPoolOps @@ -48,6 +54,7 @@ #include "base_alloc_linear.h" #include "proxy_lib.h" #include "utils_common.h" +#include "utils_load_library.h" #include "utils_log.h" #ifdef _WIN32 /* Windows ***************************************/ @@ -94,6 +101,24 @@ void utils_init_once(UTIL_ONCE_FLAG *flag, void (*onceCb)(void)); * of a UMF pool to allocate memory needed by an application. It should be freed * by an application. */ +#ifndef _WIN32 +typedef void *(*system_aligned_alloc_t)(size_t alignment, size_t size); +typedef void *(*system_calloc_t)(size_t nmemb, size_t size); +typedef void (*system_free_t)(void *ptr); +typedef void *(*system_malloc_t)(size_t size); +typedef size_t (*system_malloc_usable_size_t)(void *ptr); +typedef void *(*system_realloc_t)(void *ptr, size_t size); + +// pointers to the default system allocator's API +static system_aligned_alloc_t System_aligned_alloc; +static system_calloc_t System_calloc; +static system_free_t System_free; +static system_malloc_t System_malloc; +static system_malloc_usable_size_t System_malloc_usable_size; +static system_realloc_t System_realloc; + +static size_t Size_threshold_value = 0; +#endif /* _WIN32 */ static UTIL_ONCE_FLAG Base_alloc_leak_initialized = UTIL_ONCE_FLAG_INIT; static umf_ba_linear_pool_t *Base_alloc_leak = NULL; @@ -107,6 +132,48 @@ static __TLS int was_called_from_umfPool = 0; /*** The constructor and destructor of the proxy library *********************/ /*****************************************************************************/ +#ifndef _WIN32 +static size_t get_size_threshold(void) { + char *str_threshold = utils_env_var_get_str("UMF_PROXY", "size.threshold="); + LOG_DEBUG("UMF_PROXY[size.threshold] = %s", str_threshold); + long threshold = utils_get_size_threshold(str_threshold); + if (threshold < 0) { + LOG_ERR("incorrect size threshold: %s", str_threshold); + exit(-1); + } + + return (size_t)threshold; +} + +static int get_system_allocator_symbols(void) { + *((void **)(&System_aligned_alloc)) = + utils_get_symbol_addr(RTLD_NEXT, "aligned_alloc", NULL); + *((void **)(&System_calloc)) = + utils_get_symbol_addr(RTLD_NEXT, "calloc", NULL); + *((void **)(&System_free)) = utils_get_symbol_addr(RTLD_NEXT, "free", NULL); + *((void **)(&System_malloc)) = + utils_get_symbol_addr(RTLD_NEXT, "malloc", NULL); + *((void **)(&System_malloc_usable_size)) = + utils_get_symbol_addr(RTLD_NEXT, "malloc_usable_size", NULL); + *((void **)(&System_realloc)) = + utils_get_symbol_addr(RTLD_NEXT, "realloc", NULL); + + if (System_aligned_alloc && System_calloc && System_free && System_malloc && + System_malloc_usable_size && System_realloc) { + return 0; + } + + *((void **)(&System_aligned_alloc)) = NULL; + *((void **)(&System_calloc)) = NULL; + *((void **)(&System_free)) = NULL; + *((void **)(&System_malloc)) = NULL; + *((void **)(&System_malloc_usable_size)) = NULL; + *((void **)(&System_realloc)) = NULL; + + return -1; +} +#endif /* _WIN32 */ + void proxy_lib_create_common(void) { utils_log_init(); umf_os_memory_provider_params_t os_params = @@ -114,11 +181,21 @@ void proxy_lib_create_common(void) { umf_result_t umf_result; #ifndef _WIN32 - char shm_name[NAME_MAX]; + size_t _threshold = get_size_threshold(); + if (_threshold > 0) { + if (get_system_allocator_symbols()) { + LOG_ERR("initialization of the system allocator failed!"); + exit(-1); + } + + Size_threshold_value = _threshold; + LOG_INFO("system allocator initialized, size threshold value = %zu", + Size_threshold_value); + } if (utils_env_var_has_str("UMF_PROXY", "page.disposition=shared-fd")) { - LOG_DEBUG("proxy_lib: using the MAP_SHARED visibility mode with the " - "file descriptor duplication"); + LOG_INFO("proxy_lib: using the MAP_SHARED visibility mode with the " + "file descriptor duplication"); os_params.visibility = UMF_MEM_MAP_SHARED; os_params.shm_name = NULL; @@ -126,15 +203,16 @@ void proxy_lib_create_common(void) { "page.disposition=shared-shm")) { os_params.visibility = UMF_MEM_MAP_SHARED; + char shm_name[NAME_MAX]; memset(shm_name, 0, NAME_MAX); sprintf(shm_name, "umf_proxy_lib_shm_pid_%i", utils_getpid()); os_params.shm_name = shm_name; - LOG_DEBUG("proxy_lib: using the MAP_SHARED visibility mode with the " - "named shared memory: %s", - os_params.shm_name); + LOG_INFO("proxy_lib: using the MAP_SHARED visibility mode with the " + "named shared memory: %s", + os_params.shm_name); } -#endif +#endif /* _WIN32 */ umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), &os_params, &OS_memory_provider); @@ -149,8 +227,10 @@ void proxy_lib_create_common(void) { LOG_ERR("creating UMF pool manager failed"); exit(-1); } + // The UMF pool has just been created (Proxy_pool != NULL). Stop using // the linear allocator and start using the UMF pool allocator from now on. + LOG_DEBUG("proxy library initialized"); } void proxy_lib_destroy_common(void) { @@ -158,7 +238,7 @@ void proxy_lib_destroy_common(void) { // We cannot destroy 'Base_alloc_leak' nor 'Proxy_pool' nor 'OS_memory_provider', // because it could lead to use-after-free in the program's unloader // (for example _dl_fini() on Linux). - return; + goto fini_proxy_lib_destroy_common; } umf_memory_pool_handle_t pool = Proxy_pool; @@ -168,6 +248,10 @@ void proxy_lib_destroy_common(void) { umf_memory_provider_handle_t provider = OS_memory_provider; OS_memory_provider = NULL; umfMemoryProviderDestroy(provider); + LOG_DEBUG("proxy library destroyed"); + +fini_proxy_lib_destroy_common: + LOG_DEBUG("proxy library finalized"); } /*****************************************************************************/ @@ -246,6 +330,12 @@ static inline size_t ba_leak_pool_contains_pointer(void *ptr) { /*****************************************************************************/ void *malloc(size_t size) { +#ifndef _WIN32 + if (size < Size_threshold_value) { + return System_malloc(size); + } +#endif /* _WIN32 */ + if (!was_called_from_umfPool && Proxy_pool) { was_called_from_umfPool = 1; void *ptr = umfPoolMalloc(Proxy_pool, size); @@ -257,6 +347,12 @@ void *malloc(size_t size) { } void *calloc(size_t nmemb, size_t size) { +#ifndef _WIN32 + if ((nmemb * size) < Size_threshold_value) { + return System_calloc(nmemb, size); + } +#endif /* _WIN32 */ + if (!was_called_from_umfPool && Proxy_pool) { was_called_from_umfPool = 1; void *ptr = umfPoolCalloc(Proxy_pool, nmemb, size); @@ -276,15 +372,22 @@ void free(void *ptr) { return; } - if (Proxy_pool) { + if (Proxy_pool && (umfPoolByPtr(ptr) == Proxy_pool)) { if (umfPoolFree(Proxy_pool, ptr) != UMF_RESULT_SUCCESS) { LOG_ERR("umfPoolFree() failed"); - assert(0); } return; } - assert(0); +#ifndef _WIN32 + if (Size_threshold_value) { + System_free(ptr); + return; + } +#endif /* _WIN32 */ + + LOG_ERR("free() failed: %p", ptr); + return; } @@ -303,18 +406,31 @@ void *realloc(void *ptr, size_t size) { return ba_leak_realloc(ptr, size, leak_pool_contains_pointer); } - if (Proxy_pool) { + if (Proxy_pool && (umfPoolByPtr(ptr) == Proxy_pool)) { was_called_from_umfPool = 1; void *new_ptr = umfPoolRealloc(Proxy_pool, ptr, size); was_called_from_umfPool = 0; return new_ptr; } - assert(0); +#ifndef _WIN32 + if (Size_threshold_value) { + return System_realloc(ptr, size); + } +#endif /* _WIN32 */ + + LOG_ERR("realloc() failed: %p", ptr); + return NULL; } void *aligned_alloc(size_t alignment, size_t size) { +#ifndef _WIN32 + if (size < Size_threshold_value) { + return System_aligned_alloc(alignment, size); + } +#endif /* _WIN32 */ + if (!was_called_from_umfPool && Proxy_pool) { was_called_from_umfPool = 1; void *ptr = umfPoolAlignedMalloc(Proxy_pool, size, alignment); @@ -330,19 +446,30 @@ size_t _msize(void *ptr) { #else size_t malloc_usable_size(void *ptr) { #endif - - // a check to verify we are running the proxy library + // a check to verify if we are running the proxy library if (ptr == (void *)0x01) { return 0xDEADBEEF; } - if (!was_called_from_umfPool && Proxy_pool) { + if (ba_leak_pool_contains_pointer(ptr)) { + return 0; // unsupported in case of the ba_leak allocator + } + + if (Proxy_pool && (umfPoolByPtr(ptr) == Proxy_pool)) { was_called_from_umfPool = 1; size_t size = umfPoolMallocUsableSize(Proxy_pool, ptr); was_called_from_umfPool = 0; return size; } +#ifndef _WIN32 + if (Size_threshold_value) { + return System_malloc_usable_size(ptr); + } +#endif /* _WIN32 */ + + LOG_ERR("malloc_usable_size() failed: %p", ptr); + return 0; // unsupported in this case } diff --git a/src/utils/utils_common.h b/src/utils/utils_common.h index 90b95e3ba..6920d97cf 100644 --- a/src/utils/utils_common.h +++ b/src/utils/utils_common.h @@ -168,6 +168,8 @@ int utils_file_open_or_create(const char *path); int utils_fallocate(int fd, long offset, long len); +long utils_get_size_threshold(char *str_threshold); + #ifdef __cplusplus } #endif diff --git a/src/utils/utils_posix_common.c b/src/utils/utils_posix_common.c index 10c2473c2..b0add36b9 100644 --- a/src/utils/utils_posix_common.c +++ b/src/utils/utils_posix_common.c @@ -7,6 +7,7 @@ * */ +#include #include #include #include @@ -266,3 +267,27 @@ int utils_file_open_or_create(const char *path) { return fd; } + +// Expected input: +// char *str_threshold = utils_env_var_get_str("UMF_PROXY", "size.threshold="); +long utils_get_size_threshold(char *str_threshold) { + if (!str_threshold) { + return 0; + } + + // move to the beginning of the number + str_threshold += strlen("size.threshold="); + + // check if the first character is a digit + if (!isdigit(str_threshold[0])) { + LOG_ERR("incorrect size threshold, expected numerical value >=0: %s", + str_threshold); + return -1; + } + + size_t threshold = atol(str_threshold); + LOG_DEBUG("Size_threshold_value = (char *) %s, (size_t) %zu", str_threshold, + threshold); + + return threshold; +} diff --git a/src/utils/utils_windows_common.c b/src/utils/utils_windows_common.c index 50a7b6ed5..e941b317d 100644 --- a/src/utils/utils_windows_common.c +++ b/src/utils/utils_windows_common.c @@ -215,3 +215,10 @@ int utils_fallocate(int fd, long offset, long len) { return -1; } + +// Expected input: +// char *str_threshold = utils_env_var_get_str("UMF_PROXY", "size.threshold="); +long utils_get_size_threshold(char *str_threshold) { + (void)str_threshold; // unused + return 0; +} diff --git a/test/utils/utils_linux.cpp b/test/utils/utils_linux.cpp index 82061409b..e99bb1161 100644 --- a/test/utils/utils_linux.cpp +++ b/test/utils/utils_linux.cpp @@ -56,3 +56,17 @@ TEST_F(test, utils_shm_create_invalid_args) { ret = utils_shm_create("/abc", -1); EXPECT_EQ(ret, -1); } + +TEST_F(test, utils_get_size_threshold) { + // Expected input to utils_get_size_threshold(): + // char *str_threshold = utils_env_var_get_str("UMF_PROXY", "size.threshold="); + // positive tests + EXPECT_EQ(utils_get_size_threshold((char *)"size.threshold=111"), 111); + EXPECT_EQ(utils_get_size_threshold((char *)"size.threshold=222;abcd"), 222); + EXPECT_EQ(utils_get_size_threshold((char *)"size.threshold=333;var=value"), + 333); + // negative tests + EXPECT_EQ(utils_get_size_threshold(NULL), 0); + EXPECT_EQ(utils_get_size_threshold((char *)"size.threshold=abc"), -1); + EXPECT_EQ(utils_get_size_threshold((char *)"size.threshold=-111"), -1); +} From a4fced635067affb6787da41116ae3ffadfc5597 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Thu, 14 Nov 2024 22:18:49 +0100 Subject: [PATCH 303/352] Add WA for the issue This WA for the issue: https://github.com/oneapi-src/unified-memory-framework/issues/894 It protects us from a recursion in malloc_usable_size() when the JEMALLOC proxy_lib_pool is used. TODO: remove this WA when the issue is fixed. Signed-off-by: Lukasz Dorau --- src/proxy_lib/proxy_lib.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/proxy_lib/proxy_lib.c b/src/proxy_lib/proxy_lib.c index d687598bb..3320f2898 100644 --- a/src/proxy_lib/proxy_lib.c +++ b/src/proxy_lib/proxy_lib.c @@ -128,6 +128,13 @@ static umf_memory_pool_handle_t Proxy_pool = NULL; // it protects us from recursion in umfPool*() static __TLS int was_called_from_umfPool = 0; +// This WA for the issue: +// https://github.com/oneapi-src/unified-memory-framework/issues/894 +// It protects us from a recursion in malloc_usable_size() +// when the JEMALLOC proxy_lib_pool is used. +// TODO remove this WA when the issue is fixed. +static __TLS int was_called_from_malloc_usable_size = 0; + /*****************************************************************************/ /*** The constructor and destructor of the proxy library *********************/ /*****************************************************************************/ @@ -455,15 +462,18 @@ size_t malloc_usable_size(void *ptr) { return 0; // unsupported in case of the ba_leak allocator } - if (Proxy_pool && (umfPoolByPtr(ptr) == Proxy_pool)) { + if (!was_called_from_malloc_usable_size && Proxy_pool && + (umfPoolByPtr(ptr) == Proxy_pool)) { + was_called_from_malloc_usable_size = 1; was_called_from_umfPool = 1; size_t size = umfPoolMallocUsableSize(Proxy_pool, ptr); was_called_from_umfPool = 0; + was_called_from_malloc_usable_size = 0; return size; } #ifndef _WIN32 - if (Size_threshold_value) { + if (!was_called_from_malloc_usable_size && Size_threshold_value) { return System_malloc_usable_size(ptr); } #endif /* _WIN32 */ From 3966c3a0d5debdfaa824ab3576b1bc54fa8c2d79 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 18 Nov 2024 18:24:57 +0100 Subject: [PATCH 304/352] Add tests for the size threshold of the proxy library (Linux only) The proxyLib_size_threshold_* tests test the size threshold of the proxy library (Linux only yet). The size threshold is set to 64 bytes in this test, so all allocations of: 1) size < 64 go through the default system allocator and (umfPoolByPtr(ptr_size < 64) == nullptr) 2) size >= 64 go through the proxy lib allocator and (umfPoolByPtr(ptr_size >= 64) != nullptr). Ref: #894 Signed-off-by: Lukasz Dorau --- .github/workflows/reusable_proxy_lib.yml | 9 ++ test/CMakeLists.txt | 10 ++ test/test_proxy_lib_size_threshold.cpp | 183 +++++++++++++++++++++++ test/utils/utils_linux.cpp | 7 + 4 files changed, 209 insertions(+) create mode 100644 test/test_proxy_lib_size_threshold.cpp diff --git a/.github/workflows/reusable_proxy_lib.yml b/.github/workflows/reusable_proxy_lib.yml index 56211b97d..2a27161b3 100644 --- a/.github/workflows/reusable_proxy_lib.yml +++ b/.github/workflows/reusable_proxy_lib.yml @@ -77,6 +77,15 @@ jobs: working-directory: ${{env.BUILD_DIR}} run: UMF_PROXY="page.disposition=shared-shm" LD_PRELOAD=./lib/libumf_proxy.so /usr/bin/date + # TODO enable the provider_file_memory_ipc test when the IPC tests with the proxy library are fixed + # see the issue: https://github.com/oneapi-src/unified-memory-framework/issues/864 + - name: Run "ctest --output-on-failure" with proxy library and size.threshold=128 + working-directory: ${{env.BUILD_DIR}} + run: > + UMF_PROXY="page.disposition=shared-shm;size.threshold=128" + LD_PRELOAD=./lib/libumf_proxy.so + ctest --output-on-failure -E provider_file_memory_ipc + - name: Check coverage if: ${{ matrix.build_type == 'Debug' }} working-directory: ${{env.BUILD_DIR}} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index d24244ab0..9899991ce 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -414,6 +414,16 @@ if(UMF_PROXY_LIB_ENABLED AND UMF_BUILD_SHARED_LIBRARY) SRCS ${BA_SOURCES_FOR_TEST} test_proxy_lib.cpp LIBS ${UMF_UTILS_FOR_TEST} umf_proxy) + # TODO enable this test on Windows + if(LINUX) + add_umf_test( + NAME test_proxy_lib_size_threshold + SRCS ${BA_SOURCES_FOR_TEST} test_proxy_lib_size_threshold.cpp + LIBS ${UMF_UTILS_FOR_TEST} umf_proxy) + set_property(TEST umf-test_proxy_lib_size_threshold + PROPERTY ENVIRONMENT UMF_PROXY="size.threshold=64") + endif() + # the memoryPool test run with the proxy library add_umf_test( NAME proxy_lib_memoryPool diff --git a/test/test_proxy_lib_size_threshold.cpp b/test/test_proxy_lib_size_threshold.cpp new file mode 100644 index 000000000..fac1c516b --- /dev/null +++ b/test/test_proxy_lib_size_threshold.cpp @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2024 Intel Corporation + * + * Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +*/ + +#if defined(__APPLE__) +#include +#else +#include +#endif + +#include + +#include "base.hpp" +#include "test_helpers.h" +#include "utils_common.h" + +using umf_test::test; + +// size threshold defined by the env variable UMF_PROXY="size.threshold=64" +#define SIZE_THRESHOLD 64 +#define SIZE_EQ (SIZE_THRESHOLD) +#define SIZE_LT (SIZE_THRESHOLD - 1) + +#define ALIGN_1024 1024 + +TEST_F(test, proxyLib_basic) { + // a check to verify we are running the proxy library + void *ptr = (void *)0x01; + +#ifdef _WIN32 + size_t size = _msize(ptr); +#elif __APPLE__ + size_t size = ::malloc_size(ptr); +#else + size_t size = ::malloc_usable_size(ptr); +#endif + + ASSERT_EQ(size, 0xDEADBEEF); +} + +TEST_F(test, proxyLib_realloc_size0) { + // realloc(ptr, 0) == free(ptr) + // realloc(ptr, 0) returns NULL + ASSERT_EQ(::realloc(::malloc(SIZE_EQ), 0), nullptr); +} + +// The proxyLib_size_threshold_* tests test the size threshold of the proxy library. +// The size threshold is set to SIZE_THRESHOLD bytes in this test, so all allocations of: +// 1) size < SIZE_THRESHOLD go through the default system allocator +// (umfPoolByPtr(ptr_size < SIZE_THRESHOLD) == nullptr) +// 2) size >= SIZE_THRESHOLD go through the proxy library allocator +// (umfPoolByPtr(ptr_size >= SIZE_THRESHOLD) != nullptr) + +TEST_F(test, proxyLib_size_threshold_aligned_alloc) { +#ifdef _WIN32 + void *ptr_LT = _aligned_malloc(SIZE_LT, ALIGN_1024); + void *ptr_EQ = _aligned_malloc(SIZE_EQ, ALIGN_1024); +#else + void *ptr_LT = ::aligned_alloc(ALIGN_1024, SIZE_LT); + void *ptr_EQ = ::aligned_alloc(ALIGN_1024, SIZE_EQ); +#endif + + ASSERT_NE(ptr_LT, nullptr); + ASSERT_NE(ptr_EQ, nullptr); + + // verify alignment + ASSERT_EQ((int)(IS_ALIGNED((uintptr_t)ptr_LT, ALIGN_1024)), 1); + ASSERT_EQ((int)(IS_ALIGNED((uintptr_t)ptr_EQ, ALIGN_1024)), 1); + + ASSERT_EQ(umfPoolByPtr(ptr_LT), nullptr); + ASSERT_NE(umfPoolByPtr(ptr_EQ), nullptr); + +#ifdef _WIN32 + _aligned_free(ptr_LT); + _aligned_free(ptr_EQ); +#else + ::free(ptr_LT); + ::free(ptr_EQ); +#endif +} + +TEST_F(test, proxyLib_size_threshold_malloc) { + void *ptr_LT = malloc(SIZE_LT); + void *ptr_EQ = malloc(SIZE_EQ); + + ASSERT_NE(ptr_LT, nullptr); + ASSERT_NE(ptr_EQ, nullptr); + + ASSERT_EQ(umfPoolByPtr(ptr_LT), nullptr); + ASSERT_NE(umfPoolByPtr(ptr_EQ), nullptr); + + ::free(ptr_LT); + ::free(ptr_EQ); +} + +TEST_F(test, proxyLib_size_threshold_calloc) { + void *ptr_LT = calloc(SIZE_LT, 1); + void *ptr_EQ = calloc(SIZE_EQ, 1); + + ASSERT_NE(ptr_LT, nullptr); + ASSERT_NE(ptr_EQ, nullptr); + + ASSERT_EQ(umfPoolByPtr(ptr_LT), nullptr); + ASSERT_NE(umfPoolByPtr(ptr_EQ), nullptr); + + ::free(ptr_LT); + ::free(ptr_EQ); +} + +TEST_F(test, proxyLib_size_threshold_realloc_up) { + void *ptr_LT = malloc(SIZE_LT); + void *ptr_EQ = malloc(SIZE_EQ); + + ASSERT_NE(ptr_LT, nullptr); + ASSERT_NE(ptr_EQ, nullptr); + + void *ptr_LT_r = realloc(ptr_LT, 2 * SIZE_LT); + void *ptr_EQ_r = realloc(ptr_EQ, 2 * SIZE_EQ); + + ASSERT_NE(ptr_LT_r, nullptr); + ASSERT_NE(ptr_EQ_r, nullptr); + + ASSERT_EQ(umfPoolByPtr(ptr_LT_r), nullptr); + ASSERT_NE(umfPoolByPtr(ptr_EQ_r), nullptr); + + ::free(ptr_LT_r); + ::free(ptr_EQ_r); +} + +TEST_F(test, proxyLib_size_threshold_realloc_down) { + void *ptr_LT = malloc(SIZE_LT); + void *ptr_EQ = malloc(SIZE_EQ); + + ASSERT_NE(ptr_LT, nullptr); + ASSERT_NE(ptr_EQ, nullptr); + + void *ptr_LT_r = realloc(ptr_LT, SIZE_LT / 2); + void *ptr_EQ_r = realloc(ptr_EQ, SIZE_EQ / 2); + + ASSERT_NE(ptr_LT_r, nullptr); + ASSERT_NE(ptr_EQ_r, nullptr); + + ASSERT_EQ(umfPoolByPtr(ptr_LT_r), nullptr); + ASSERT_NE(umfPoolByPtr(ptr_EQ_r), nullptr); + + ::free(ptr_LT_r); + ::free(ptr_EQ_r); +} + +TEST_F(test, proxyLib_size_threshold_malloc_usable_size) { + + void *ptr_LT = ::malloc(SIZE_LT); + void *ptr_EQ = ::malloc(SIZE_EQ); + + ASSERT_NE(ptr_LT, nullptr); + ASSERT_NE(ptr_EQ, nullptr); + + if (ptr_LT == nullptr || ptr_EQ == nullptr) { + // Fix for the following CodeQL's warning on Windows: + // 'ptr' could be '0': this does not adhere to the specification for the function '_msize'. + return; + } + +#ifdef _WIN32 + size_t size_LT = _msize(ptr_LT); + size_t size_EQ = _msize(ptr_EQ); +#elif __APPLE__ + size_t size_LT = ::malloc_size(ptr_LT); + size_t size_EQ = ::malloc_size(ptr_EQ); +#else + size_t size_LT = ::malloc_usable_size(ptr_LT); + size_t size_EQ = ::malloc_usable_size(ptr_EQ); +#endif + + ASSERT_EQ((int)(size_LT == 0 || size_LT >= SIZE_LT), 1); + ASSERT_EQ((int)(size_EQ == 0 || size_EQ >= SIZE_EQ), 1); + + ::free(ptr_LT); + ::free(ptr_EQ); +} diff --git a/test/utils/utils_linux.cpp b/test/utils/utils_linux.cpp index e99bb1161..cbe99ae74 100644 --- a/test/utils/utils_linux.cpp +++ b/test/utils/utils_linux.cpp @@ -60,13 +60,20 @@ TEST_F(test, utils_shm_create_invalid_args) { TEST_F(test, utils_get_size_threshold) { // Expected input to utils_get_size_threshold(): // char *str_threshold = utils_env_var_get_str("UMF_PROXY", "size.threshold="); + // positive tests EXPECT_EQ(utils_get_size_threshold((char *)"size.threshold=111"), 111); EXPECT_EQ(utils_get_size_threshold((char *)"size.threshold=222;abcd"), 222); EXPECT_EQ(utils_get_size_threshold((char *)"size.threshold=333;var=value"), 333); + // LONG_MAX = 9223372036854775807 + EXPECT_EQ(utils_get_size_threshold( + (char *)"size.threshold=9223372036854775807;var=value"), + 9223372036854775807); + // negative tests EXPECT_EQ(utils_get_size_threshold(NULL), 0); + EXPECT_EQ(utils_get_size_threshold((char *)"size.threshold="), -1); EXPECT_EQ(utils_get_size_threshold((char *)"size.threshold=abc"), -1); EXPECT_EQ(utils_get_size_threshold((char *)"size.threshold=-111"), -1); } From 16ca017429b0ca85cb6a7ade574f22869b351135 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Tue, 19 Nov 2024 11:34:41 +0100 Subject: [PATCH 305/352] Fix warnings about unused parameter Signed-off-by: Lukasz Dorau --- src/provider/provider_cuda.c | 1 + src/provider/provider_devdax_memory.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/src/provider/provider_cuda.c b/src/provider/provider_cuda.c index db0016c44..68fe0da23 100644 --- a/src/provider/provider_cuda.c +++ b/src/provider/provider_cuda.c @@ -470,6 +470,7 @@ static umf_result_t cu_memory_provider_open_ipc_handle(void *provider, static umf_result_t cu_memory_provider_close_ipc_handle(void *provider, void *ptr, size_t size) { + (void)provider; (void)size; CUresult cu_result; diff --git a/src/provider/provider_devdax_memory.c b/src/provider/provider_devdax_memory.c index d11cfa809..1179ed115 100644 --- a/src/provider/provider_devdax_memory.c +++ b/src/provider/provider_devdax_memory.c @@ -326,6 +326,7 @@ static umf_result_t devdax_purge_lazy(void *provider, void *ptr, size_t size) { } static umf_result_t devdax_purge_force(void *provider, void *ptr, size_t size) { + (void)provider; // unused errno = 0; if (utils_purge(ptr, size, UMF_PURGE_FORCE)) { devdax_store_last_native_error( @@ -410,6 +411,7 @@ static umf_result_t devdax_put_ipc_handle(void *provider, static umf_result_t devdax_open_ipc_handle(void *provider, void *providerIpcData, void **ptr) { + (void)provider; // unused *ptr = NULL; devdax_ipc_data_t *devdax_ipc_data = (devdax_ipc_data_t *)providerIpcData; @@ -469,6 +471,7 @@ static umf_result_t devdax_open_ipc_handle(void *provider, static umf_result_t devdax_close_ipc_handle(void *provider, void *ptr, size_t size) { + (void)provider; // unused size = ALIGN_UP(size, DEVDAX_PAGE_SIZE_2MB); errno = 0; From 4e62f3ca3fd254fef350c8af7c4090df8c72c9dc Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Tue, 19 Nov 2024 11:35:06 +0100 Subject: [PATCH 306/352] Fix: getGlobalLruListSize() is needed only in debug mode Fix the warning: warning : unused function 'getGlobalLruListSize' [-Wunused-function] Signed-off-by: Lukasz Dorau --- src/ipc_cache.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ipc_cache.c b/src/ipc_cache.c index bff251b2e..40ecc3978 100644 --- a/src/ipc_cache.c +++ b/src/ipc_cache.c @@ -89,12 +89,14 @@ umf_result_t umfIpcCacheGlobalInit(void) { return ret; } +#ifndef NDEBUG static size_t getGlobalLruListSize(lru_list_t lru_list) { size_t size = 0; ipc_handle_cache_entry_t *tmp; DL_COUNT(lru_list, tmp, size); return size; } +#endif /* NDEBUG */ void umfIpcCacheGlobalTearDown(void) { ipc_mapped_handle_cache_global_t *cache_global = IPC_MAPPED_CACHE_GLOBAL; From 48d5146cf215bb0eee3e852aa93c82dc57ff6ae4 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Wed, 13 Nov 2024 14:01:23 +0100 Subject: [PATCH 307/352] Update jemalloc pool params implementation --- examples/dram_and_fsdax/dram_and_fsdax.c | 22 ++++- include/umf/pools/pool_jemalloc.h | 30 +++++- src/pool/pool_jemalloc.c | 56 ++++++++++- test/pools/jemalloc_pool.cpp | 119 +++++++++++++++++++++++ 4 files changed, 217 insertions(+), 10 deletions(-) diff --git a/examples/dram_and_fsdax/dram_and_fsdax.c b/examples/dram_and_fsdax/dram_and_fsdax.c index ac7b0434c..0d21ce620 100644 --- a/examples/dram_and_fsdax/dram_and_fsdax.c +++ b/examples/dram_and_fsdax/dram_and_fsdax.c @@ -67,12 +67,23 @@ static umf_memory_pool_handle_t create_fsdax_pool(const char *path) { // so it should be used with a pool manager that will take over // the managing of the provided memory - for example the jemalloc pool // with the `disable_provider_free` parameter set to true. - umf_jemalloc_pool_params_t pool_params; - pool_params.disable_provider_free = true; + umf_jemalloc_pool_params_handle_t pool_params; + umf_result = umfJemallocPoolParamsCreate(&pool_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to create jemalloc params!\n"); + umfMemoryProviderDestroy(provider_fsdax); + return NULL; + } + umf_result = umfJemallocPoolParamsSetKeepAllMemory(pool_params, true); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to set KeepAllMemory!\n"); + umfMemoryProviderDestroy(provider_fsdax); + return NULL; + } // Create an FSDAX memory pool umf_result = - umfPoolCreate(umfJemallocPoolOps(), provider_fsdax, &pool_params, + umfPoolCreate(umfJemallocPoolOps(), provider_fsdax, pool_params, UMF_POOL_CREATE_FLAG_OWN_PROVIDER, &pool_fsdax); if (umf_result != UMF_RESULT_SUCCESS) { fprintf(stderr, "Failed to create an FSDAX memory pool!\n"); @@ -80,6 +91,11 @@ static umf_memory_pool_handle_t create_fsdax_pool(const char *path) { return NULL; } + umf_result = umfJemallocPoolParamsDestroy(pool_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to destroy jemalloc params!\n"); + } + return pool_fsdax; } diff --git a/include/umf/pools/pool_jemalloc.h b/include/umf/pools/pool_jemalloc.h index dfd75746b..0cbecd38f 100644 --- a/include/umf/pools/pool_jemalloc.h +++ b/include/umf/pools/pool_jemalloc.h @@ -17,11 +17,31 @@ extern "C" { #include #include -/// @brief Configuration of Jemalloc Pool -typedef struct umf_jemalloc_pool_params_t { - /// Set to true if umfMemoryProviderFree() should never be called. - bool disable_provider_free; -} umf_jemalloc_pool_params_t; +struct umf_jemalloc_pool_params_t; + +/// @brief handle to the parameters of the jemalloc pool. +typedef struct umf_jemalloc_pool_params_t *umf_jemalloc_pool_params_handle_t; + +/// @brief Create a struct to store parameters of jemalloc pool. +/// @param hParams [out] handle to the newly created parameters struct. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t +umfJemallocPoolParamsCreate(umf_jemalloc_pool_params_handle_t *hParams); + +/// @brief Destroy parameters struct. +/// @param hParams handle to the parameters of the jemalloc pool. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t +umfJemallocPoolParamsDestroy(umf_jemalloc_pool_params_handle_t hParams); + +/// @brief Set if \p umfMemoryProviderFree() should never be called. +/// @param hParams handle to the parameters of the jemalloc pool. +/// @param keepAllMemory \p true if the jemalloc pool should not call +/// \p umfMemoryProviderFree, \p false otherwise. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t +umfJemallocPoolParamsSetKeepAllMemory(umf_jemalloc_pool_params_handle_t hParams, + bool keepAllMemory); umf_memory_pool_ops_t *umfJemallocPoolOps(void); diff --git a/src/pool/pool_jemalloc.c b/src/pool/pool_jemalloc.c index fa1022e83..3ec7c7805 100644 --- a/src/pool/pool_jemalloc.c +++ b/src/pool/pool_jemalloc.c @@ -41,6 +41,12 @@ typedef struct jemalloc_memory_pool_t { bool disable_provider_free; } jemalloc_memory_pool_t; +// Configuration of Jemalloc Pool +typedef struct umf_jemalloc_pool_params_t { + /// Set to true if umfMemoryProviderFree() should never be called. + bool disable_provider_free; +} umf_jemalloc_pool_params_t; + static __TLS umf_result_t TLS_last_allocation_error; static jemalloc_memory_pool_t *pool_by_arena_index[MALLCTL_ARENAS_ALL]; @@ -53,6 +59,52 @@ static jemalloc_memory_pool_t *get_pool_by_arena_index(unsigned arena_ind) { return pool_by_arena_index[arena_ind]; } +umf_result_t +umfJemallocPoolParamsCreate(umf_jemalloc_pool_params_handle_t *hParams) { + if (!hParams) { + LOG_ERR("jemalloc pool params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + umf_jemalloc_pool_params_t *params_data = + umf_ba_global_alloc(sizeof(*params_data)); + if (!params_data) { + LOG_ERR("cannot allocate memory for jemalloc poolparams"); + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + params_data->disable_provider_free = false; + + *hParams = (umf_jemalloc_pool_params_handle_t)params_data; + + return UMF_RESULT_SUCCESS; +} + +umf_result_t +umfJemallocPoolParamsDestroy(umf_jemalloc_pool_params_handle_t hParams) { + if (!hParams) { + LOG_ERR("jemalloc pool params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + umf_ba_global_free(hParams); + + return UMF_RESULT_SUCCESS; +} + +umf_result_t +umfJemallocPoolParamsSetKeepAllMemory(umf_jemalloc_pool_params_handle_t hParams, + bool keepAllMemory) { + if (!hParams) { + LOG_ERR("jemalloc pool params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + hParams->disable_provider_free = keepAllMemory; + + return UMF_RESULT_SUCCESS; +} + // arena_extent_alloc - an extent allocation function conforms to the extent_alloc_t type and upon // success returns a pointer to size bytes of mapped memory on behalf of arena arena_ind such that // the extent's base address is a multiple of alignment, as well as setting *zero to indicate @@ -401,8 +453,8 @@ static umf_result_t op_initialize(umf_memory_provider_handle_t provider, assert(provider); assert(out_pool); - umf_jemalloc_pool_params_t *je_params = - (umf_jemalloc_pool_params_t *)params; + umf_jemalloc_pool_params_handle_t je_params = + (umf_jemalloc_pool_params_handle_t)params; extent_hooks_t *pHooks = &arena_extent_hooks; size_t unsigned_size = sizeof(unsigned); diff --git a/test/pools/jemalloc_pool.cpp b/test/pools/jemalloc_pool.cpp index 8659e9836..3a78c5371 100644 --- a/test/pools/jemalloc_pool.cpp +++ b/test/pools/jemalloc_pool.cpp @@ -42,3 +42,122 @@ TEST_F(test, metadataNotAllocatedUsingProvider) { [pool = pool.get()](void *ptr) { umfPoolFree(pool, ptr); }); } } + +using jemallocPoolParams = bool; +struct umfJemallocPoolParamsTest + : umf_test::test, + ::testing::WithParamInterface { + + struct validation_params_t { + bool keep_all_memory; + }; + + struct provider_validator : public umf_test::provider_ba_global { + using base_provider = umf_test::provider_ba_global; + + umf_result_t initialize(validation_params_t *params) { + EXPECT_NE(params, nullptr); + expected_params = params; + return UMF_RESULT_SUCCESS; + } + umf_result_t free(void *ptr, size_t size) { + EXPECT_EQ(expected_params->keep_all_memory, false); + return base_provider::free(ptr, size); + } + + validation_params_t *expected_params; + }; + + static constexpr umf_memory_provider_ops_t VALIDATOR_PROVIDER_OPS = + umf::providerMakeCOps(); + + umfJemallocPoolParamsTest() : expected_params{false}, params(nullptr) {} + void SetUp() override { + test::SetUp(); + expected_params.keep_all_memory = this->GetParam(); + umf_result_t ret = umfJemallocPoolParamsCreate(¶ms); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ret = umfJemallocPoolParamsSetKeepAllMemory( + params, expected_params.keep_all_memory); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + } + + void TearDown() override { + umfJemallocPoolParamsDestroy(params); + test::TearDown(); + } + + umf::pool_unique_handle_t makePool() { + umf_memory_provider_handle_t hProvider = nullptr; + umf_memory_pool_handle_t hPool = nullptr; + + auto ret = umfMemoryProviderCreate(&VALIDATOR_PROVIDER_OPS, + &expected_params, &hProvider); + EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + + ret = umfPoolCreate(umfJemallocPoolOps(), hProvider, params, + UMF_POOL_CREATE_FLAG_OWN_PROVIDER, &hPool); + EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + + return umf::pool_unique_handle_t(hPool, &umfPoolDestroy); + } + + void allocFreeFlow() { + static const size_t ALLOC_SIZE = 128; + static const size_t NUM_ALLOCATIONS = 100; + std::vector ptrs; + + auto pool = makePool(); + ASSERT_NE(pool, nullptr); + + for (size_t i = 0; i < NUM_ALLOCATIONS; ++i) { + auto *ptr = umfPoolMalloc(pool.get(), ALLOC_SIZE); + ASSERT_NE(ptr, nullptr); + ptrs.push_back(ptr); + } + + for (size_t i = 0; i < NUM_ALLOCATIONS; ++i) { + auto ret = umfPoolFree(pool.get(), ptrs[i]); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + } + + // Now pool can call free during pool destruction + expected_params.keep_all_memory = false; + } + + validation_params_t expected_params; + umf_jemalloc_pool_params_handle_t params; +}; + +TEST_P(umfJemallocPoolParamsTest, allocFree) { allocFreeFlow(); } + +TEST_P(umfJemallocPoolParamsTest, updateParams) { + expected_params.keep_all_memory = !expected_params.keep_all_memory; + umf_result_t ret = umfJemallocPoolParamsSetKeepAllMemory( + params, expected_params.keep_all_memory); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + allocFreeFlow(); +} + +TEST_P(umfJemallocPoolParamsTest, invalidParams) { + umf_result_t ret = umfJemallocPoolParamsCreate(nullptr); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + ret = umfJemallocPoolParamsSetKeepAllMemory(nullptr, true); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + ret = umfJemallocPoolParamsSetKeepAllMemory(nullptr, false); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + ret = umfJemallocPoolParamsDestroy(nullptr); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(umfJemallocPoolParamsTest); + +/* TODO: enable this test after the issue #903 is fixed. +(https://github.com/oneapi-src/unified-memory-framework/issues/903) +INSTANTIATE_TEST_SUITE_P(jemallocPoolTest, umfJemallocPoolParamsTest, + testing::Values(false, true)); +*/ From 9d74c17b7ef864bfe306c271e6377e3d43479c93 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Fri, 15 Nov 2024 14:00:38 +0100 Subject: [PATCH 308/352] Update disjoint pool params implementation --- benchmark/multithread.cpp | 15 +- benchmark/ubench.c | 101 +++++++-- .../cuda_shared_memory/cuda_shared_memory.c | 46 +++- examples/ipc_level_zero/ipc_level_zero.c | 18 +- .../level_zero_shared_memory.c | 46 +++- include/umf/pools/pool_disjoint.h | 135 +++++++----- src/pool/pool_disjoint.cpp | 196 +++++++++++++++++- test/c_api/disjoint_pool.c | 22 +- test/c_api/multi_pool.c | 12 +- test/disjointCoarseMallocPool.cpp | 123 ++++++++--- test/pools/disjoint_pool.cpp | 154 +++++++++++--- test/provider_os_memory.cpp | 46 +++- test/providers/ipc_cuda_prov_consumer.c | 18 +- test/providers/ipc_cuda_prov_producer.c | 18 +- test/providers/ipc_level_zero_prov_consumer.c | 18 +- test/providers/ipc_level_zero_prov_producer.c | 18 +- 16 files changed, 789 insertions(+), 197 deletions(-) diff --git a/benchmark/multithread.cpp b/benchmark/multithread.cpp index 8239c8cd4..c698ed045 100644 --- a/benchmark/multithread.cpp +++ b/benchmark/multithread.cpp @@ -117,10 +117,15 @@ int main() { #endif #if defined(UMF_BUILD_LIBUMF_POOL_DISJOINT) - auto disjointParams = umfDisjointPoolParamsDefault(); + umf_disjoint_pool_params_handle_t hDisjointParams = nullptr; + umf_result_t ret = umfDisjointPoolParamsCreate(&hDisjointParams); + if (ret != UMF_RESULT_SUCCESS) { + std::cerr << "disjoint pool params create failed" << std::endl; + return -1; + } std::cout << "disjoint_pool mt_alloc_free: "; - mt_alloc_free(poolCreateExtParams{umfDisjointPoolOps(), &disjointParams, + mt_alloc_free(poolCreateExtParams{umfDisjointPoolOps(), hDisjointParams, umfOsMemoryProviderOps(), &osParams}); #else std::cout << "skipping disjoint_pool mt_alloc_free" << std::endl; @@ -129,5 +134,11 @@ int main() { // ctest looks for "PASSED" in the output std::cout << "PASSED" << std::endl; + ret = umfDisjointPoolParamsDestroy(hDisjointParams); + if (ret != UMF_RESULT_SUCCESS) { + std::cerr << "disjoint pool params destroy failed" << std::endl; + return -1; + } + return 0; } diff --git a/benchmark/ubench.c b/benchmark/ubench.c index 15890d4e9..0ac174de6 100644 --- a/benchmark/ubench.c +++ b/benchmark/ubench.c @@ -260,16 +260,47 @@ UBENCH_EX(simple, disjoint_pool_with_os_memory_provider) { exit(-1); } - umf_disjoint_pool_params_t disjoint_memory_pool_params = {0}; - disjoint_memory_pool_params.SlabMinSize = DISJOINT_POOL_SLAB_MIN_SIZE; - disjoint_memory_pool_params.MaxPoolableSize = - DISJOINT_POOL_MAX_POOLABLE_SIZE; - disjoint_memory_pool_params.Capacity = DISJOINT_POOL_CAPACITY; - disjoint_memory_pool_params.MinBucketSize = DISJOINT_POOL_MIN_BUCKET_SIZE; + umf_disjoint_pool_params_handle_t disjoint_memory_pool_params = NULL; + umf_result = umfDisjointPoolParamsCreate(&disjoint_memory_pool_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "ERROR: umfDisjointPoolParamsCreate failed\n"); + exit(-1); + } + + umf_result = umfDisjointPoolParamsSetSlabMinSize( + disjoint_memory_pool_params, DISJOINT_POOL_SLAB_MIN_SIZE); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, + "error: umfDisjointPoolParamsSetSlabMinSize() failed\n"); + exit(-1); + } + + umf_result = umfDisjointPoolParamsSetMaxPoolableSize( + disjoint_memory_pool_params, DISJOINT_POOL_MAX_POOLABLE_SIZE); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, + "error: umfDisjointPoolParamsSetMaxPoolableSize() failed\n"); + exit(-1); + } + + umf_result = umfDisjointPoolParamsSetCapacity(disjoint_memory_pool_params, + DISJOINT_POOL_CAPACITY); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "error: umfDisjointPoolParamsSetCapacity() failed\n"); + exit(-1); + } + + umf_result = umfDisjointPoolParamsSetMinBucketSize( + disjoint_memory_pool_params, DISJOINT_POOL_MIN_BUCKET_SIZE); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, + "error: umfDisjointPoolParamsSetMinBucketSize() failed\n"); + exit(-1); + } umf_memory_pool_handle_t disjoint_pool; umf_result = umfPoolCreate(umfDisjointPoolOps(), os_memory_provider, - &disjoint_memory_pool_params, 0, &disjoint_pool); + disjoint_memory_pool_params, 0, &disjoint_pool); if (umf_result != UMF_RESULT_SUCCESS) { fprintf(stderr, "error: umfPoolCreate() failed\n"); exit(-1); @@ -284,6 +315,7 @@ UBENCH_EX(simple, disjoint_pool_with_os_memory_provider) { } umfPoolDestroy(disjoint_pool); + umfDisjointPoolParamsDestroy(disjoint_memory_pool_params); umfMemoryProviderDestroy(os_memory_provider); free(array); } @@ -458,19 +490,50 @@ UBENCH_EX(ipc, disjoint_pool_with_level_zero_provider) { goto err_free_ipc_handles; } - umf_disjoint_pool_params_t disjoint_params = {0}; - disjoint_params.SlabMinSize = BUFFER_SIZE * 10; - disjoint_params.MaxPoolableSize = 4ull * 1024ull * 1024ull; - disjoint_params.Capacity = 64ull * 1024ull; - disjoint_params.MinBucketSize = 64; - umf_pool_create_flags_t flags = UMF_POOL_CREATE_FLAG_OWN_PROVIDER; + umf_disjoint_pool_params_handle_t disjoint_params = NULL; + umf_result = umfDisjointPoolParamsCreate(&disjoint_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "ERROR: umfDisjointPoolParamsCreate failed\n"); + goto err_provider_destroy; + } + + umf_result = + umfDisjointPoolParamsSetSlabMinSize(disjoint_params, BUFFER_SIZE * 10); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, + "error: umfDisjointPoolParamsSetSlabMinSize() failed\n"); + goto err_params_destroy; + } + + umf_result = umfDisjointPoolParamsSetMaxPoolableSize( + disjoint_params, 4ull * 1024ull * 1024ull); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, + "error: umfDisjointPoolParamsSetMaxPoolableSize() failed\n"); + goto err_params_destroy; + } + + umf_result = + umfDisjointPoolParamsSetCapacity(disjoint_params, 64ull * 1024ull); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "error: umfDisjointPoolParamsSetCapacity() failed\n"); + goto err_params_destroy; + } + + umf_result = umfDisjointPoolParamsSetMinBucketSize(disjoint_params, 64); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, + "error: umfDisjointPoolParamsSetMinBucketSize() failed\n"); + goto err_params_destroy; + } + + umf_pool_create_flags_t flags = UMF_POOL_CREATE_FLAG_NONE; umf_memory_pool_handle_t pool; - umf_result = umfPoolCreate(umfDisjointPoolOps(), provider, &disjoint_params, + umf_result = umfPoolCreate(umfDisjointPoolOps(), provider, disjoint_params, flags, &pool); if (umf_result != UMF_RESULT_SUCCESS) { fprintf(stderr, "error: umfPoolCreate() failed\n"); - umfMemoryProviderDestroy(provider); - goto err_free_ipc_handles; + goto err_params_destroy; } for (size_t i = 0; i < N_BUFFERS; ++i) { @@ -495,6 +558,12 @@ UBENCH_EX(ipc, disjoint_pool_with_level_zero_provider) { umfPoolDestroy(pool); +err_params_destroy: + umfDisjointPoolParamsDestroy(disjoint_params); + +err_provider_destroy: + umfMemoryProviderDestroy(provider); + err_free_ipc_handles: free(ipc_handles); diff --git a/examples/cuda_shared_memory/cuda_shared_memory.c b/examples/cuda_shared_memory/cuda_shared_memory.c index 55a7dd12f..22e5e3f10 100644 --- a/examples/cuda_shared_memory/cuda_shared_memory.c +++ b/examples/cuda_shared_memory/cuda_shared_memory.c @@ -67,23 +67,48 @@ int main(void) { // Setup parameters for the Disjoint Pool. It will be used for managing the // memory allocated using memory provider. - umf_disjoint_pool_params_t disjoint_memory_pool_params = - umfDisjointPoolParamsDefault(); + umf_disjoint_pool_params_handle_t hDisjointParams = NULL; + res = umfDisjointPoolParamsCreate(&hDisjointParams); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "disjoint pool params create failed\n"); + ret = -1; + goto memory_provider_destroy; + } // Set the Slab Min Size to 64KB - the page size for GPU allocations - disjoint_memory_pool_params.SlabMinSize = 64 * 1024L; + res = umfDisjointPoolParamsSetSlabMinSize(hDisjointParams, 64 * 1024L); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to set the slab min size!\n"); + ret = -1; + goto pool_params_destroy; + } // We would keep only single slab per each allocation bucket - disjoint_memory_pool_params.Capacity = 1; + res = umfDisjointPoolParamsSetCapacity(hDisjointParams, 1); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to set the capacity!\n"); + ret = -1; + goto pool_params_destroy; + } // Set the maximum poolable size to 64KB - objects with size above this // limit will not be stored/allocated from the pool. - disjoint_memory_pool_params.MaxPoolableSize = 64 * 1024L; + res = umfDisjointPoolParamsSetMaxPoolableSize(hDisjointParams, 64 * 1024L); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to set the max poolable size!\n"); + ret = -1; + goto pool_params_destroy; + } // Enable tracing - disjoint_memory_pool_params.PoolTrace = 1; + res = umfDisjointPoolParamsSetTrace(hDisjointParams, 1); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to set the pool trace!\n"); + ret = -1; + goto pool_params_destroy; + } // Create Disjoint Pool memory pool. umf_memory_pool_handle_t cu_disjoint_memory_pool; - res = umfPoolCreate(umfDisjointPoolOps(), cu_memory_provider, - &disjoint_memory_pool_params, UMF_POOL_CREATE_FLAG_NONE, - &cu_disjoint_memory_pool); + res = + umfPoolCreate(umfDisjointPoolOps(), cu_memory_provider, hDisjointParams, + UMF_POOL_CREATE_FLAG_NONE, &cu_disjoint_memory_pool); if (res != UMF_RESULT_SUCCESS) { fprintf(stderr, "Failed to create a memory pool!\n"); ret = -1; @@ -116,6 +141,9 @@ int main(void) { memory_pool_destroy: umfPoolDestroy(cu_disjoint_memory_pool); +pool_params_destroy: + umfDisjointPoolParamsDestroy(hDisjointParams); + memory_provider_destroy: umfMemoryProviderDestroy(cu_memory_provider); diff --git a/examples/ipc_level_zero/ipc_level_zero.c b/examples/ipc_level_zero/ipc_level_zero.c index 9a6b4177b..cfab57b0d 100644 --- a/examples/ipc_level_zero/ipc_level_zero.c +++ b/examples/ipc_level_zero/ipc_level_zero.c @@ -35,17 +35,29 @@ int create_level_zero_pool(ze_context_handle_t context, return -1; } + umf_disjoint_pool_params_handle_t disjoint_params = NULL; + umf_result = umfDisjointPoolParamsCreate(&disjoint_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "ERROR: Failed to create pool params!\n"); + goto provider_destroy; + } + // create pool umf_pool_create_flags_t flags = UMF_POOL_CREATE_FLAG_OWN_PROVIDER; - umf_disjoint_pool_params_t disjoint_params = umfDisjointPoolParamsDefault(); - umf_result = umfPoolCreate(umfDisjointPoolOps(), provider, &disjoint_params, + umf_result = umfPoolCreate(umfDisjointPoolOps(), provider, disjoint_params, flags, pool); + umfDisjointPoolParamsDestroy(disjoint_params); if (umf_result != UMF_RESULT_SUCCESS) { fprintf(stderr, "ERROR: Failed to create pool!\n"); - return -1; + goto provider_destroy; } return 0; + +provider_destroy: + umfMemoryProviderDestroy(provider); + + return -1; } int main(void) { diff --git a/examples/level_zero_shared_memory/level_zero_shared_memory.c b/examples/level_zero_shared_memory/level_zero_shared_memory.c index 06413a018..1a38beceb 100644 --- a/examples/level_zero_shared_memory/level_zero_shared_memory.c +++ b/examples/level_zero_shared_memory/level_zero_shared_memory.c @@ -72,27 +72,54 @@ int main(void) { // Setup parameters for the Disjoint Pool. It will be used for managing the // memory allocated using memory provider. - umf_disjoint_pool_params_t disjoint_memory_pool_params = - umfDisjointPoolParamsDefault(); + umf_disjoint_pool_params_handle_t disjoint_memory_pool_params = NULL; + res = umfDisjointPoolParamsCreate(&disjoint_memory_pool_params); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to create pool params!\n"); + ret = -1; + goto memory_provider_destroy; + } // Set the Slab Min Size to 64KB - the page size for GPU allocations - disjoint_memory_pool_params.SlabMinSize = 64 * 1024L; + res = umfDisjointPoolParamsSetSlabMinSize(disjoint_memory_pool_params, + 64 * 1024L); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to set Slab Min Size!\n"); + ret = -1; + goto disjoint_params_destroy; + } // We would keep only single slab per each allocation bucket - disjoint_memory_pool_params.Capacity = 1; + res = umfDisjointPoolParamsSetCapacity(disjoint_memory_pool_params, 1); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to set Capacity!\n"); + ret = -1; + goto disjoint_params_destroy; + } // Set the maximum poolable size to 64KB - objects with size above this // limit will not be stored/allocated from the pool. - disjoint_memory_pool_params.MaxPoolableSize = 64 * 1024L; + res = umfDisjointPoolParamsSetMaxPoolableSize(disjoint_memory_pool_params, + 64 * 1024L); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to set Max Poolable Size!\n"); + ret = -1; + goto disjoint_params_destroy; + } // Enable tracing - disjoint_memory_pool_params.PoolTrace = 1; + res = umfDisjointPoolParamsSetTrace(disjoint_memory_pool_params, 1); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to set Trace!\n"); + ret = -1; + goto disjoint_params_destroy; + } // Create Disjoint Pool memory pool. umf_memory_pool_handle_t ze_disjoint_memory_pool; res = umfPoolCreate(umfDisjointPoolOps(), ze_memory_provider, - &disjoint_memory_pool_params, UMF_POOL_CREATE_FLAG_NONE, + disjoint_memory_pool_params, UMF_POOL_CREATE_FLAG_NONE, &ze_disjoint_memory_pool); if (res != UMF_RESULT_SUCCESS) { fprintf(stderr, "Failed to create a memory pool!\n"); ret = -1; - goto memory_provider_destroy; + goto disjoint_params_destroy; } printf("Disjoint Pool created at %p\n", (void *)ze_disjoint_memory_pool); @@ -121,6 +148,9 @@ int main(void) { memory_pool_destroy: umfPoolDestroy(ze_disjoint_memory_pool); +disjoint_params_destroy: + umfDisjointPoolParamsDestroy(disjoint_memory_pool_params); + memory_provider_destroy: umfMemoryProviderDestroy(ze_memory_provider); diff --git a/include/umf/pools/pool_disjoint.h b/include/umf/pools/pool_disjoint.h index 2fe5355a2..fdf682ae5 100644 --- a/include/umf/pools/pool_disjoint.h +++ b/include/umf/pools/pool_disjoint.h @@ -16,68 +16,93 @@ extern "C" { /// i.e. if multiple pools use the same shared limits, sum of those pools' /// sizes cannot exceed MaxSize. typedef struct umf_disjoint_pool_shared_limits_t - umf_disjoint_pool_shared_limits_t; + *umf_disjoint_pool_shared_limits_handle_t; -/// @brief Create a pool limits struct -/// @param MaxSize specifies hard limit for memory allocated from a provider -/// @return pointer to created pool limits struct -umf_disjoint_pool_shared_limits_t * +struct umf_disjoint_pool_params_t; +/// @brief handle to the parameters of the disjoint pool. +typedef struct umf_disjoint_pool_params_t *umf_disjoint_pool_params_handle_t; + +/// @brief Create a pool limits struct. +/// @param MaxSize specifies hard limit for memory allocated from a provider. +/// @return handle to the created shared limits struct. +umf_disjoint_pool_shared_limits_handle_t umfDisjointPoolSharedLimitsCreate(size_t MaxSize); -/// @brief Destroy previously created pool limits struct -/// @param PoolLimits pointer to a pool limits struct +/// @brief Destroy previously created pool limits struct. +/// @param hSharedLimits handle to the shared limits struct. void umfDisjointPoolSharedLimitsDestroy( - umf_disjoint_pool_shared_limits_t *PoolLimits); - -/// @brief Configuration of Disjoint Pool -typedef struct umf_disjoint_pool_params_t { - /// Minimum allocation size that will be requested from the system. - /// By default this is the minimum allocation size of each memory type. - size_t SlabMinSize; - - /// Allocations up to this limit will be subject to chunking/pooling - size_t MaxPoolableSize; - - /// When pooling, each bucket will hold a max of 'Capacity' unfreed slabs - size_t Capacity; - - /// Holds the minimum bucket size valid for allocation of a memory type. - /// This value must be a power of 2. - size_t MinBucketSize; - - /// Holds size of the pool managed by the allocator. - size_t CurPoolSize; - - /// Whether to print pool usage statistics - int PoolTrace; - - /// Memory limits that can be shared between multitple pool instances, - /// i.e. if multiple pools use the same SharedLimits sum of those pools' - /// sizes cannot exceed MaxSize. - umf_disjoint_pool_shared_limits_t *SharedLimits; - - /// Name used in traces - const char *Name; -} umf_disjoint_pool_params_t; + umf_disjoint_pool_shared_limits_handle_t hSharedLimits); + +/// @brief Create a struct to store parameters of disjoint pool. +/// @param hParams [out] handle to the newly created parameters struct. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t +umfDisjointPoolParamsCreate(umf_disjoint_pool_params_handle_t *hParams); + +/// @brief Destroy parameters struct. +/// @param hParams handle to the parameters of the disjoint pool. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t +umfDisjointPoolParamsDestroy(umf_disjoint_pool_params_handle_t hParams); + +/// @brief Set minimum allocation size that will be requested from the memory provider. +/// @param hParams handle to the parameters of the disjoint pool. +/// @param slabMinSize minimum allocation size. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t +umfDisjointPoolParamsSetSlabMinSize(umf_disjoint_pool_params_handle_t hParams, + size_t slabMinSize); + +/// @brief Set size limit for allocations that are subject to pooling. +/// @param hParams handle to the parameters of the disjoint pool. +/// @param maxPoolableSize maximum poolable size. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfDisjointPoolParamsSetMaxPoolableSize( + umf_disjoint_pool_params_handle_t hParams, size_t maxPoolableSize); + +/// @brief Set maximum capacity of each bucket. Each bucket will hold a +/// max of \p maxCapacity unfreed slabs. +/// @param hParams handle to the parameters of the disjoint pool. +/// @param maxCapacity maximum capacity of each bucket. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t +umfDisjointPoolParamsSetCapacity(umf_disjoint_pool_params_handle_t hParams, + size_t maxCapacity); + +/// @brief Set minimum bucket allocation size. +/// @param hParams handle to the parameters of the disjoint pool. +/// @param minBucketSize minimum bucket size. Must be power of 2. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t +umfDisjointPoolParamsSetMinBucketSize(umf_disjoint_pool_params_handle_t hParams, + size_t minBucketSize); + +/// @brief Set trace level for pool usage statistics. +/// @param hParams handle to the parameters of the disjoint pool. +/// @param poolTrace trace level. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t +umfDisjointPoolParamsSetTrace(umf_disjoint_pool_params_handle_t hParams, + int poolTrace); + +/// @brief Set shared limits for disjoint pool. +/// @param hParams handle to the parameters of the disjoint pool. +/// @param hSharedLimits handle tp the shared limits. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfDisjointPoolParamsSetSharedLimits( + umf_disjoint_pool_params_handle_t hParams, + umf_disjoint_pool_shared_limits_handle_t hSharedLimits); + +/// @brief Set custom name of the disjoint pool to be used in the traces. +/// @param hParams handle to the parameters of the disjoint pool. +/// @param name custom name of the pool. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t +umfDisjointPoolParamsSetName(umf_disjoint_pool_params_handle_t hParams, + const char *name); umf_memory_pool_ops_t *umfDisjointPoolOps(void); -/// @brief Create default params struct for disjoint pool -static inline umf_disjoint_pool_params_t umfDisjointPoolParamsDefault(void) { - umf_disjoint_pool_params_t params = { - 0, /* SlabMinSize */ - 0, /* MaxPoolableSize */ - 0, /* Capacity */ - UMF_DISJOINT_POOL_MIN_BUCKET_DEFAULT_SIZE, /* MinBucketSize */ - 0, /* CurPoolSize */ - 0, /* PoolTrace */ - NULL, /* SharedLimits */ - "disjoint_pool" /* Name */ - }; - - return params; -} - #ifdef __cplusplus } #endif diff --git a/src/pool/pool_disjoint.cpp b/src/pool/pool_disjoint.cpp index 2cf8df7a4..e0298b43d 100644 --- a/src/pool/pool_disjoint.cpp +++ b/src/pool/pool_disjoint.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -57,13 +58,43 @@ typedef struct umf_disjoint_pool_shared_limits_t { std::atomic TotalSize; } umf_disjoint_pool_shared_limits_t; +// Configuration of Disjoint Pool +typedef struct umf_disjoint_pool_params_t { + // Minimum allocation size that will be requested from the memory provider. + size_t SlabMinSize; + + // Allocations up to this limit will be subject to chunking/pooling + size_t MaxPoolableSize; + + // When pooling, each bucket will hold a max of 'Capacity' unfreed slabs + size_t Capacity; + + // Holds the minimum bucket size valid for allocation of a memory type. + // This value must be a power of 2. + size_t MinBucketSize; + + // Holds size of the pool managed by the allocator. + size_t CurPoolSize; + + // Whether to print pool usage statistics + int PoolTrace; + + // Memory limits that can be shared between multitple pool instances, + // i.e. if multiple pools use the same SharedLimits sum of those pools' + // sizes cannot exceed MaxSize. + umf_disjoint_pool_shared_limits_handle_t SharedLimits; + + // Name used in traces + char *Name; +} umf_disjoint_pool_params_t; + class DisjointPool { public: class AllocImpl; using Config = umf_disjoint_pool_params_t; umf_result_t initialize(umf_memory_provider_handle_t provider, - umf_disjoint_pool_params_t *parameters); + umf_disjoint_pool_params_handle_t parameters); void *malloc(size_t size); void *calloc(size_t, size_t); void *realloc(void *, size_t); @@ -85,8 +116,151 @@ umfDisjointPoolSharedLimitsCreate(size_t MaxSize) { } void umfDisjointPoolSharedLimitsDestroy( - umf_disjoint_pool_shared_limits_t *limits) { - delete limits; + umf_disjoint_pool_shared_limits_handle_t hSharedLimits) { + delete hSharedLimits; +} + +umf_result_t +umfDisjointPoolParamsCreate(umf_disjoint_pool_params_handle_t *hParams) { + static const char *DEFAULT_NAME = "disjoint_pool"; + + if (!hParams) { + LOG_ERR("disjoint pool params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + umf_disjoint_pool_params_handle_t params = new umf_disjoint_pool_params_t{}; + if (params == nullptr) { + LOG_ERR("cannot allocate memory for disjoint pool params"); + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + params->SlabMinSize = 0; + params->MaxPoolableSize = 0; + params->Capacity = 0; + params->MinBucketSize = UMF_DISJOINT_POOL_MIN_BUCKET_DEFAULT_SIZE; + params->CurPoolSize = 0; + params->PoolTrace = 0; + params->SharedLimits = nullptr; + params->Name = nullptr; + + umf_result_t ret = umfDisjointPoolParamsSetName(params, DEFAULT_NAME); + if (ret != UMF_RESULT_SUCCESS) { + delete params; + return ret; + } + + *hParams = params; + + return UMF_RESULT_SUCCESS; +} + +umf_result_t +umfDisjointPoolParamsDestroy(umf_disjoint_pool_params_handle_t hParams) { + if (hParams) { + delete[] hParams->Name; + delete hParams; + } + + return UMF_RESULT_SUCCESS; +} + +umf_result_t +umfDisjointPoolParamsSetSlabMinSize(umf_disjoint_pool_params_handle_t hParams, + size_t slabMinSize) { + if (!hParams) { + LOG_ERR("disjoint pool params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + hParams->SlabMinSize = slabMinSize; + return UMF_RESULT_SUCCESS; +} + +umf_result_t umfDisjointPoolParamsSetMaxPoolableSize( + umf_disjoint_pool_params_handle_t hParams, size_t maxPoolableSize) { + if (!hParams) { + LOG_ERR("disjoint pool params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + hParams->MaxPoolableSize = maxPoolableSize; + return UMF_RESULT_SUCCESS; +} + +umf_result_t +umfDisjointPoolParamsSetCapacity(umf_disjoint_pool_params_handle_t hParams, + size_t maxCapacity) { + if (!hParams) { + LOG_ERR("disjoint pool params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + hParams->Capacity = maxCapacity; + return UMF_RESULT_SUCCESS; +} + +umf_result_t +umfDisjointPoolParamsSetMinBucketSize(umf_disjoint_pool_params_handle_t hParams, + size_t minBucketSize) { + if (!hParams) { + LOG_ERR("disjoint pool params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + // minBucketSize parameter must be a power of 2 and greater than 0. + if (minBucketSize == 0 || (minBucketSize & (minBucketSize - 1))) { + LOG_ERR("minBucketSize must be a power of 2 and greater than 0"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + hParams->MinBucketSize = minBucketSize; + return UMF_RESULT_SUCCESS; +} + +umf_result_t +umfDisjointPoolParamsSetTrace(umf_disjoint_pool_params_handle_t hParams, + int poolTrace) { + if (!hParams) { + LOG_ERR("disjoint pool params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + hParams->PoolTrace = poolTrace; + return UMF_RESULT_SUCCESS; +} + +umf_result_t umfDisjointPoolParamsSetSharedLimits( + umf_disjoint_pool_params_handle_t hParams, + umf_disjoint_pool_shared_limits_handle_t hSharedLimits) { + if (!hParams) { + LOG_ERR("disjoint pool params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + hParams->SharedLimits = hSharedLimits; + return UMF_RESULT_SUCCESS; +} + +umf_result_t +umfDisjointPoolParamsSetName(umf_disjoint_pool_params_handle_t hParams, + const char *name) { + if (!hParams) { + LOG_ERR("disjoint pool params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + char *newName = new char[std::strlen(name) + 1]; + if (newName == nullptr) { + LOG_ERR("cannot allocate memory for disjoint pool name"); + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + delete[] hParams->Name; + hParams->Name = newName; + std::strcpy(hParams->Name, name); + + return UMF_RESULT_SUCCESS; } // Allocations are a minimum of 4KB/64KB/2MB even when a smaller size is @@ -351,11 +525,15 @@ class DisjointPool::AllocImpl { public: AllocImpl(umf_memory_provider_handle_t hProvider, - umf_disjoint_pool_params_t *params) + umf_disjoint_pool_params_handle_t params) : MemHandle{hProvider}, params(*params) { VALGRIND_DO_CREATE_MEMPOOL(this, 0, 0); + // deep copy of the Name + this->params.Name = new char[std::strlen(params->Name) + 1]; + std::strcpy(this->params.Name, params->Name); + // Generate buckets sized such as: 64, 96, 128, 192, ..., CutOff. // Powers of 2 and the value halfway between the powers of 2. auto Size1 = this->params.MinBucketSize; @@ -379,7 +557,10 @@ class DisjointPool::AllocImpl { } } - ~AllocImpl() { VALGRIND_DO_DESTROY_MEMPOOL(this); } + ~AllocImpl() { + VALGRIND_DO_DESTROY_MEMPOOL(this); + delete[] this->params.Name; + } void *allocate(size_t Size, size_t Alignment, bool &FromPool); void *allocate(size_t Size, bool &FromPool); @@ -1015,8 +1196,9 @@ void DisjointPool::AllocImpl::printStats(bool &TitlePrinted, } } -umf_result_t DisjointPool::initialize(umf_memory_provider_handle_t provider, - umf_disjoint_pool_params_t *parameters) { +umf_result_t +DisjointPool::initialize(umf_memory_provider_handle_t provider, + umf_disjoint_pool_params_handle_t parameters) { if (!provider) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; } diff --git a/test/c_api/disjoint_pool.c b/test/c_api/disjoint_pool.c index 13cd65ab0..4d4634def 100644 --- a/test/c_api/disjoint_pool.c +++ b/test/c_api/disjoint_pool.c @@ -13,12 +13,16 @@ void test_disjoint_pool_default_params(void) { umf_memory_provider_handle_t provider = nullProviderCreate(); umf_result_t retp; umf_memory_pool_handle_t pool = NULL; - umf_disjoint_pool_params_t params = umfDisjointPoolParamsDefault(); - retp = umfPoolCreate(umfDisjointPoolOps(), provider, ¶ms, 0, &pool); + umf_disjoint_pool_params_handle_t params = NULL; + + retp = umfDisjointPoolParamsCreate(¶ms); + UT_ASSERTeq(retp, UMF_RESULT_SUCCESS); + retp = umfPoolCreate(umfDisjointPoolOps(), provider, params, 0, &pool); UT_ASSERTeq(retp, UMF_RESULT_SUCCESS); umfPoolDestroy(pool); + umfDisjointPoolParamsDestroy(params); umfMemoryProviderDestroy(provider); } @@ -26,19 +30,25 @@ void test_disjoint_pool_shared_limits(void) { umf_memory_provider_handle_t provider = nullProviderCreate(); umf_result_t retp; umf_memory_pool_handle_t pool = NULL; - umf_disjoint_pool_params_t params = umfDisjointPoolParamsDefault(); + umf_disjoint_pool_params_handle_t params = NULL; + + retp = umfDisjointPoolParamsCreate(¶ms); + UT_ASSERTeq(retp, UMF_RESULT_SUCCESS); - umf_disjoint_pool_shared_limits_t *limits = + umf_disjoint_pool_shared_limits_handle_t limits = umfDisjointPoolSharedLimitsCreate(1024); - params.SharedLimits = limits; + UT_ASSERTne(limits, NULL); - retp = umfPoolCreate(umfDisjointPoolOps(), provider, ¶ms, 0, &pool); + retp = umfDisjointPoolParamsSetSharedLimits(params, limits); + UT_ASSERTeq(retp, UMF_RESULT_SUCCESS); + retp = umfPoolCreate(umfDisjointPoolOps(), provider, ¶ms, 0, &pool); UT_ASSERTeq(retp, UMF_RESULT_SUCCESS); umfPoolDestroy(pool); umfMemoryProviderDestroy(provider); umfDisjointPoolSharedLimitsDestroy(limits); + umfDisjointPoolParamsDestroy(params); } int main(void) { diff --git a/test/c_api/multi_pool.c b/test/c_api/multi_pool.c index 9b5f73e77..518f992ea 100644 --- a/test/c_api/multi_pool.c +++ b/test/c_api/multi_pool.c @@ -17,10 +17,16 @@ umf_memory_pool_handle_t createDisjointPool(umf_memory_provider_handle_t provider) { umf_memory_pool_handle_t pool = NULL; - umf_disjoint_pool_params_t params = umfDisjointPoolParamsDefault(); - umf_result_t ret = - umfPoolCreate(umfDisjointPoolOps(), provider, ¶ms, 0, &pool); + umf_disjoint_pool_params_handle_t params = NULL; + + umf_result_t ret = umfDisjointPoolParamsCreate(¶ms); + UT_ASSERTeq(ret, UMF_RESULT_SUCCESS); + + ret = umfPoolCreate(umfDisjointPoolOps(), provider, params, 0, &pool); UT_ASSERTeq(ret, UMF_RESULT_SUCCESS); + + umfDisjointPoolParamsDestroy(params); + return pool; } diff --git a/test/disjointCoarseMallocPool.cpp b/test/disjointCoarseMallocPool.cpp index 3c5ec6166..32e1d24f3 100644 --- a/test/disjointCoarseMallocPool.cpp +++ b/test/disjointCoarseMallocPool.cpp @@ -68,20 +68,34 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_basic) { ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(coarse_memory_provider, nullptr); - umf_disjoint_pool_params_t disjoint_memory_pool_params = {}; - disjoint_memory_pool_params.SlabMinSize = 4096; - disjoint_memory_pool_params.MaxPoolableSize = 4096; - disjoint_memory_pool_params.Capacity = 4; - disjoint_memory_pool_params.MinBucketSize = 64; - disjoint_memory_pool_params.PoolTrace = 1; + umf_disjoint_pool_params_handle_t disjoint_pool_params = NULL; + umf_result = umfDisjointPoolParamsCreate(&disjoint_pool_params); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(disjoint_pool_params, nullptr); + umf_result = + umfDisjointPoolParamsSetSlabMinSize(disjoint_pool_params, 4096); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = + umfDisjointPoolParamsSetMaxPoolableSize(disjoint_pool_params, 4096); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = umfDisjointPoolParamsSetCapacity(disjoint_pool_params, 4); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = + umfDisjointPoolParamsSetMinBucketSize(disjoint_pool_params, 64); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = umfDisjointPoolParamsSetTrace(disjoint_pool_params, 1); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); umf_memory_pool_handle_t pool; umf_result = umfPoolCreate(umfDisjointPoolOps(), coarse_memory_provider, - &disjoint_memory_pool_params, + disjoint_pool_params, UMF_POOL_CREATE_FLAG_OWN_PROVIDER, &pool); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(pool, nullptr); + umf_result = umfDisjointPoolParamsDestroy(disjoint_pool_params); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + // test umf_memory_provider_handle_t prov = NULL; @@ -245,20 +259,33 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_simple1) { ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(coarse_memory_provider, nullptr); - umf_disjoint_pool_params_t disjoint_memory_pool_params = {}; - disjoint_memory_pool_params.SlabMinSize = 4096; - disjoint_memory_pool_params.MaxPoolableSize = 4096; - disjoint_memory_pool_params.Capacity = 4; - disjoint_memory_pool_params.MinBucketSize = 64; - disjoint_memory_pool_params.PoolTrace = 1; + umf_disjoint_pool_params_handle_t disjoint_pool_params = NULL; + umf_result = umfDisjointPoolParamsCreate(&disjoint_pool_params); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(disjoint_pool_params, nullptr); + umf_result = + umfDisjointPoolParamsSetSlabMinSize(disjoint_pool_params, 4096); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = + umfDisjointPoolParamsSetMaxPoolableSize(disjoint_pool_params, 4096); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = umfDisjointPoolParamsSetCapacity(disjoint_pool_params, 4); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = + umfDisjointPoolParamsSetMinBucketSize(disjoint_pool_params, 64); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = umfDisjointPoolParamsSetTrace(disjoint_pool_params, 1); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); umf_memory_pool_handle_t pool; - umf_result = umfPoolCreate(umfDisjointPoolOps(), coarse_memory_provider, - &disjoint_memory_pool_params, - UMF_POOL_CREATE_FLAG_NONE, &pool); + umf_result = + umfPoolCreate(umfDisjointPoolOps(), coarse_memory_provider, + disjoint_pool_params, UMF_POOL_CREATE_FLAG_NONE, &pool); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(pool, nullptr); + umf_result = umfDisjointPoolParamsDestroy(disjoint_pool_params); + umf_memory_provider_handle_t prov = NULL; umfPoolGetMemoryProvider(pool, &prov); ASSERT_NE(prov, nullptr); @@ -342,20 +369,34 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMallocPool_simple2) { ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(coarse_memory_provider, nullptr); - umf_disjoint_pool_params_t disjoint_memory_pool_params = {}; - disjoint_memory_pool_params.SlabMinSize = 4096; - disjoint_memory_pool_params.MaxPoolableSize = 4096; - disjoint_memory_pool_params.Capacity = 4; - disjoint_memory_pool_params.MinBucketSize = 64; - disjoint_memory_pool_params.PoolTrace = 1; + umf_disjoint_pool_params_handle_t disjoint_pool_params = NULL; + umf_result = umfDisjointPoolParamsCreate(&disjoint_pool_params); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(disjoint_pool_params, nullptr); + umf_result = + umfDisjointPoolParamsSetSlabMinSize(disjoint_pool_params, 4096); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = + umfDisjointPoolParamsSetMaxPoolableSize(disjoint_pool_params, 4096); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = umfDisjointPoolParamsSetCapacity(disjoint_pool_params, 4); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = + umfDisjointPoolParamsSetMinBucketSize(disjoint_pool_params, 64); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = umfDisjointPoolParamsSetTrace(disjoint_pool_params, 1); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); umf_memory_pool_handle_t pool; - umf_result = umfPoolCreate(umfDisjointPoolOps(), coarse_memory_provider, - &disjoint_memory_pool_params, - UMF_POOL_CREATE_FLAG_NONE, &pool); + umf_result = + umfPoolCreate(umfDisjointPoolOps(), coarse_memory_provider, + disjoint_pool_params, UMF_POOL_CREATE_FLAG_NONE, &pool); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(pool, nullptr); + umf_result = umfDisjointPoolParamsDestroy(disjoint_pool_params); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + // test double sizes[] = {2, 4, 0.5, 1, 8, 0.25}; size_t alignment[] = {0, 4, 0, 16, 32, 128}; @@ -419,20 +460,34 @@ TEST_P(CoarseWithMemoryStrategyTest, disjointCoarseMMapPool_random) { ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(coarse_memory_provider, nullptr); - umf_disjoint_pool_params_t disjoint_memory_pool_params = {}; - disjoint_memory_pool_params.SlabMinSize = 1024; - disjoint_memory_pool_params.MaxPoolableSize = 1024; - disjoint_memory_pool_params.Capacity = 2; - disjoint_memory_pool_params.MinBucketSize = 16; - disjoint_memory_pool_params.PoolTrace = 1; + umf_disjoint_pool_params_handle_t disjoint_pool_params = NULL; + umf_result = umfDisjointPoolParamsCreate(&disjoint_pool_params); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(disjoint_pool_params, nullptr); + umf_result = + umfDisjointPoolParamsSetSlabMinSize(disjoint_pool_params, 1024); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = + umfDisjointPoolParamsSetMaxPoolableSize(disjoint_pool_params, 1024); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = umfDisjointPoolParamsSetCapacity(disjoint_pool_params, 2); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = + umfDisjointPoolParamsSetMinBucketSize(disjoint_pool_params, 16); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = umfDisjointPoolParamsSetTrace(disjoint_pool_params, 1); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); umf_memory_pool_handle_t pool; - umf_result = umfPoolCreate(umfDisjointPoolOps(), coarse_memory_provider, - &disjoint_memory_pool_params, - UMF_POOL_CREATE_FLAG_NONE, &pool); + umf_result = + umfPoolCreate(umfDisjointPoolOps(), coarse_memory_provider, + disjoint_pool_params, UMF_POOL_CREATE_FLAG_NONE, &pool); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(pool, nullptr); + umf_result = umfDisjointPoolParamsDestroy(disjoint_pool_params); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + // set constant seed so each test run will have the same scenario uint32_t seed = 1234; std::mt19937 mt(seed); diff --git a/test/pools/disjoint_pool.cpp b/test/pools/disjoint_pool.cpp index 5f048a7e6..319997c82 100644 --- a/test/pools/disjoint_pool.cpp +++ b/test/pools/disjoint_pool.cpp @@ -2,6 +2,8 @@ // Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include + #include "pool.hpp" #include "poolFixtures.hpp" #include "pool_disjoint.h" @@ -9,13 +11,43 @@ #include "provider_null.h" #include "provider_trace.h" -umf_disjoint_pool_params_t poolConfig() { - umf_disjoint_pool_params_t config{}; - config.SlabMinSize = 4096; - config.MaxPoolableSize = 4096; - config.Capacity = 4; - config.MinBucketSize = 64; - return config; +using disjoint_params_unique_handle_t = + std::unique_ptr; + +static constexpr size_t DEFAULT_DISJOINT_SLAB_MIN_SIZE = 4096; +static constexpr size_t DEFAULT_DISJOINT_MAX_POOLABLE_SIZE = 4096; +static constexpr size_t DEFAULT_DISJOINT_CAPACITY = 4; +static constexpr size_t DEFAULT_DISJOINT_MIN_BUCKET_SIZE = 64; + +disjoint_params_unique_handle_t poolConfig() { + umf_disjoint_pool_params_handle_t config = nullptr; + umf_result_t res = umfDisjointPoolParamsCreate(&config); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error("Failed to create pool params"); + } + res = umfDisjointPoolParamsSetSlabMinSize(config, + DEFAULT_DISJOINT_SLAB_MIN_SIZE); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error("Failed to set slab min size"); + } + res = umfDisjointPoolParamsSetMaxPoolableSize( + config, DEFAULT_DISJOINT_MAX_POOLABLE_SIZE); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error("Failed to set max poolable size"); + } + res = umfDisjointPoolParamsSetCapacity(config, DEFAULT_DISJOINT_CAPACITY); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error("Failed to set capacity"); + } + res = umfDisjointPoolParamsSetMinBucketSize( + config, DEFAULT_DISJOINT_MIN_BUCKET_SIZE); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error("Failed to set min bucket size"); + } + + return disjoint_params_unique_handle_t(config, + &umfDisjointPoolParamsDestroy); } using umf_test::test; @@ -47,12 +79,14 @@ TEST_F(test, freeErrorPropagation) { provider_handle = providerUnique.get(); // force all allocations to go to memory provider - umf_disjoint_pool_params_t params = poolConfig(); - params.MaxPoolableSize = 0; + disjoint_params_unique_handle_t params = poolConfig(); + umf_result_t retp = + umfDisjointPoolParamsSetMaxPoolableSize(params.get(), 0); + EXPECT_EQ(retp, UMF_RESULT_SUCCESS); umf_memory_pool_handle_t pool = NULL; - umf_result_t retp = - umfPoolCreate(umfDisjointPoolOps(), provider_handle, ¶ms, 0, &pool); + retp = umfPoolCreate(umfDisjointPoolOps(), provider_handle, params.get(), 0, + &pool); EXPECT_EQ(retp, UMF_RESULT_SUCCESS); auto poolHandle = umf_test::wrapPoolUnique(pool); @@ -92,8 +126,10 @@ TEST_F(test, sharedLimits) { static constexpr size_t SlabMinSize = 1024; static constexpr size_t MaxSize = 4 * SlabMinSize; - auto config = poolConfig(); - config.SlabMinSize = SlabMinSize; + disjoint_params_unique_handle_t config = poolConfig(); + umf_result_t ret = + umfDisjointPoolParamsSetSlabMinSize(config.get(), SlabMinSize); + EXPECT_EQ(ret, UMF_RESULT_SUCCESS); auto limits = std::unique_ptr(defaultPoolConfig.Capacity) / 2))); +INSTANTIATE_TEST_SUITE_P(disjointPoolTests, umfMemTest, + ::testing::Values(std::make_tuple( + poolCreateExtParams{ + umfDisjointPoolOps(), + (void *)defaultPoolConfig.get(), + &MOCK_OUT_OF_MEM_PROVIDER_OPS, + (void *)&DEFAULT_DISJOINT_CAPACITY, nullptr}, + static_cast(DEFAULT_DISJOINT_CAPACITY) / 2))); INSTANTIATE_TEST_SUITE_P(disjointMultiPoolTests, umfMultiPoolTest, ::testing::Values(poolCreateExtParams{ - umfDisjointPoolOps(), (void *)&defaultPoolConfig, + umfDisjointPoolOps(), + (void *)defaultPoolConfig.get(), &BA_GLOBAL_PROVIDER_OPS, nullptr, nullptr})); diff --git a/test/provider_os_memory.cpp b/test/provider_os_memory.cpp index 3c3cb7c7b..fc6469a0d 100644 --- a/test/provider_os_memory.cpp +++ b/test/provider_os_memory.cpp @@ -9,8 +9,10 @@ #include "test_helpers.h" #include -#include #include +#if (defined UMF_POOL_DISJOINT_ENABLED) +#include +#endif #ifdef UMF_POOL_JEMALLOC_ENABLED #include #endif @@ -383,19 +385,43 @@ auto os_params = osMemoryProviderParamsShared(); HostMemoryAccessor hostAccessor; -umf_disjoint_pool_params_t disjointPoolParams() { - umf_disjoint_pool_params_t params = umfDisjointPoolParamsDefault(); - params.SlabMinSize = 4096; - params.MaxPoolableSize = 4096; - params.Capacity = 4; - params.MinBucketSize = 64; - return params; +#if (defined UMF_POOL_DISJOINT_ENABLED) +using disjoint_params_unique_handle_t = + std::unique_ptr; + +disjoint_params_unique_handle_t disjointPoolParams() { + umf_disjoint_pool_params_handle_t params = nullptr; + umf_result_t res = umfDisjointPoolParamsCreate(¶ms); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error("Failed to create pool params"); + } + res = umfDisjointPoolParamsSetSlabMinSize(params, 4096); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error("Failed to set slab min size"); + } + res = umfDisjointPoolParamsSetMaxPoolableSize(params, 4096); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error("Failed to set max poolable size"); + } + res = umfDisjointPoolParamsSetCapacity(params, 4); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error("Failed to set capacity"); + } + res = umfDisjointPoolParamsSetMinBucketSize(params, 64); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error("Failed to set min bucket size"); + } + + return disjoint_params_unique_handle_t(params, + &umfDisjointPoolParamsDestroy); } -umf_disjoint_pool_params_t disjointParams = disjointPoolParams(); +disjoint_params_unique_handle_t disjointParams = disjointPoolParams(); +#endif static std::vector ipcTestParamsList = { #if (defined UMF_POOL_DISJOINT_ENABLED) - {umfDisjointPoolOps(), &disjointParams, umfOsMemoryProviderOps(), + {umfDisjointPoolOps(), disjointParams.get(), umfOsMemoryProviderOps(), &os_params, &hostAccessor, false}, #endif #ifdef UMF_POOL_JEMALLOC_ENABLED diff --git a/test/providers/ipc_cuda_prov_consumer.c b/test/providers/ipc_cuda_prov_consumer.c index 5be6785a1..3286cee28 100644 --- a/test/providers/ipc_cuda_prov_consumer.c +++ b/test/providers/ipc_cuda_prov_consumer.c @@ -26,9 +26,19 @@ int main(int argc, char *argv[]) { cuda_memory_provider_params_t cu_params = create_cuda_prov_params(UMF_MEMORY_TYPE_DEVICE); - umf_disjoint_pool_params_t pool_params = umfDisjointPoolParamsDefault(); + umf_disjoint_pool_params_handle_t pool_params = NULL; - return run_consumer(port, umfDisjointPoolOps(), &pool_params, - umfCUDAMemoryProviderOps(), &cu_params, memcopy, - &cu_params); + umf_result_t umf_result = umfDisjointPoolParamsCreate(&pool_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to create pool params!\n"); + return -1; + } + + int ret = run_consumer(port, umfDisjointPoolOps(), pool_params, + umfCUDAMemoryProviderOps(), &cu_params, memcopy, + &cu_params); + + umfDisjointPoolParamsDestroy(pool_params); + + return ret; } diff --git a/test/providers/ipc_cuda_prov_producer.c b/test/providers/ipc_cuda_prov_producer.c index bd4673ce7..d11004d6d 100644 --- a/test/providers/ipc_cuda_prov_producer.c +++ b/test/providers/ipc_cuda_prov_producer.c @@ -26,9 +26,19 @@ int main(int argc, char *argv[]) { cuda_memory_provider_params_t cu_params = create_cuda_prov_params(UMF_MEMORY_TYPE_DEVICE); - umf_disjoint_pool_params_t pool_params = umfDisjointPoolParamsDefault(); + umf_disjoint_pool_params_handle_t pool_params = NULL; - return run_producer(port, umfDisjointPoolOps(), &pool_params, - umfCUDAMemoryProviderOps(), &cu_params, memcopy, - &cu_params); + umf_result_t umf_result = umfDisjointPoolParamsCreate(&pool_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to create pool params!\n"); + return -1; + } + + int ret = run_producer(port, umfDisjointPoolOps(), pool_params, + umfCUDAMemoryProviderOps(), &cu_params, memcopy, + &cu_params); + + umfDisjointPoolParamsDestroy(pool_params); + + return ret; } diff --git a/test/providers/ipc_level_zero_prov_consumer.c b/test/providers/ipc_level_zero_prov_consumer.c index 70b72a7fc..4ec952f4f 100644 --- a/test/providers/ipc_level_zero_prov_consumer.c +++ b/test/providers/ipc_level_zero_prov_consumer.c @@ -26,9 +26,19 @@ int main(int argc, char *argv[]) { level_zero_memory_provider_params_t l0_params = create_level_zero_prov_params(UMF_MEMORY_TYPE_DEVICE); - umf_disjoint_pool_params_t pool_params = umfDisjointPoolParamsDefault(); + umf_disjoint_pool_params_handle_t pool_params = NULL; - return run_consumer(port, umfDisjointPoolOps(), &pool_params, - umfLevelZeroMemoryProviderOps(), &l0_params, memcopy, - &l0_params); + umf_result_t umf_result = umfDisjointPoolParamsCreate(&pool_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to create pool params!\n"); + return -1; + } + + int ret = run_consumer(port, umfDisjointPoolOps(), pool_params, + umfLevelZeroMemoryProviderOps(), &l0_params, memcopy, + &l0_params); + + umfDisjointPoolParamsDestroy(pool_params); + + return ret; } diff --git a/test/providers/ipc_level_zero_prov_producer.c b/test/providers/ipc_level_zero_prov_producer.c index 8e758644f..ba950c602 100644 --- a/test/providers/ipc_level_zero_prov_producer.c +++ b/test/providers/ipc_level_zero_prov_producer.c @@ -26,9 +26,19 @@ int main(int argc, char *argv[]) { level_zero_memory_provider_params_t l0_params = create_level_zero_prov_params(UMF_MEMORY_TYPE_DEVICE); - umf_disjoint_pool_params_t pool_params = umfDisjointPoolParamsDefault(); + umf_disjoint_pool_params_handle_t pool_params = NULL; - return run_producer(port, umfDisjointPoolOps(), &pool_params, - umfLevelZeroMemoryProviderOps(), &l0_params, memcopy, - &l0_params); + umf_result_t umf_result = umfDisjointPoolParamsCreate(&pool_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to create pool params!\n"); + return -1; + } + + int ret = run_producer(port, umfDisjointPoolOps(), pool_params, + umfLevelZeroMemoryProviderOps(), &l0_params, memcopy, + &l0_params); + + umfDisjointPoolParamsDestroy(pool_params); + + return ret; } From 63f97b8c0ec8d10c1cfd7400845b0e894b96bb15 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Nov 2024 16:45:10 +0000 Subject: [PATCH 309/352] Bump packaging in /third_party in the pip-dependencies group Bumps the pip-dependencies group in /third_party with 1 update: [packaging](https://github.com/pypa/packaging). Updates `packaging` from 24.1 to 24.2 - [Release notes](https://github.com/pypa/packaging/releases) - [Changelog](https://github.com/pypa/packaging/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pypa/packaging/compare/24.1...24.2) --- updated-dependencies: - dependency-name: packaging dependency-type: direct:production update-type: version-update:semver-minor dependency-group: pip-dependencies ... Signed-off-by: dependabot[bot] --- third_party/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/requirements.txt b/third_party/requirements.txt index 17be62608..6a8be6e46 100644 --- a/third_party/requirements.txt +++ b/third_party/requirements.txt @@ -4,7 +4,7 @@ clang-format==15.0.7 cmake-format==0.6.13 black==24.3.0 # Tests -packaging==24.1 +packaging==24.2 # Generating HTML documentation pygments==2.18.0 sphinxcontrib_applehelp==2.0.0 From 7b7cea785c6662b9663b581cdc3fd9fa94d7fb84 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 20 Nov 2024 10:30:03 +0100 Subject: [PATCH 310/352] Print dlerror in utils_open_library() and utils_get_symbol_addr() Signed-off-by: Lukasz Dorau --- src/utils/utils_load_library.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/utils/utils_load_library.c b/src/utils/utils_load_library.c index cbe7be445..ef0da450b 100644 --- a/src/utils/utils_load_library.c +++ b/src/utils/utils_load_library.c @@ -66,7 +66,13 @@ void *utils_open_library(const char *filename, int userFlags) { if (userFlags & UMF_UTIL_OPEN_LIBRARY_GLOBAL) { dlopenFlags |= RTLD_GLOBAL; } - return dlopen(filename, dlopenFlags); + + void *handle = dlopen(filename, dlopenFlags); + if (handle == NULL) { + LOG_FATAL("dlopen(%s) failed with error: %s", filename, dlerror()); + } + + return handle; } int utils_close_library(void *handle) { return dlclose(handle); } @@ -80,7 +86,7 @@ void *utils_get_symbol_addr(void *handle, const char *symbol, void *addr = dlsym(handle, symbol); if (addr == NULL) { - LOG_ERR("Required symbol not found: %s", symbol); + LOG_ERR("required symbol not found: %s (error: %s)", symbol, dlerror()); } return addr; From 68e19f5cba128f3c8c554cdcbd8af06da742b268 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Staniewski?= Date: Wed, 20 Nov 2024 08:39:25 +0000 Subject: [PATCH 311/352] Enable `-Werror` in developer build --- cmake/helpers.cmake | 8 ++++++-- src/ipc_cache.c | 5 +++++ src/memtargets/memtarget_numa.c | 6 +++--- src/provider/provider_cuda.c | 2 +- src/provider/provider_level_zero.c | 4 ++-- src/provider/provider_os_memory.c | 3 ++- test/CMakeLists.txt | 5 ++++- test/memspaces/memspace_fixtures.hpp | 2 ++ test/poolFixtures.hpp | 5 +++++ test/providers/provider_level_zero.cpp | 4 ++-- 10 files changed, 32 insertions(+), 12 deletions(-) diff --git a/cmake/helpers.cmake b/cmake/helpers.cmake index 1372531a0..2a16de742 100644 --- a/cmake/helpers.cmake +++ b/cmake/helpers.cmake @@ -244,8 +244,9 @@ function(add_umf_target_compile_options name) target_compile_definitions(${name} PRIVATE -D_FORTIFY_SOURCE=2) endif() if(UMF_DEVELOPER_MODE) - target_compile_options(${name} PRIVATE -fno-omit-frame-pointer - -fstack-protector-strong) + target_compile_options( + ${name} PRIVATE -fno-omit-frame-pointer + -fstack-protector-strong -Werror) endif() if(UMF_USE_COVERAGE) if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") @@ -279,6 +280,9 @@ function(add_umf_target_compile_options name) # disable 4200 warning: nonstandard extension used: # zero-sized array in struct/union /wd4200) + if(UMF_DEVELOPER_MODE) + target_compile_options(${name} PRIVATE /WX) + endif() if(${CMAKE_C_COMPILER_ID} MATCHES "MSVC") target_compile_options( ${name} diff --git a/src/ipc_cache.c b/src/ipc_cache.c index 40ecc3978..60072d4df 100644 --- a/src/ipc_cache.c +++ b/src/ipc_cache.c @@ -17,6 +17,11 @@ #include "utils_log.h" #include "utlist.h" +// HASH_ADD macro produces `warning C4702: unreachable code` on MSVC +#ifdef _MSC_VER +#pragma warning(disable : 4702) +#endif + struct ipc_handle_cache_entry_t; typedef struct ipc_handle_cache_entry_t *hash_map_t; diff --git a/src/memtargets/memtarget_numa.c b/src/memtargets/memtarget_numa.c index cb0e4ce00..34ba7fc10 100644 --- a/src/memtargets/memtarget_numa.c +++ b/src/memtargets/memtarget_numa.c @@ -40,7 +40,7 @@ static umf_result_t numa_initialize(void *params, void **memTarget) { return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; } - numaTarget->physical_id = config->physical_id; + numaTarget->physical_id = (unsigned)config->physical_id; *memTarget = numaTarget; return UMF_RESULT_SUCCESS; } @@ -100,7 +100,7 @@ static umf_result_t numa_memory_provider_create_from_memspace( params.partitions = (umf_numa_split_partition_t *)policy->ops.split.part; - params.partitions_len = policy->ops.split.part_len; + params.partitions_len = (unsigned)policy->ops.split.part_len; break; default: return UMF_RESULT_ERROR_INVALID_ARGUMENT; @@ -131,7 +131,7 @@ static umf_result_t numa_memory_provider_create_from_memspace( for (size_t i = 0; i < numNodesProvider; i++) { params.numa_list[i] = numaTargets[i]->physical_id; } - params.numa_list_len = numNodesProvider; + params.numa_list_len = (unsigned)numNodesProvider; } umf_memory_provider_handle_t numaProvider = NULL; diff --git a/src/provider/provider_cuda.c b/src/provider/provider_cuda.c index 68fe0da23..5a686d857 100644 --- a/src/provider/provider_cuda.c +++ b/src/provider/provider_cuda.c @@ -217,7 +217,7 @@ static void cu_memory_provider_finalize(void *provider) { umf_ba_global_free(provider); } -/* +/* * This function is used by the CUDA provider to make sure that * the required context is set. If the current context is * not the required one, it will be saved in restore_ctx. diff --git a/src/provider/provider_level_zero.c b/src/provider/provider_level_zero.c index 3339042ce..6b4468da6 100644 --- a/src/provider/provider_level_zero.c +++ b/src/provider/provider_level_zero.c @@ -148,12 +148,12 @@ static umf_result_t ze_memory_provider_initialize(void *params, } if ((ze_params->memory_type == UMF_MEMORY_TYPE_HOST) == - (bool)ze_params->level_zero_device_handle) { + (ze_params->level_zero_device_handle != NULL)) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; } if ((bool)ze_params->resident_device_count != - (bool)ze_params->resident_device_handles) { + (ze_params->resident_device_handles != NULL)) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; } diff --git a/src/provider/provider_os_memory.c b/src/provider/provider_os_memory.c index 3ea5cf220..dae947651 100644 --- a/src/provider/provider_os_memory.c +++ b/src/provider/provider_os_memory.c @@ -1207,8 +1207,9 @@ static umf_result_t os_get_ipc_handle(void *provider, const void *ptr, os_ipc_data->visibility = os_provider->visibility; os_ipc_data->shm_name_len = strlen(os_provider->shm_name); if (os_ipc_data->shm_name_len > 0) { + // NOTE: +1 for '\0' at the end of the string strncpy(os_ipc_data->shm_name, os_provider->shm_name, - os_ipc_data->shm_name_len); + os_ipc_data->shm_name_len + 1); } else { os_ipc_data->fd = os_provider->fd; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 9899991ce..1f2ef5959 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -75,8 +75,11 @@ function(build_umf_test) # tests retrieve arguments using 'GetParam()', which applies a 'const' # qualifier often discarded in the test scenarios. target_compile_options(${TEST_TARGET_NAME} PRIVATE -Wno-cast-qual) - endif() + if(UMF_DEVELOPER_MODE) + target_compile_options(${TEST_TARGET_NAME} PRIVATE -Werror) + endif() + endif() target_link_directories(${TEST_TARGET_NAME} PRIVATE ${LIB_DIRS}) target_include_directories( diff --git a/test/memspaces/memspace_fixtures.hpp b/test/memspaces/memspace_fixtures.hpp index 9bcfc5fbe..da174c4f1 100644 --- a/test/memspaces/memspace_fixtures.hpp +++ b/test/memspaces/memspace_fixtures.hpp @@ -87,6 +87,8 @@ struct memspaceProviderTest : ::memspaceGetTest { } auto [isQuerySupported, memspaceGet] = ::memspaceGetTest::GetParam(); + (void)memspaceGet; + isQuerySupported(nodeIds.front()); // The test has been marked as skipped in isQuerySupported, diff --git a/test/poolFixtures.hpp b/test/poolFixtures.hpp index e1c1cc722..d761a3cfd 100644 --- a/test/poolFixtures.hpp +++ b/test/poolFixtures.hpp @@ -70,6 +70,11 @@ struct umfPoolTest : umf_test::test, auto [pool_ops, pool_params, provider_ops, provider_params, coarse_params] = this->GetParam(); + (void)pool_ops; + (void)pool_params; + (void)provider_params; + (void)coarse_params; + if (provider_ops == umfDevDaxMemoryProviderOps()) { char *path = getenv("UMF_TESTS_DEVDAX_PATH"); if (path == nullptr || path[0] == 0) { diff --git a/test/providers/provider_level_zero.cpp b/test/providers/provider_level_zero.cpp index 4041362f0..347fa9888 100644 --- a/test/providers/provider_level_zero.cpp +++ b/test/providers/provider_level_zero.cpp @@ -254,9 +254,9 @@ TEST_P(umfLevelZeroProviderTest, allocInvalidSize) { ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(provider, nullptr); - // try to alloc (int)-1 void *ptr = nullptr; - umf_result = umfMemoryProviderAlloc(provider, -1, 0, &ptr); + umf_result = umfMemoryProviderAlloc( + provider, std::numeric_limits::max(), 0, &ptr); ASSERT_EQ(umf_result, UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC); const char *message; int32_t error; From 60cc555d0227cb9a93a492737e4801aab55e68b2 Mon Sep 17 00:00:00 2001 From: Patryk Kaminski Date: Fri, 8 Nov 2024 10:14:50 +0100 Subject: [PATCH 312/352] Add a RUNPATH to installed libraries --- CMakeLists.txt | 6 ++++++ src/CMakeLists.txt | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index aef1ee16b..f55a4198c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,6 +63,12 @@ option(UMF_FORMAT_CODE_STYLE set(UMF_HWLOC_NAME "hwloc" CACHE STRING "Custom name for hwloc library w/o extension") +set(UMF_INSTALL_RPATH + "" + CACHE + STRING + "Set the runtime search path to the directory with dependencies (e.g. hwloc)" +) # Only a part of skips is treated as a failure now. TODO: extend to all tests option(UMF_TESTS_FAIL_ON_SKIP "Treat skips in tests as fail" OFF) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7078d629f..2f7480c81 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -115,6 +115,10 @@ elseif(MACOSX) endif() if(UMF_BUILD_SHARED_LIBRARY) + if(UMF_INSTALL_RPATH) + set(CMAKE_INSTALL_RPATH "${UMF_INSTALL_RPATH}") + endif() + if(NOT UMF_DISABLE_HWLOC) set(HWLOC_LIB ${UMF_HWLOC_NAME}) endif() From da98ba9ff107d93e1452d3f3c7d9b0c63411e0d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Staniewski?= Date: Wed, 6 Nov 2024 12:41:30 +0000 Subject: [PATCH 313/352] Add test for `umfPoolMallocUsableSize` --- test/poolFixtures.hpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/poolFixtures.hpp b/test/poolFixtures.hpp index e1c1cc722..bb3c2a994 100644 --- a/test/poolFixtures.hpp +++ b/test/poolFixtures.hpp @@ -9,6 +9,7 @@ #include "provider.hpp" #include "umf/providers/provider_coarse.h" #include "umf/providers/provider_devdax_memory.h" +#include "utils/utils_sanitizers.h" #include #include @@ -456,4 +457,26 @@ TEST_P(umfPoolTest, allocMaxSize) { ASSERT_EQ(ptr, nullptr); } +TEST_P(umfPoolTest, mallocUsableSize) { +#ifdef __SANITIZE_ADDRESS__ + // Sanitizer replaces malloc_usable_size implementation with its own + GTEST_SKIP() + << "This test is invalid with AddressSanitizer instrumentation"; +#endif + + for (size_t allocSize : {32, 48, 1024, 8192}) { + char *ptr = static_cast(umfPoolMalloc(pool.get(), allocSize)); + ASSERT_NE(ptr, nullptr); + size_t result = umfPoolMallocUsableSize(pool.get(), ptr); + ASSERT_TRUE(result == 0 || result >= allocSize); + + // Make sure we can write to this memory + for (size_t i = 0; i < result; i++) { + ptr[i] = 123; + } + + umfPoolFree(pool.get(), ptr); + } +} + #endif /* UMF_TEST_POOL_FIXTURES_HPP */ From d3a13980bbe4855612e6750a819f1c6b8f1fd5e2 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Wed, 20 Nov 2024 04:30:47 -0800 Subject: [PATCH 314/352] Update Cuda provider config API --- .../cuda_shared_memory/cuda_shared_memory.c | 48 +++++- include/umf/providers/provider_cuda.h | 44 ++++- src/libumf.def | 5 + src/libumf.map | 5 + src/provider/provider_cuda.c | 112 +++++++++++- test/providers/cuda_helpers.cpp | 96 ++++++++--- test/providers/cuda_helpers.h | 7 +- test/providers/ipc_cuda_prov_common.c | 7 +- test/providers/ipc_cuda_prov_common.h | 5 + test/providers/ipc_cuda_prov_consumer.c | 67 +++++++- test/providers/ipc_cuda_prov_producer.c | 67 +++++++- test/providers/provider_cuda.cpp | 159 +++++++++++++++--- 12 files changed, 538 insertions(+), 84 deletions(-) diff --git a/examples/cuda_shared_memory/cuda_shared_memory.c b/examples/cuda_shared_memory/cuda_shared_memory.c index 22e5e3f10..50c8f9240 100644 --- a/examples/cuda_shared_memory/cuda_shared_memory.c +++ b/examples/cuda_shared_memory/cuda_shared_memory.c @@ -43,24 +43,51 @@ int main(void) { // Create a context on the device cuCtxCreate(&cuContext, 0, cuDevice); - // Setup parameters for the CUDA memory provider. It will be used for + // Setup parameters for the CUDA Memory Provider. It will be used for // allocating memory from CUDA devices. - cuda_memory_provider_params_t cu_memory_provider_params; - cu_memory_provider_params.cuda_context_handle = cuContext; - cu_memory_provider_params.cuda_device_handle = cuDevice; + umf_cuda_memory_provider_params_handle_t cu_memory_provider_params = NULL; + res = umfCUDAMemoryProviderParamsCreate(&cu_memory_provider_params); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to create memory provider params!\n"); + ret = -1; + goto cuda_destroy; + } + + res = umfCUDAMemoryProviderParamsSetContext(cu_memory_provider_params, + cuContext); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to set context in memory provider params!\n"); + ret = -1; + goto provider_params_destroy; + } + + res = umfCUDAMemoryProviderParamsSetDevice(cu_memory_provider_params, + cuDevice); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to set device in memory provider params!\n"); + ret = -1; + goto provider_params_destroy; + } // Set the memory type to shared to allow the memory to be accessed on both // CPU and GPU. - cu_memory_provider_params.memory_type = UMF_MEMORY_TYPE_SHARED; + res = umfCUDAMemoryProviderParamsSetMemoryType(cu_memory_provider_params, + UMF_MEMORY_TYPE_SHARED); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, + "Failed to set memory type in memory provider params!\n"); + ret = -1; + goto provider_params_destroy; + } // Create CUDA memory provider umf_memory_provider_handle_t cu_memory_provider; - res = umfMemoryProviderCreate(umfCUDAMemoryProviderOps(), - &cu_memory_provider_params, - &cu_memory_provider); + res = + umfMemoryProviderCreate(umfCUDAMemoryProviderOps(), + cu_memory_provider_params, &cu_memory_provider); if (res != UMF_RESULT_SUCCESS) { fprintf(stderr, "Failed to create a memory provider!\n"); ret = -1; - goto cuda_destroy; + goto provider_params_destroy; } printf("CUDA memory provider created at %p\n", (void *)cu_memory_provider); @@ -147,6 +174,9 @@ int main(void) { memory_provider_destroy: umfMemoryProviderDestroy(cu_memory_provider); +provider_params_destroy: + umfCUDAMemoryProviderParamsDestroy(cu_memory_provider_params); + cuda_destroy: ret = cuCtxDestroy(cuContext); return ret; diff --git a/include/umf/providers/provider_cuda.h b/include/umf/providers/provider_cuda.h index 2f6a07d81..5f1d5a6e2 100644 --- a/include/umf/providers/provider_cuda.h +++ b/include/umf/providers/provider_cuda.h @@ -14,12 +14,44 @@ extern "C" { #endif -/// @brief CUDA Memory Provider settings struct -typedef struct cuda_memory_provider_params_t { - void *cuda_context_handle; ///< Handle to the CUDA context - int cuda_device_handle; ///< Handle to the CUDA device - umf_usm_memory_type_t memory_type; ///< Allocation memory type -} cuda_memory_provider_params_t; +struct umf_cuda_memory_provider_params_t; + +typedef struct umf_cuda_memory_provider_params_t + *umf_cuda_memory_provider_params_handle_t; + +/// @brief Create a struct to store parameters of the CUDA Memory Provider. +/// @param hParams [out] handle to the newly created parameters struct. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfCUDAMemoryProviderParamsCreate( + umf_cuda_memory_provider_params_handle_t *hParams); + +/// @brief Destroy parameters struct. +/// @param hParams handle to the parameters of the CUDA Memory Provider. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfCUDAMemoryProviderParamsDestroy( + umf_cuda_memory_provider_params_handle_t hParams); + +/// @brief Set the CUDA context handle in the parameters struct. +/// @param hParams handle to the parameters of the CUDA Memory Provider. +/// @param hContext handle to the CUDA context. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfCUDAMemoryProviderParamsSetContext( + umf_cuda_memory_provider_params_handle_t hParams, void *hContext); + +/// @brief Set the CUDA device handle in the parameters struct. +/// @param hParams handle to the parameters of the CUDA Memory Provider. +/// @param hDevice handle to the CUDA device. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfCUDAMemoryProviderParamsSetDevice( + umf_cuda_memory_provider_params_handle_t hParams, int hDevice); + +/// @brief Set the memory type in the parameters struct. +/// @param hParams handle to the parameters of the CUDA Memory Provider. +/// @param memoryType memory type. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfCUDAMemoryProviderParamsSetMemoryType( + umf_cuda_memory_provider_params_handle_t hParams, + umf_usm_memory_type_t memoryType); umf_memory_provider_ops_t *umfCUDAMemoryProviderOps(void); diff --git a/src/libumf.def b/src/libumf.def index 56e26050c..8f29f4579 100644 --- a/src/libumf.def +++ b/src/libumf.def @@ -17,6 +17,11 @@ EXPORTS umfCoarseMemoryProviderGetStats umfCoarseMemoryProviderOps umfCUDAMemoryProviderOps + umfCUDAMemoryProviderParamsCreate + umfCUDAMemoryProviderParamsDestroy + umfCUDAMemoryProviderParamsSetContext + umfCUDAMemoryProviderParamsSetDevice + umfCUDAMemoryProviderParamsSetMemoryType umfDevDaxMemoryProviderOps umfFree umfFileMemoryProviderOps diff --git a/src/libumf.map b/src/libumf.map index 19235705c..f70d247b5 100644 --- a/src/libumf.map +++ b/src/libumf.map @@ -11,6 +11,11 @@ UMF_1.0 { umfCoarseMemoryProviderGetStats; umfCoarseMemoryProviderOps; umfCUDAMemoryProviderOps; + umfCUDAMemoryProviderParamsCreate; + umfCUDAMemoryProviderParamsDestroy; + umfCUDAMemoryProviderParamsSetContext; + umfCUDAMemoryProviderParamsSetDevice; + umfCUDAMemoryProviderParamsSetMemoryType; umfDevDaxMemoryProviderOps; umfFree; umfFileMemoryProviderOps; diff --git a/src/provider/provider_cuda.c b/src/provider/provider_cuda.c index 5a686d857..3c4e39451 100644 --- a/src/provider/provider_cuda.c +++ b/src/provider/provider_cuda.c @@ -14,6 +14,40 @@ #if defined(UMF_NO_CUDA_PROVIDER) +umf_result_t umfCUDAMemoryProviderParamsCreate( + umf_cuda_memory_provider_params_handle_t *hParams) { + (void)hParams; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + +umf_result_t umfCUDAMemoryProviderParamsDestroy( + umf_cuda_memory_provider_params_handle_t hParams) { + (void)hParams; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + +umf_result_t umfCUDAMemoryProviderParamsSetContext( + umf_cuda_memory_provider_params_handle_t hParams, void *hContext) { + (void)hParams; + (void)hContext; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + +umf_result_t umfCUDAMemoryProviderParamsSetDevice( + umf_cuda_memory_provider_params_handle_t hParams, int hDevice) { + (void)hParams; + (void)hDevice; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + +umf_result_t umfCUDAMemoryProviderParamsSetMemoryType( + umf_cuda_memory_provider_params_handle_t hParams, + umf_usm_memory_type_t memoryType) { + (void)hParams; + (void)memoryType; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + umf_memory_provider_ops_t *umfCUDAMemoryProviderOps(void) { // not supported return NULL; @@ -48,6 +82,13 @@ typedef struct cu_memory_provider_t { size_t min_alignment; } cu_memory_provider_t; +// CUDA Memory Provider settings struct +typedef struct umf_cuda_memory_provider_params_t { + void *cuda_context_handle; ///< Handle to the CUDA context + int cuda_device_handle; ///< Handle to the CUDA device + umf_usm_memory_type_t memory_type; ///< Allocation memory type +} umf_cuda_memory_provider_params_t; + typedef struct cu_ops_t { CUresult (*cuMemGetAllocationGranularity)( size_t *granularity, const CUmemAllocationProp *prop, @@ -158,14 +199,81 @@ static void init_cu_global_state(void) { } } +umf_result_t umfCUDAMemoryProviderParamsCreate( + umf_cuda_memory_provider_params_handle_t *hParams) { + if (!hParams) { + LOG_ERR("CUDA Memory Provider params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + umf_cuda_memory_provider_params_handle_t params_data = + umf_ba_global_alloc(sizeof(umf_cuda_memory_provider_params_t)); + if (!params_data) { + LOG_ERR("Cannot allocate memory for CUDA Memory Provider params"); + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + params_data->cuda_context_handle = NULL; + params_data->cuda_device_handle = -1; + params_data->memory_type = UMF_MEMORY_TYPE_UNKNOWN; + + *hParams = params_data; + + return UMF_RESULT_SUCCESS; +} + +umf_result_t umfCUDAMemoryProviderParamsDestroy( + umf_cuda_memory_provider_params_handle_t hParams) { + umf_ba_global_free(hParams); + + return UMF_RESULT_SUCCESS; +} + +umf_result_t umfCUDAMemoryProviderParamsSetContext( + umf_cuda_memory_provider_params_handle_t hParams, void *hContext) { + if (!hParams) { + LOG_ERR("CUDA Memory Provider params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + hParams->cuda_context_handle = hContext; + + return UMF_RESULT_SUCCESS; +} + +umf_result_t umfCUDAMemoryProviderParamsSetDevice( + umf_cuda_memory_provider_params_handle_t hParams, int hDevice) { + if (!hParams) { + LOG_ERR("CUDA Memory Provider params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + hParams->cuda_device_handle = hDevice; + + return UMF_RESULT_SUCCESS; +} + +umf_result_t umfCUDAMemoryProviderParamsSetMemoryType( + umf_cuda_memory_provider_params_handle_t hParams, + umf_usm_memory_type_t memoryType) { + if (!hParams) { + LOG_ERR("CUDA Memory Provider params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + hParams->memory_type = memoryType; + + return UMF_RESULT_SUCCESS; +} + static umf_result_t cu_memory_provider_initialize(void *params, void **provider) { if (params == NULL) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - cuda_memory_provider_params_t *cu_params = - (cuda_memory_provider_params_t *)params; + umf_cuda_memory_provider_params_handle_t cu_params = + (umf_cuda_memory_provider_params_handle_t)params; if (cu_params->memory_type == UMF_MEMORY_TYPE_UNKNOWN || cu_params->memory_type > UMF_MEMORY_TYPE_SHARED) { diff --git a/test/providers/cuda_helpers.cpp b/test/providers/cuda_helpers.cpp index 37e71bd6a..9c41d9382 100644 --- a/test/providers/cuda_helpers.cpp +++ b/test/providers/cuda_helpers.cpp @@ -39,9 +39,63 @@ struct libcu_ops { } libcu_ops; #if USE_DLOPEN +// Generic no-op stub function for all callbacks +template CUresult noop_stub(Args &&...) { + return CUDA_SUCCESS; // Always return CUDA_SUCCESS +} + struct DlHandleCloser { void operator()(void *dlHandle) { if (dlHandle) { + libcu_ops.cuInit = [](auto... args) { return noop_stub(args...); }; + libcu_ops.cuCtxCreate = [](auto... args) { + return noop_stub(args...); + }; + libcu_ops.cuCtxDestroy = [](auto... args) { + return noop_stub(args...); + }; + libcu_ops.cuCtxGetCurrent = [](auto... args) { + return noop_stub(args...); + }; + libcu_ops.cuCtxSetCurrent = [](auto... args) { + return noop_stub(args...); + }; + libcu_ops.cuDeviceGet = [](auto... args) { + return noop_stub(args...); + }; + libcu_ops.cuMemAlloc = [](auto... args) { + return noop_stub(args...); + }; + libcu_ops.cuMemFree = [](auto... args) { + return noop_stub(args...); + }; + libcu_ops.cuMemAllocHost = [](auto... args) { + return noop_stub(args...); + }; + libcu_ops.cuMemAllocManaged = [](auto... args) { + return noop_stub(args...); + }; + libcu_ops.cuMemFreeHost = [](auto... args) { + return noop_stub(args...); + }; + libcu_ops.cuMemsetD32 = [](auto... args) { + return noop_stub(args...); + }; + libcu_ops.cuMemcpy = [](auto... args) { + return noop_stub(args...); + }; + libcu_ops.cuPointerGetAttribute = [](auto... args) { + return noop_stub(args...); + }; + libcu_ops.cuPointerGetAttributes = [](auto... args) { + return noop_stub(args...); + }; + libcu_ops.cuStreamSynchronize = [](auto... args) { + return noop_stub(args...); + }; + libcu_ops.cuCtxSynchronize = [](auto... args) { + return noop_stub(args...); + }; utils_close_library(dlHandle); } } @@ -355,38 +409,40 @@ int init_cuda() { return InitResult; } -cuda_memory_provider_params_t -create_cuda_prov_params(umf_usm_memory_type_t memory_type) { - cuda_memory_provider_params_t params = {NULL, 0, UMF_MEMORY_TYPE_UNKNOWN}; - int ret = -1; +int get_cuda_device(CUdevice *device) { + CUdevice cuDevice = -1; - ret = init_cuda(); + int ret = init_cuda(); if (ret != 0) { - // Return empty params. Test will be skipped. - return params; + fprintf(stderr, "init_cuda() failed!\n"); + return ret; } - // Get the first CUDA device - CUdevice cuDevice = -1; CUresult res = libcu_ops.cuDeviceGet(&cuDevice, 0); if (res != CUDA_SUCCESS || cuDevice < 0) { - // Return empty params. Test will be skipped. - return params; + return -1; } - // Create a CUDA context + *device = cuDevice; + return 0; +} + +int create_context(CUdevice device, CUcontext *context) { CUcontext cuContext = nullptr; - res = libcu_ops.cuCtxCreate(&cuContext, 0, cuDevice); - if (res != CUDA_SUCCESS || cuContext == nullptr) { - // Return empty params. Test will be skipped. - return params; + + int ret = init_cuda(); + if (ret != 0) { + fprintf(stderr, "init_cuda() failed!\n"); + return ret; } - params.cuda_context_handle = cuContext; - params.cuda_device_handle = cuDevice; - params.memory_type = memory_type; + CUresult res = libcu_ops.cuCtxCreate(&cuContext, 0, device); + if (res != CUDA_SUCCESS || cuContext == nullptr) { + return -1; + } - return params; + *context = cuContext; + return 0; } int destroy_context(CUcontext context) { diff --git a/test/providers/cuda_helpers.h b/test/providers/cuda_helpers.h index fc349fc14..fc06c1fcf 100644 --- a/test/providers/cuda_helpers.h +++ b/test/providers/cuda_helpers.h @@ -26,6 +26,10 @@ extern "C" { #endif +int get_cuda_device(CUdevice *device); + +int create_context(CUdevice device, CUcontext *context); + int destroy_context(CUcontext context); int cuda_fill(CUcontext context, CUdevice device, void *ptr, size_t size, @@ -40,9 +44,6 @@ CUcontext get_mem_context(void *ptr); CUcontext get_current_context(); -cuda_memory_provider_params_t -create_cuda_prov_params(umf_usm_memory_type_t memory_type); - #ifdef __cplusplus } #endif diff --git a/test/providers/ipc_cuda_prov_common.c b/test/providers/ipc_cuda_prov_common.c index ac00bb01b..a38e4d061 100644 --- a/test/providers/ipc_cuda_prov_common.c +++ b/test/providers/ipc_cuda_prov_common.c @@ -13,10 +13,9 @@ #include "ipc_cuda_prov_common.h" void memcopy(void *dst, const void *src, size_t size, void *context) { - cuda_memory_provider_params_t *cu_params = - (cuda_memory_provider_params_t *)context; - int ret = cuda_copy(cu_params->cuda_context_handle, - cu_params->cuda_device_handle, dst, (void *)src, size); + cuda_copy_ctx_t *cu_params = (cuda_copy_ctx_t *)context; + int ret = cuda_copy(cu_params->context, cu_params->device, dst, (void *)src, + size); if (ret != 0) { fprintf(stderr, "cuda_copy failed with error %d\n", ret); } diff --git a/test/providers/ipc_cuda_prov_common.h b/test/providers/ipc_cuda_prov_common.h index cecdc2bb8..e50546efd 100644 --- a/test/providers/ipc_cuda_prov_common.h +++ b/test/providers/ipc_cuda_prov_common.h @@ -10,6 +10,11 @@ #include +typedef struct cuda_copy_ctx_t { + CUcontext context; + CUdevice device; +} cuda_copy_ctx_t; + void memcopy(void *dst, const void *src, size_t size, void *context); #endif // UMF_TEST_IPC_CUDA_PROV_COMMON_H diff --git a/test/providers/ipc_cuda_prov_consumer.c b/test/providers/ipc_cuda_prov_consumer.c index 3286cee28..1aeb5b15c 100644 --- a/test/providers/ipc_cuda_prov_consumer.c +++ b/test/providers/ipc_cuda_prov_consumer.c @@ -22,23 +22,76 @@ int main(int argc, char *argv[]) { } int port = atoi(argv[1]); + CUdevice hDevice = -1; + CUcontext hContext = NULL; - cuda_memory_provider_params_t cu_params = - create_cuda_prov_params(UMF_MEMORY_TYPE_DEVICE); + int ret = get_cuda_device(&hDevice); + if (ret != 0) { + fprintf(stderr, "get_cuda_device() failed!\n"); + return -1; + } + + ret = create_context(hDevice, &hContext); + if (ret != 0) { + fprintf(stderr, "create_context() failed!\n"); + return -1; + } + + umf_cuda_memory_provider_params_handle_t cu_params = NULL; + umf_result_t umf_result = umfCUDAMemoryProviderParamsCreate(&cu_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to create CUDA params!\n"); + ret = -1; + goto destroy_context; + } + + umf_result = umfCUDAMemoryProviderParamsSetContext(cu_params, hContext); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, + "Failed to set context in CUDA Memory Provider params!\n"); + ret = -1; + goto destroy_provider_params; + } + + umf_result = umfCUDAMemoryProviderParamsSetDevice(cu_params, hDevice); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, + "Failed to set device in CUDA Memory Provider params!\n"); + ret = -1; + goto destroy_provider_params; + } + + umf_result = umfCUDAMemoryProviderParamsSetMemoryType( + cu_params, UMF_MEMORY_TYPE_DEVICE); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to set memory type in CUDA memory " + "provider params!\n"); + ret = -1; + goto destroy_provider_params; + } umf_disjoint_pool_params_handle_t pool_params = NULL; - umf_result_t umf_result = umfDisjointPoolParamsCreate(&pool_params); + umf_result = umfDisjointPoolParamsCreate(&pool_params); if (umf_result != UMF_RESULT_SUCCESS) { fprintf(stderr, "Failed to create pool params!\n"); - return -1; + ret = -1; + goto destroy_provider_params; } - int ret = run_consumer(port, umfDisjointPoolOps(), pool_params, - umfCUDAMemoryProviderOps(), &cu_params, memcopy, - &cu_params); + cuda_copy_ctx_t copy_ctx = {hContext, hDevice}; + + ret = + run_consumer(port, umfDisjointPoolOps(), pool_params, + umfCUDAMemoryProviderOps(), cu_params, memcopy, ©_ctx); umfDisjointPoolParamsDestroy(pool_params); +destroy_provider_params: + umfCUDAMemoryProviderParamsDestroy(cu_params); + +destroy_context: + destroy_context(hContext); + return ret; } diff --git a/test/providers/ipc_cuda_prov_producer.c b/test/providers/ipc_cuda_prov_producer.c index d11004d6d..c2cd1d132 100644 --- a/test/providers/ipc_cuda_prov_producer.c +++ b/test/providers/ipc_cuda_prov_producer.c @@ -22,23 +22,76 @@ int main(int argc, char *argv[]) { } int port = atoi(argv[1]); + CUdevice hDevice = -1; + CUcontext hContext = NULL; - cuda_memory_provider_params_t cu_params = - create_cuda_prov_params(UMF_MEMORY_TYPE_DEVICE); + int ret = get_cuda_device(&hDevice); + if (ret != 0) { + fprintf(stderr, "get_cuda_device() failed!\n"); + return -1; + } + + ret = create_context(hDevice, &hContext); + if (ret != 0) { + fprintf(stderr, "create_context() failed!\n"); + return -1; + } + + umf_cuda_memory_provider_params_handle_t cu_params = NULL; + umf_result_t umf_result = umfCUDAMemoryProviderParamsCreate(&cu_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to create CUDA params!\n"); + ret = -1; + goto destroy_context; + } + + umf_result = umfCUDAMemoryProviderParamsSetContext(cu_params, hContext); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, + "Failed to set context in CUDA Memory Provider params!\n"); + ret = -1; + goto destroy_provider_params; + } + + umf_result = umfCUDAMemoryProviderParamsSetDevice(cu_params, hDevice); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, + "Failed to set device in CUDA Memory Provider params!\n"); + ret = -1; + goto destroy_provider_params; + } + + umf_result = umfCUDAMemoryProviderParamsSetMemoryType( + cu_params, UMF_MEMORY_TYPE_DEVICE); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to set memory type in CUDA memory " + "provider params!\n"); + ret = -1; + goto destroy_provider_params; + } umf_disjoint_pool_params_handle_t pool_params = NULL; - umf_result_t umf_result = umfDisjointPoolParamsCreate(&pool_params); + umf_result = umfDisjointPoolParamsCreate(&pool_params); if (umf_result != UMF_RESULT_SUCCESS) { fprintf(stderr, "Failed to create pool params!\n"); - return -1; + ret = -1; + goto destroy_provider_params; } - int ret = run_producer(port, umfDisjointPoolOps(), pool_params, - umfCUDAMemoryProviderOps(), &cu_params, memcopy, - &cu_params); + cuda_copy_ctx_t copy_ctx = {hContext, hDevice}; + + ret = + run_producer(port, umfDisjointPoolOps(), pool_params, + umfCUDAMemoryProviderOps(), cu_params, memcopy, ©_ctx); umfDisjointPoolParamsDestroy(pool_params); +destroy_provider_params: + umfCUDAMemoryProviderParamsDestroy(cu_params); + +destroy_context: + destroy_context(hContext); + return ret; } diff --git a/test/providers/provider_cuda.cpp b/test/providers/provider_cuda.cpp index 58e3beb9e..4f1d35911 100644 --- a/test/providers/provider_cuda.cpp +++ b/test/providers/provider_cuda.cpp @@ -19,6 +19,82 @@ using umf_test::test; using namespace umf_test; +class CUDATestHelper { + public: + CUDATestHelper(); + + ~CUDATestHelper() { + if (hContext_) { + destroy_context(hContext_); + } + } + + CUcontext get_test_context() const { return hContext_; } + + CUdevice get_test_device() const { return hDevice_; } + + private: + CUcontext hContext_ = nullptr; + CUdevice hDevice_ = -1; +}; + +CUDATestHelper::CUDATestHelper() { + int ret = get_cuda_device(&hDevice_); + if (ret != 0) { + fprintf(stderr, "get_cuda_device() failed!\n"); + return; + } + + ret = create_context(hDevice_, &hContext_); + if (ret != 0) { + fprintf(stderr, "create_context() failed!\n"); + return; + } +} + +using cuda_params_unique_handle_t = + std::unique_ptr; + +cuda_params_unique_handle_t +create_cuda_prov_params(CUcontext context, CUdevice device, + umf_usm_memory_type_t memory_type) { + umf_cuda_memory_provider_params_handle_t params = nullptr; + + umf_result_t res = umfCUDAMemoryProviderParamsCreate(¶ms); + if (res != UMF_RESULT_SUCCESS) { + return cuda_params_unique_handle_t(nullptr, + &umfCUDAMemoryProviderParamsDestroy); + } + + res = umfCUDAMemoryProviderParamsSetContext(params, context); + if (res != UMF_RESULT_SUCCESS) { + umfCUDAMemoryProviderParamsDestroy(params); + return cuda_params_unique_handle_t(nullptr, + &umfCUDAMemoryProviderParamsDestroy); + ; + } + + res = umfCUDAMemoryProviderParamsSetDevice(params, device); + if (res != UMF_RESULT_SUCCESS) { + umfCUDAMemoryProviderParamsDestroy(params); + return cuda_params_unique_handle_t(nullptr, + &umfCUDAMemoryProviderParamsDestroy); + ; + } + + res = umfCUDAMemoryProviderParamsSetMemoryType(params, memory_type); + if (res != UMF_RESULT_SUCCESS) { + umfCUDAMemoryProviderParamsDestroy(params); + return cuda_params_unique_handle_t(nullptr, + &umfCUDAMemoryProviderParamsDestroy); + ; + } + + return cuda_params_unique_handle_t(params, + &umfCUDAMemoryProviderParamsDestroy); +} + class CUDAMemoryAccessor : public MemoryAccessor { public: CUDAMemoryAccessor(CUcontext hContext, CUdevice hDevice) @@ -51,7 +127,8 @@ class CUDAMemoryAccessor : public MemoryAccessor { }; using CUDAProviderTestParams = - std::tuple; + std::tuple; struct umfCUDAProviderTest : umf_test::test, @@ -60,15 +137,20 @@ struct umfCUDAProviderTest void SetUp() override { test::SetUp(); - auto [cuda_params, accessor] = this->GetParam(); + auto [cuda_params, cu_context, memory_type, accessor] = + this->GetParam(); params = cuda_params; memAccessor = accessor; + expected_context = cu_context; + expected_memory_type = memory_type; } void TearDown() override { test::TearDown(); } - cuda_memory_provider_params_t params; + umf_cuda_memory_provider_params_handle_t params; MemoryAccessor *memAccessor = nullptr; + CUcontext expected_context; + umf_usm_memory_type_t expected_memory_type; }; TEST_P(umfCUDAProviderTest, basic) { @@ -79,7 +161,7 @@ TEST_P(umfCUDAProviderTest, basic) { // create CUDA provider umf_memory_provider_handle_t provider = nullptr; umf_result_t umf_result = - umfMemoryProviderCreate(umfCUDAMemoryProviderOps(), ¶ms, &provider); + umfMemoryProviderCreate(umfCUDAMemoryProviderOps(), params, &provider); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(provider, nullptr); @@ -102,14 +184,14 @@ TEST_P(umfCUDAProviderTest, basic) { memAccessor->fill(ptr, size, &pattern, sizeof(pattern)); CUcontext actual_mem_context = get_mem_context(ptr); - ASSERT_EQ(actual_mem_context, (CUcontext)params.cuda_context_handle); + ASSERT_EQ(actual_mem_context, expected_context); CUcontext actual_current_context = get_current_context(); ASSERT_EQ(actual_current_context, expected_current_context); umf_usm_memory_type_t memoryTypeActual = - get_mem_type((CUcontext)params.cuda_context_handle, ptr); - ASSERT_EQ(memoryTypeActual, params.memory_type); + get_mem_type(actual_current_context, ptr); + ASSERT_EQ(memoryTypeActual, expected_memory_type); // check if the pattern was successfully applied uint32_t *hostMemory = (uint32_t *)calloc(1, size); @@ -128,7 +210,7 @@ TEST_P(umfCUDAProviderTest, basic) { TEST_P(umfCUDAProviderTest, getPageSize) { umf_memory_provider_handle_t provider = nullptr; umf_result_t umf_result = - umfMemoryProviderCreate(umfCUDAMemoryProviderOps(), ¶ms, &provider); + umfMemoryProviderCreate(umfCUDAMemoryProviderOps(), params, &provider); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(provider, nullptr); @@ -152,7 +234,7 @@ TEST_P(umfCUDAProviderTest, getPageSize) { TEST_P(umfCUDAProviderTest, getName) { umf_memory_provider_handle_t provider = nullptr; umf_result_t umf_result = - umfMemoryProviderCreate(umfCUDAMemoryProviderOps(), ¶ms, &provider); + umfMemoryProviderCreate(umfCUDAMemoryProviderOps(), params, &provider); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(provider, nullptr); @@ -167,14 +249,14 @@ TEST_P(umfCUDAProviderTest, allocInvalidSize) { // create CUDA provider umf_memory_provider_handle_t provider = nullptr; umf_result_t umf_result = - umfMemoryProviderCreate(umfCUDAMemoryProviderOps(), ¶ms, &provider); + umfMemoryProviderCreate(umfCUDAMemoryProviderOps(), params, &provider); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(provider, nullptr); void *ptr = nullptr; // NOTE: some scenarios are invalid only for the DEVICE allocations - if (params.memory_type == UMF_MEMORY_TYPE_DEVICE) { + if (expected_memory_type == UMF_MEMORY_TYPE_DEVICE) { // try to alloc SIZE_MAX umf_result = umfMemoryProviderAlloc(provider, SIZE_MAX, 0, &ptr); ASSERT_EQ(ptr, nullptr); @@ -198,14 +280,14 @@ TEST_P(umfCUDAProviderTest, providerCreateInvalidArgs) { umfMemoryProviderCreate(umfCUDAMemoryProviderOps(), nullptr, &provider); ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); - umf_result = umfMemoryProviderCreate(nullptr, ¶ms, nullptr); + umf_result = umfMemoryProviderCreate(nullptr, params, nullptr); ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); } TEST_P(umfCUDAProviderTest, getPageSizeInvalidArgs) { umf_memory_provider_handle_t provider = nullptr; umf_result_t umf_result = - umfMemoryProviderCreate(umfCUDAMemoryProviderOps(), ¶ms, &provider); + umfMemoryProviderCreate(umfCUDAMemoryProviderOps(), params, &provider); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(provider, nullptr); @@ -218,26 +300,51 @@ TEST_P(umfCUDAProviderTest, getPageSizeInvalidArgs) { umfMemoryProviderDestroy(provider); } +TEST_P(umfCUDAProviderTest, cudaProviderNullParams) { + umf_result_t res = umfCUDAMemoryProviderParamsCreate(nullptr); + EXPECT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + res = umfCUDAMemoryProviderParamsSetContext(nullptr, expected_context); + EXPECT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + res = umfCUDAMemoryProviderParamsSetDevice(nullptr, 1); + EXPECT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + res = + umfCUDAMemoryProviderParamsSetMemoryType(nullptr, expected_memory_type); + EXPECT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} + // TODO add tests that mixes CUDA Memory Provider and Disjoint Pool -cuda_memory_provider_params_t cuParams_device_memory = - create_cuda_prov_params(UMF_MEMORY_TYPE_DEVICE); -cuda_memory_provider_params_t cuParams_shared_memory = - create_cuda_prov_params(UMF_MEMORY_TYPE_SHARED); -cuda_memory_provider_params_t cuParams_host_memory = - create_cuda_prov_params(UMF_MEMORY_TYPE_HOST); +CUDATestHelper cudaTestHelper; + +cuda_params_unique_handle_t cuParams_device_memory = create_cuda_prov_params( + cudaTestHelper.get_test_context(), cudaTestHelper.get_test_device(), + UMF_MEMORY_TYPE_DEVICE); +cuda_params_unique_handle_t cuParams_shared_memory = create_cuda_prov_params( + cudaTestHelper.get_test_context(), cudaTestHelper.get_test_device(), + UMF_MEMORY_TYPE_SHARED); +cuda_params_unique_handle_t cuParams_host_memory = create_cuda_prov_params( + cudaTestHelper.get_test_context(), cudaTestHelper.get_test_device(), + UMF_MEMORY_TYPE_HOST); -CUDAMemoryAccessor - cuAccessor((CUcontext)cuParams_device_memory.cuda_context_handle, - (CUdevice)cuParams_device_memory.cuda_device_handle); +CUDAMemoryAccessor cuAccessor(cudaTestHelper.get_test_context(), + cudaTestHelper.get_test_device()); HostMemoryAccessor hostAccessor; INSTANTIATE_TEST_SUITE_P( umfCUDAProviderTestSuite, umfCUDAProviderTest, ::testing::Values( - CUDAProviderTestParams{cuParams_device_memory, &cuAccessor}, - CUDAProviderTestParams{cuParams_shared_memory, &hostAccessor}, - CUDAProviderTestParams{cuParams_host_memory, &hostAccessor})); + CUDAProviderTestParams{cuParams_device_memory.get(), + cudaTestHelper.get_test_context(), + UMF_MEMORY_TYPE_DEVICE, &cuAccessor}, + CUDAProviderTestParams{cuParams_shared_memory.get(), + cudaTestHelper.get_test_context(), + UMF_MEMORY_TYPE_SHARED, &hostAccessor}, + CUDAProviderTestParams{cuParams_host_memory.get(), + cudaTestHelper.get_test_context(), + UMF_MEMORY_TYPE_HOST, &hostAccessor})); // TODO: add IPC API GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(umfIpcTest); @@ -246,5 +353,5 @@ INSTANTIATE_TEST_SUITE_P(umfCUDAProviderTestSuite, umfIpcTest, ::testing::Values(ipcTestParams{ umfProxyPoolOps(), nullptr, umfCUDAMemoryProviderOps(), - &cuParams_device_memory, &cuAccessor})); + cuParams_device_memory.get(), &cuAccessor, false})); */ From 8d81df93ce4a77cc656cf7730d21698ff9646473 Mon Sep 17 00:00:00 2001 From: "Kenneth Benzie (Benie)" Date: Thu, 21 Nov 2024 14:27:17 +0000 Subject: [PATCH 315/352] Fix output directory on Windows with non-VS generators On Windows when configuring CMake with the Ninja generator and `-DUMF_BUILD_SHARED_LIBRARY=ON` the `umf.dll` is output to the `${CMAKE_BINARY_DIR}/bin/$` directory, this is problematic as it breaks tools like `urinfo.exe` and `sycl-ls.exe` in development builds as they rely on `umf.dll` residing in the same directory in order to be loaded. This behavior is desirable when using Visual Studio generators, however. Therefore, this patch changes the logic to check if `CMAKE_GENERATOR` matches the `"Visual Studio"` string before appending `$` to the output directory. --- CMakeLists.txt | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f55a4198c..d1409c0c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -332,17 +332,11 @@ endforeach() set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_UMF_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) -if(MSVC) +if(CMAKE_GENERATOR MATCHES "Visual Studio" OR CMAKE_GENERATOR MATCHES + "Ninja Multi-Config") set(CMAKE_UMF_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/$) endif() -# Define a path for custom commands to work around MSVC -set(CUSTOM_COMMAND_BINARY_DIR ${CMAKE_UMF_OUTPUT_DIRECTORY}) -if(MSVC) - # MSVC implicitly adds $ to the output path - set(CUSTOM_COMMAND_BINARY_DIR ${CUSTOM_COMMAND_BINARY_DIR}/$) -endif() - # Sanitizer flags if(UMF_USE_ASAN) add_sanitizer_flag(address) From a37fbc27c777d3cb64dc3e248b3862d6083276b1 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Fri, 22 Nov 2024 22:03:55 +0100 Subject: [PATCH 316/352] Fix unreachable code error when Sanitazer is enabled --- test/poolFixtures.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/poolFixtures.hpp b/test/poolFixtures.hpp index f63a0ee63..995db981b 100644 --- a/test/poolFixtures.hpp +++ b/test/poolFixtures.hpp @@ -467,7 +467,7 @@ TEST_P(umfPoolTest, mallocUsableSize) { // Sanitizer replaces malloc_usable_size implementation with its own GTEST_SKIP() << "This test is invalid with AddressSanitizer instrumentation"; -#endif +#else for (size_t allocSize : {32, 48, 1024, 8192}) { char *ptr = static_cast(umfPoolMalloc(pool.get(), allocSize)); @@ -482,6 +482,7 @@ TEST_P(umfPoolTest, mallocUsableSize) { umfPoolFree(pool.get(), ptr); } +#endif } #endif /* UMF_TEST_POOL_FIXTURES_HPP */ From 68e9cf1d22a5506acd763ccbf5600023eea259bc Mon Sep 17 00:00:00 2001 From: Patryk Kaminski Date: Mon, 25 Nov 2024 10:24:38 +0100 Subject: [PATCH 317/352] Disable libudev in hwloc builds UMF does not link with libudev. Fixes the error on linking with a hwloc static library on systems with libudev installed: ld.lld: error: undefined symbol: udev_device_new_from_subsystem_sysname --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d1409c0c5..d647ef2a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -176,7 +176,8 @@ else() ./configure --prefix=${hwloc_targ_BINARY_DIR} --enable-static=yes --enable-shared=no --disable-libxml2 --disable-pci --disable-levelzero --disable-opencl - --disable-cuda --disable-nvml CFLAGS=-fPIC CXXFLAGS=-fPIC + --disable-cuda --disable-nvml --disable-libudev CFLAGS=-fPIC + CXXFLAGS=-fPIC WORKING_DIRECTORY ${hwloc_targ_SOURCE_DIR} OUTPUT ${hwloc_targ_SOURCE_DIR}/Makefile DEPENDS ${hwloc_targ_SOURCE_DIR}/configure) From 447093d71336cc0fe48a7ecfc01b2758bc456a23 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Tue, 19 Nov 2024 12:47:43 +0100 Subject: [PATCH 318/352] Update Level Zero provider config API --- benchmark/ubench.c | 65 +++-- examples/ipc_level_zero/ipc_level_zero.c | 45 +++- .../level_zero_shared_memory.c | 48 +++- include/umf/providers/provider_level_zero.h | 64 ++++- src/libumf.def | 6 + src/libumf.map | 6 + src/provider/provider_level_zero.c | 173 +++++++++++- test/providers/ipc_level_zero_prov_common.c | 6 +- test/providers/ipc_level_zero_prov_common.h | 7 + test/providers/ipc_level_zero_prov_consumer.c | 79 +++++- test/providers/ipc_level_zero_prov_producer.c | 79 +++++- test/providers/level_zero_helpers.cpp | 153 ++++++----- test/providers/level_zero_helpers.h | 3 - test/providers/provider_level_zero.cpp | 250 ++++++++++++++---- 14 files changed, 794 insertions(+), 190 deletions(-) diff --git a/benchmark/ubench.c b/benchmark/ubench.c index 0ac174de6..645ddb743 100644 --- a/benchmark/ubench.c +++ b/benchmark/ubench.c @@ -421,11 +421,10 @@ static void do_ipc_get_put_benchmark(alloc_t *allocs, size_t num_allocs, } } -int create_level_zero_params(level_zero_memory_provider_params_t *params) { +int create_level_zero_params(ze_context_handle_t *context, + ze_device_handle_t *device) { uint32_t driver_idx = 0; ze_driver_handle_t driver = NULL; - ze_context_handle_t context = NULL; - ze_device_handle_t device = NULL; int ret = init_level_zero(); if (ret != 0) { @@ -439,36 +438,68 @@ int create_level_zero_params(level_zero_memory_provider_params_t *params) { return ret; } - ret = create_context(driver, &context); + ret = create_context(driver, context); if (ret != 0) { fprintf(stderr, "Failed to create L0 context!\n"); return ret; } - ret = find_gpu_device(driver, &device); - if (ret || device == NULL) { + ret = find_gpu_device(driver, device); + if (ret) { fprintf(stderr, "Cannot find GPU device!\n"); - destroy_context(context); + destroy_context(*context); return ret; } - params->level_zero_context_handle = context; - params->level_zero_device_handle = device; - params->memory_type = UMF_MEMORY_TYPE_DEVICE; - return ret; } UBENCH_EX(ipc, disjoint_pool_with_level_zero_provider) { const size_t BUFFER_SIZE = 100; const size_t N_BUFFERS = 1000; - level_zero_memory_provider_params_t level_zero_params = {0}; + umf_result_t umf_result; + ze_context_handle_t context = NULL; + ze_device_handle_t device = NULL; + umf_level_zero_memory_provider_params_handle_t level_zero_params = NULL; - int ret = create_level_zero_params(&level_zero_params); + int ret = create_level_zero_params(&context, &device); if (ret != 0) { + fprintf(stderr, "error: create_level_zero_params() failed\n"); exit(-1); } + umf_result = umfLevelZeroMemoryProviderParamsCreate(&level_zero_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, + "error: umfLevelZeroMemoryProviderParamsCreate() failed\n"); + goto err_destroy_context; + } + + umf_result = + umfLevelZeroMemoryProviderParamsSetContext(level_zero_params, context); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, + "error: umfLevelZeroMemoryProviderParamsSetContext() failed\n"); + goto err_destroy_params; + } + + umf_result = + umfLevelZeroMemoryProviderParamsSetDevice(level_zero_params, device); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, + "error: umfLevelZeroMemoryProviderParamsSetDevice() failed\n"); + goto err_destroy_params; + } + + umf_result = umfLevelZeroMemoryProviderParamsSetMemoryType( + level_zero_params, UMF_MEMORY_TYPE_DEVICE); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf( + stderr, + "error: umfLevelZeroMemoryProviderParamsSetMemoryType() failed\n"); + goto err_destroy_params; + } + alloc_t *allocs = alloc_array(N_BUFFERS); if (allocs == NULL) { fprintf(stderr, "error: alloc_array() failed\n"); @@ -481,10 +512,9 @@ UBENCH_EX(ipc, disjoint_pool_with_level_zero_provider) { goto err_free_allocs; } - umf_result_t umf_result; umf_memory_provider_handle_t provider = NULL; umf_result = umfMemoryProviderCreate(umfLevelZeroMemoryProviderOps(), - &level_zero_params, &provider); + level_zero_params, &provider); if (umf_result != UMF_RESULT_SUCCESS) { fprintf(stderr, "error: umfMemoryProviderCreate() failed\n"); goto err_free_ipc_handles; @@ -570,8 +600,11 @@ UBENCH_EX(ipc, disjoint_pool_with_level_zero_provider) { err_free_allocs: free(allocs); +err_destroy_params: + umfLevelZeroMemoryProviderParamsDestroy(level_zero_params); + err_destroy_context: - destroy_context(level_zero_params.level_zero_context_handle); + destroy_context(context); } #endif /* (defined UMF_BUILD_LIBUMF_POOL_DISJOINT && defined UMF_BUILD_LEVEL_ZERO_PROVIDER && defined UMF_BUILD_GPU_TESTS) */ diff --git a/examples/ipc_level_zero/ipc_level_zero.c b/examples/ipc_level_zero/ipc_level_zero.c index cfab57b0d..fc93eb930 100644 --- a/examples/ipc_level_zero/ipc_level_zero.c +++ b/examples/ipc_level_zero/ipc_level_zero.c @@ -20,15 +20,48 @@ int create_level_zero_pool(ze_context_handle_t context, ze_device_handle_t device, umf_memory_pool_handle_t *pool) { // setup params - level_zero_memory_provider_params_t params = {0}; - params.level_zero_context_handle = context; - params.level_zero_device_handle = device; - params.memory_type = UMF_MEMORY_TYPE_DEVICE; + umf_level_zero_memory_provider_params_handle_t provider_params = NULL; + + umf_result_t umf_result = + umfLevelZeroMemoryProviderParamsCreate(&provider_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, + "ERROR: Failed to create Level Zero memory provider params!\n"); + return -1; + } + + umf_result = + umfLevelZeroMemoryProviderParamsSetContext(provider_params, context); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "ERROR: Failed to set context in Level Zero memory " + "provider params!\n"); + umfLevelZeroMemoryProviderParamsDestroy(provider_params); + return -1; + } + + umf_result = + umfLevelZeroMemoryProviderParamsSetDevice(provider_params, device); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "ERROR: Failed to set device in Level Zero memory " + "provider params!\n"); + umfLevelZeroMemoryProviderParamsDestroy(provider_params); + return -1; + } + + umf_result = umfLevelZeroMemoryProviderParamsSetMemoryType( + provider_params, UMF_MEMORY_TYPE_DEVICE); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "ERROR: Failed to set memory type in Level Zero memory " + "provider params!\n"); + umfLevelZeroMemoryProviderParamsDestroy(provider_params); + return -1; + } // create Level Zero provider umf_memory_provider_handle_t provider = 0; - umf_result_t umf_result = umfMemoryProviderCreate( - umfLevelZeroMemoryProviderOps(), ¶ms, &provider); + umf_result = umfMemoryProviderCreate(umfLevelZeroMemoryProviderOps(), + provider_params, &provider); + umfLevelZeroMemoryProviderParamsDestroy(provider_params); if (umf_result != UMF_RESULT_SUCCESS) { fprintf(stderr, "ERROR: Failed to create Level Zero memory provider!\n"); diff --git a/examples/level_zero_shared_memory/level_zero_shared_memory.c b/examples/level_zero_shared_memory/level_zero_shared_memory.c index 1a38beceb..d7f68168d 100644 --- a/examples/level_zero_shared_memory/level_zero_shared_memory.c +++ b/examples/level_zero_shared_memory/level_zero_shared_memory.c @@ -49,22 +49,51 @@ int main(void) { // Setup parameters for the Level Zero memory provider. It will be used for // allocating memory from Level Zero devices. - level_zero_memory_provider_params_t ze_memory_provider_params = {0}; - ze_memory_provider_params.level_zero_context_handle = hContext; - ze_memory_provider_params.level_zero_device_handle = hDevice; + umf_level_zero_memory_provider_params_handle_t ze_memory_provider_params = + NULL; + res = umfLevelZeroMemoryProviderParamsCreate(&ze_memory_provider_params); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to create memory provider params!\n"); + ret = -1; + goto level_zero_destroy; + } + + res = umfLevelZeroMemoryProviderParamsSetContext(ze_memory_provider_params, + hContext); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to set context in memory provider params!\n"); + ret = -1; + goto provider_params_destroy; + } + + res = umfLevelZeroMemoryProviderParamsSetDevice(ze_memory_provider_params, + hDevice); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to set device in memory provider params!\n"); + ret = -1; + goto provider_params_destroy; + } + // Set the memory type to shared to allow the memory to be accessed on both // CPU and GPU. - ze_memory_provider_params.memory_type = UMF_MEMORY_TYPE_SHARED; + res = umfLevelZeroMemoryProviderParamsSetMemoryType( + ze_memory_provider_params, UMF_MEMORY_TYPE_SHARED); + if (res != UMF_RESULT_SUCCESS) { + fprintf(stderr, + "Failed to set memory type in memory provider params!\n"); + ret = -1; + goto provider_params_destroy; + } // Create Level Zero memory provider umf_memory_provider_handle_t ze_memory_provider; - res = umfMemoryProviderCreate(umfLevelZeroMemoryProviderOps(), - &ze_memory_provider_params, - &ze_memory_provider); + res = + umfMemoryProviderCreate(umfLevelZeroMemoryProviderOps(), + ze_memory_provider_params, &ze_memory_provider); if (res != UMF_RESULT_SUCCESS) { fprintf(stderr, "Failed to create a memory provider!\n"); ret = -1; - goto level_zero_destroy; + goto provider_params_destroy; } printf("Level Zero memory provider created at %p\n", @@ -154,6 +183,9 @@ int main(void) { memory_provider_destroy: umfMemoryProviderDestroy(ze_memory_provider); +provider_params_destroy: + umfLevelZeroMemoryProviderParamsDestroy(ze_memory_provider_params); + level_zero_destroy: ret = destroy_context(hContext); return ret; diff --git a/include/umf/providers/provider_level_zero.h b/include/umf/providers/provider_level_zero.h index b3cc02851..f760c5724 100644 --- a/include/umf/providers/provider_level_zero.h +++ b/include/umf/providers/provider_level_zero.h @@ -17,20 +17,56 @@ extern "C" { typedef struct _ze_device_handle_t *ze_device_handle_t; typedef struct _ze_context_handle_t *ze_context_handle_t; -/// @brief Level Zero Memory Provider settings struct -typedef struct level_zero_memory_provider_params_t { - ze_context_handle_t - level_zero_context_handle; ///< Handle to the Level Zero context - ze_device_handle_t - level_zero_device_handle; ///< Handle to the Level Zero device - - umf_usm_memory_type_t memory_type; ///< Allocation memory type - - ze_device_handle_t * - resident_device_handles; ///< Array of devices for which the memory should be made resident - uint32_t - resident_device_count; ///< Number of devices for which the memory should be made resident -} level_zero_memory_provider_params_t; +struct umf_level_zero_memory_provider_params_t; + +/// @brief handle to the parameters of the Level Zero Memory Provider. +typedef struct umf_level_zero_memory_provider_params_t + *umf_level_zero_memory_provider_params_handle_t; + +/// @brief Create a struct to store parameters of the Level Zero Memory Provider. +/// @param hParams [out] handle to the newly created parameters struct. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfLevelZeroMemoryProviderParamsCreate( + umf_level_zero_memory_provider_params_handle_t *hParams); + +/// @brief Destroy parameters struct. +/// @param hParams handle to the parameters of the Level Zero Memory Provider. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfLevelZeroMemoryProviderParamsDestroy( + umf_level_zero_memory_provider_params_handle_t hParams); + +/// @brief Set the Level Zero context handle in the parameters struct. +/// @param hParams handle to the parameters of the Level Zero Memory Provider. +/// @param hContext handle to the Level Zero context. Cannot be \p NULL. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfLevelZeroMemoryProviderParamsSetContext( + umf_level_zero_memory_provider_params_handle_t hParams, + ze_context_handle_t hContext); + +/// @brief Set the Level Zero device handle in the parameters struct. +/// @param hParams handle to the parameters of the Level Zero Memory Provider. +/// @param hDevice handle to the Level Zero device. Can be \p NULL if memory type is \p UMF_MEMORY_TYPE_HOST. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfLevelZeroMemoryProviderParamsSetDevice( + umf_level_zero_memory_provider_params_handle_t hParams, + ze_device_handle_t hDevice); + +/// @brief Set the memory type in the parameters struct. +/// @param hParams handle to the parameters of the Level Zero Memory Provider. +/// @param memoryType memory type. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfLevelZeroMemoryProviderParamsSetMemoryType( + umf_level_zero_memory_provider_params_handle_t hParams, + umf_usm_memory_type_t memoryType); + +/// @brief Set the resident devices in the parameters struct. +/// @param hParams handle to the parameters of the Level Zero Memory Provider. +/// @param hDevices array of devices for which the memory should be made resident. +/// @param deviceCount number of devices for which the memory should be made resident. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfLevelZeroMemoryProviderParamsSetResidentDevices( + umf_level_zero_memory_provider_params_handle_t hParams, + ze_device_handle_t *hDevices, uint32_t deviceCount); umf_memory_provider_ops_t *umfLevelZeroMemoryProviderOps(void); diff --git a/src/libumf.def b/src/libumf.def index 8f29f4579..42a924bd7 100644 --- a/src/libumf.def +++ b/src/libumf.def @@ -28,6 +28,12 @@ EXPORTS umfGetIPCHandle umfGetLastFailedMemoryProvider umfLevelZeroMemoryProviderOps + umfLevelZeroMemoryProviderParamsCreate + umfLevelZeroMemoryProviderParamsDestroy + umfLevelZeroMemoryProviderParamsSetContext + umfLevelZeroMemoryProviderParamsSetDevice + umfLevelZeroMemoryProviderParamsSetMemoryType + umfLevelZeroMemoryProviderParamsSetResidentDevices umfMemoryProviderAlloc umfMemoryProviderAllocationMerge umfMemoryProviderAllocationSplit diff --git a/src/libumf.map b/src/libumf.map index f70d247b5..443194e55 100644 --- a/src/libumf.map +++ b/src/libumf.map @@ -22,6 +22,12 @@ UMF_1.0 { umfGetIPCHandle; umfGetLastFailedMemoryProvider; umfLevelZeroMemoryProviderOps; + umfLevelZeroMemoryProviderParamsCreate; + umfLevelZeroMemoryProviderParamsDestroy; + umfLevelZeroMemoryProviderParamsSetContext; + umfLevelZeroMemoryProviderParamsSetDevice; + umfLevelZeroMemoryProviderParamsSetMemoryType; + umfLevelZeroMemoryProviderParamsSetResidentDevices; umfMemoryProviderAlloc; umfMemoryProviderAllocationMerge; umfMemoryProviderAllocationSplit; diff --git a/src/provider/provider_level_zero.c b/src/provider/provider_level_zero.c index 6b4468da6..f4a3e97c2 100644 --- a/src/provider/provider_level_zero.c +++ b/src/provider/provider_level_zero.c @@ -16,6 +16,51 @@ #if defined(UMF_NO_LEVEL_ZERO_PROVIDER) +umf_result_t umfLevelZeroMemoryProviderParamsCreate( + umf_level_zero_memory_provider_params_handle_t *hParams) { + (void)hParams; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + +umf_result_t umfLevelZeroMemoryProviderParamsDestroy( + umf_level_zero_memory_provider_params_handle_t hParams) { + (void)hParams; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + +umf_result_t umfLevelZeroMemoryProviderParamsSetContext( + umf_level_zero_memory_provider_params_handle_t hParams, + ze_context_handle_t hContext) { + (void)hParams; + (void)hContext; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + +umf_result_t umfLevelZeroMemoryProviderParamsSetDevice( + umf_level_zero_memory_provider_params_handle_t hParams, + ze_device_handle_t hDevice) { + (void)hParams; + (void)hDevice; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + +umf_result_t umfLevelZeroMemoryProviderParamsSetMemoryType( + umf_level_zero_memory_provider_params_handle_t hParams, + umf_usm_memory_type_t memoryType) { + (void)hParams; + (void)memoryType; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + +umf_result_t umfLevelZeroMemoryProviderParamsSetResidentDevices( + umf_level_zero_memory_provider_params_handle_t hParams, + ze_device_handle_t *hDevices, uint32_t deviceCount) { + (void)hParams; + (void)hDevices; + (void)deviceCount; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + umf_memory_provider_ops_t *umfLevelZeroMemoryProviderOps(void) { // not supported return NULL; @@ -24,6 +69,7 @@ umf_memory_provider_ops_t *umfLevelZeroMemoryProviderOps(void) { #else // !defined(UMF_NO_LEVEL_ZERO_PROVIDER) #include "base_alloc_global.h" +#include "libumf.h" #include "utils_assert.h" #include "utils_common.h" #include "utils_concurrency.h" @@ -32,6 +78,21 @@ umf_memory_provider_ops_t *umfLevelZeroMemoryProviderOps(void) { #include "utils_sanitizers.h" #include "ze_api.h" +// Level Zero Memory Provider settings struct +typedef struct umf_level_zero_memory_provider_params_t { + ze_context_handle_t + level_zero_context_handle; ///< Handle to the Level Zero context + ze_device_handle_t + level_zero_device_handle; ///< Handle to the Level Zero device + + umf_usm_memory_type_t memory_type; ///< Allocation memory type + + ze_device_handle_t * + resident_device_handles; ///< Array of devices for which the memory should be made resident + uint32_t + resident_device_count; ///< Number of devices for which the memory should be made resident +} umf_level_zero_memory_provider_params_t; + typedef struct ze_memory_provider_t { ze_context_handle_t context; ze_device_handle_t device; @@ -134,26 +195,127 @@ static void init_ze_global_state(void) { } } +umf_result_t umfLevelZeroMemoryProviderParamsCreate( + umf_level_zero_memory_provider_params_handle_t *hParams) { + libumfInit(); + if (!hParams) { + LOG_ERR("Level zero memory provider params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + umf_level_zero_memory_provider_params_t *params = + umf_ba_global_alloc(sizeof(umf_level_zero_memory_provider_params_t)); + if (!params) { + LOG_ERR("Cannot allocate memory for Level Zero memory provider params"); + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + // Assign default values + params->level_zero_context_handle = NULL; + params->level_zero_device_handle = NULL; + params->memory_type = UMF_MEMORY_TYPE_UNKNOWN; + params->resident_device_handles = NULL; + params->resident_device_count = 0; + + *hParams = params; + + return UMF_RESULT_SUCCESS; +} + +umf_result_t umfLevelZeroMemoryProviderParamsDestroy( + umf_level_zero_memory_provider_params_handle_t hParams) { + umf_ba_global_free(hParams); + + return UMF_RESULT_SUCCESS; +} + +umf_result_t umfLevelZeroMemoryProviderParamsSetContext( + umf_level_zero_memory_provider_params_handle_t hParams, + ze_context_handle_t hContext) { + if (!hParams) { + LOG_ERR("Level zero memory provider params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + if (!hContext) { + LOG_ERR("Level zero context handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + hParams->level_zero_context_handle = hContext; + + return UMF_RESULT_SUCCESS; +} + +umf_result_t umfLevelZeroMemoryProviderParamsSetDevice( + umf_level_zero_memory_provider_params_handle_t hParams, + ze_device_handle_t hDevice) { + if (!hParams) { + LOG_ERR("Level zero memory provider params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + hParams->level_zero_device_handle = hDevice; + + return UMF_RESULT_SUCCESS; +} + +umf_result_t umfLevelZeroMemoryProviderParamsSetMemoryType( + umf_level_zero_memory_provider_params_handle_t hParams, + umf_usm_memory_type_t memoryType) { + if (!hParams) { + LOG_ERR("Level zero memory provider params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + hParams->memory_type = memoryType; + + return UMF_RESULT_SUCCESS; +} + +umf_result_t umfLevelZeroMemoryProviderParamsSetResidentDevices( + umf_level_zero_memory_provider_params_handle_t hParams, + ze_device_handle_t *hDevices, uint32_t deviceCount) { + if (!hParams) { + LOG_ERR("Level zero memory provider params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + if (deviceCount && !hDevices) { + LOG_ERR("Resident devices array is NULL, but deviceCount is not zero"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + hParams->resident_device_handles = hDevices; + hParams->resident_device_count = deviceCount; + + return UMF_RESULT_SUCCESS; +} + static umf_result_t ze_memory_provider_initialize(void *params, void **provider) { if (params == NULL) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - level_zero_memory_provider_params_t *ze_params = - (level_zero_memory_provider_params_t *)params; + umf_level_zero_memory_provider_params_handle_t ze_params = + (umf_level_zero_memory_provider_params_handle_t)params; if (!ze_params->level_zero_context_handle) { + LOG_ERR("Level Zero context handle is NULL"); return UMF_RESULT_ERROR_INVALID_ARGUMENT; } if ((ze_params->memory_type == UMF_MEMORY_TYPE_HOST) == (ze_params->level_zero_device_handle != NULL)) { + LOG_ERR("Level Zero device handle is NULL"); return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - if ((bool)ze_params->resident_device_count != - (ze_params->resident_device_handles != NULL)) { + if ((bool)ze_params->resident_device_count && + (ze_params->resident_device_handles == NULL)) { + LOG_ERR("Resident devices handles array is NULL, but device_count is " + "not zero"); return UMF_RESULT_ERROR_INVALID_ARGUMENT; } @@ -166,6 +328,7 @@ static umf_result_t ze_memory_provider_initialize(void *params, ze_memory_provider_t *ze_provider = umf_ba_global_alloc(sizeof(ze_memory_provider_t)); if (!ze_provider) { + LOG_ERR("Cannot allocate memory for Level Zero Memory Provider"); return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; } @@ -178,6 +341,7 @@ static umf_result_t ze_memory_provider_initialize(void *params, ze_provider->device, &ze_provider->device_properties)); if (ret != UMF_RESULT_SUCCESS) { + LOG_ERR("Cannot get device properties"); umf_ba_global_free(ze_provider); return ret; } @@ -190,6 +354,7 @@ static umf_result_t ze_memory_provider_initialize(void *params, ze_provider->resident_device_handles = umf_ba_global_alloc( sizeof(ze_device_handle_t) * ze_params->resident_device_count); if (!ze_provider->resident_device_handles) { + LOG_ERR("Cannot allocate memory for resident devices"); umf_ba_global_free(ze_provider); return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; } diff --git a/test/providers/ipc_level_zero_prov_common.c b/test/providers/ipc_level_zero_prov_common.c index 11813653d..8b951cfc8 100644 --- a/test/providers/ipc_level_zero_prov_common.c +++ b/test/providers/ipc_level_zero_prov_common.c @@ -13,11 +13,9 @@ #include void memcopy(void *dst, const void *src, size_t size, void *context) { - level_zero_memory_provider_params_t *l0_params = - (level_zero_memory_provider_params_t *)context; + level_zero_copy_ctx_t *l0_params = (level_zero_copy_ctx_t *)context; int ret = - level_zero_copy(l0_params->level_zero_context_handle, - l0_params->level_zero_device_handle, dst, src, size); + level_zero_copy(l0_params->context, l0_params->device, dst, src, size); if (ret != 0) { fprintf(stderr, "level_zero_copy failed with error %d\n", ret); } diff --git a/test/providers/ipc_level_zero_prov_common.h b/test/providers/ipc_level_zero_prov_common.h index dff51d08b..ea444133d 100644 --- a/test/providers/ipc_level_zero_prov_common.h +++ b/test/providers/ipc_level_zero_prov_common.h @@ -10,6 +10,13 @@ #include +#include "ze_api.h" + +typedef struct level_zero_copy_ctx_t { + ze_context_handle_t context; + ze_device_handle_t device; +} level_zero_copy_ctx_t; + void memcopy(void *dst, const void *src, size_t size, void *context); #endif // UMF_TEST_IPC_LEVEL_ZERO_PROV_COMMON_H diff --git a/test/providers/ipc_level_zero_prov_consumer.c b/test/providers/ipc_level_zero_prov_consumer.c index 4ec952f4f..7fcb031cb 100644 --- a/test/providers/ipc_level_zero_prov_consumer.c +++ b/test/providers/ipc_level_zero_prov_consumer.c @@ -22,23 +22,88 @@ int main(int argc, char *argv[]) { } int port = atoi(argv[1]); + uint32_t driver_idx = 0; + ze_driver_handle_t hDriver = NULL; + ze_device_handle_t hDevice = NULL; + ze_context_handle_t hContext = NULL; - level_zero_memory_provider_params_t l0_params = - create_level_zero_prov_params(UMF_MEMORY_TYPE_DEVICE); + int ret = find_driver_with_gpu(&driver_idx, &hDriver); + if (ret != 0 || hDriver == NULL) { + fprintf(stderr, "find_driver_with_gpu() failed!\n"); + return -1; + } + + ret = find_gpu_device(hDriver, &hDevice); + if (ret != 0 || hDevice == NULL) { + fprintf(stderr, "find_gpu_device() failed!\n"); + return -1; + } + + ret = create_context(hDriver, &hContext); + if (ret != 0) { + fprintf(stderr, "create_context() failed!\n"); + return -1; + } + + umf_level_zero_memory_provider_params_handle_t l0_params = NULL; + umf_result_t umf_result = + umfLevelZeroMemoryProviderParamsCreate(&l0_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, + "Failed to create Level Zero Memory Provider params!\n"); + ret = -1; + goto destroy_context; + } + + umf_result = + umfLevelZeroMemoryProviderParamsSetContext(l0_params, hContext); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf( + stderr, + "Failed to set context in Level Zero Memory Provider params!\n"); + ret = -1; + goto destroy_provider_params; + } + + umf_result = umfLevelZeroMemoryProviderParamsSetDevice(l0_params, hDevice); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, + "Failed to set device in Level Zero Memory Provider params!\n"); + ret = -1; + goto destroy_provider_params; + } + + umf_result = umfLevelZeroMemoryProviderParamsSetMemoryType( + l0_params, UMF_MEMORY_TYPE_DEVICE); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to set memory type in Level Zero Memory " + "Provider params!\n"); + ret = -1; + goto destroy_provider_params; + } umf_disjoint_pool_params_handle_t pool_params = NULL; - umf_result_t umf_result = umfDisjointPoolParamsCreate(&pool_params); + umf_result = umfDisjointPoolParamsCreate(&pool_params); if (umf_result != UMF_RESULT_SUCCESS) { fprintf(stderr, "Failed to create pool params!\n"); - return -1; + ret = -1; + goto destroy_provider_params; } - int ret = run_consumer(port, umfDisjointPoolOps(), pool_params, - umfLevelZeroMemoryProviderOps(), &l0_params, memcopy, - &l0_params); + level_zero_copy_ctx_t copy_ctx = {hContext, hDevice}; + + ret = run_consumer(port, umfDisjointPoolOps(), pool_params, + umfLevelZeroMemoryProviderOps(), l0_params, memcopy, + ©_ctx); umfDisjointPoolParamsDestroy(pool_params); +destroy_provider_params: + umfLevelZeroMemoryProviderParamsDestroy(l0_params); + +destroy_context: + destroy_context(hContext); + return ret; } diff --git a/test/providers/ipc_level_zero_prov_producer.c b/test/providers/ipc_level_zero_prov_producer.c index ba950c602..d9c672dee 100644 --- a/test/providers/ipc_level_zero_prov_producer.c +++ b/test/providers/ipc_level_zero_prov_producer.c @@ -22,23 +22,88 @@ int main(int argc, char *argv[]) { } int port = atoi(argv[1]); + uint32_t driver_idx = 0; + ze_driver_handle_t hDriver = NULL; + ze_device_handle_t hDevice = NULL; + ze_context_handle_t hContext = NULL; - level_zero_memory_provider_params_t l0_params = - create_level_zero_prov_params(UMF_MEMORY_TYPE_DEVICE); + int ret = find_driver_with_gpu(&driver_idx, &hDriver); + if (ret != 0 || hDriver == NULL) { + fprintf(stderr, "find_driver_with_gpu() failed!\n"); + return -1; + } + + ret = find_gpu_device(hDriver, &hDevice); + if (ret != 0 || hDevice == NULL) { + fprintf(stderr, "find_gpu_device() failed!\n"); + return -1; + } + + ret = create_context(hDriver, &hContext); + if (ret != 0) { + fprintf(stderr, "create_context() failed!\n"); + return -1; + } + + umf_level_zero_memory_provider_params_handle_t l0_params = NULL; + umf_result_t umf_result = + umfLevelZeroMemoryProviderParamsCreate(&l0_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, + "Failed to create Level Zero Memory Provider params!\n"); + ret = -1; + goto destroy_context; + } + + umf_result = + umfLevelZeroMemoryProviderParamsSetContext(l0_params, hContext); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf( + stderr, + "Failed to set context in Level Zero Memory Provider params!\n"); + ret = -1; + goto destroy_provider_params; + } + + umf_result = umfLevelZeroMemoryProviderParamsSetDevice(l0_params, hDevice); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, + "Failed to set device in Level Zero Memory Provider params!\n"); + ret = -1; + goto destroy_provider_params; + } + + umf_result = umfLevelZeroMemoryProviderParamsSetMemoryType( + l0_params, UMF_MEMORY_TYPE_DEVICE); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to set memory type in Level Zero Memory " + "Provider params!\n"); + ret = -1; + goto destroy_provider_params; + } umf_disjoint_pool_params_handle_t pool_params = NULL; - umf_result_t umf_result = umfDisjointPoolParamsCreate(&pool_params); + umf_result = umfDisjointPoolParamsCreate(&pool_params); if (umf_result != UMF_RESULT_SUCCESS) { fprintf(stderr, "Failed to create pool params!\n"); - return -1; + ret = -1; + goto destroy_provider_params; } - int ret = run_producer(port, umfDisjointPoolOps(), pool_params, - umfLevelZeroMemoryProviderOps(), &l0_params, memcopy, - &l0_params); + level_zero_copy_ctx_t copy_ctx = {hContext, hDevice}; + + ret = run_producer(port, umfDisjointPoolOps(), pool_params, + umfLevelZeroMemoryProviderOps(), l0_params, memcopy, + ©_ctx); umfDisjointPoolParamsDestroy(pool_params); +destroy_provider_params: + umfLevelZeroMemoryProviderParamsDestroy(l0_params); + +destroy_context: + destroy_context(hContext); + return ret; } diff --git a/test/providers/level_zero_helpers.cpp b/test/providers/level_zero_helpers.cpp index 4cd993956..cd387ab91 100644 --- a/test/providers/level_zero_helpers.cpp +++ b/test/providers/level_zero_helpers.cpp @@ -63,9 +63,68 @@ struct libze_ops { } libze_ops; #if USE_DLOPEN +// Generic no-op stub function for all callbacks +template ze_result_t noop_stub(Args &&...) { + return ZE_RESULT_SUCCESS; // Always return ZE_RESULT_SUCCESS +} + struct DlHandleCloser { void operator()(void *dlHandle) { if (dlHandle) { + // Reset all function pointers to no-op stubs in case the library + // but some other global object still try to call Level Zero functions. + libze_ops.zeInit = [](auto... args) { return noop_stub(args...); }; + libze_ops.zeDriverGet = [](auto... args) { + return noop_stub(args...); + }; + libze_ops.zeDeviceGet = [](auto... args) { + return noop_stub(args...); + }; + libze_ops.zeDeviceGetProperties = [](auto... args) { + return noop_stub(args...); + }; + libze_ops.zeContextCreate = [](auto... args) { + return noop_stub(args...); + }; + libze_ops.zeContextDestroy = [](auto... args) { + return noop_stub(args...); + }; + libze_ops.zeCommandQueueCreate = [](auto... args) { + return noop_stub(args...); + }; + libze_ops.zeCommandQueueDestroy = [](auto... args) { + return noop_stub(args...); + }; + libze_ops.zeCommandQueueExecuteCommandLists = [](auto... args) { + return noop_stub(args...); + }; + libze_ops.zeCommandQueueSynchronize = [](auto... args) { + return noop_stub(args...); + }; + libze_ops.zeCommandListCreate = [](auto... args) { + return noop_stub(args...); + }; + libze_ops.zeCommandListDestroy = [](auto... args) { + return noop_stub(args...); + }; + libze_ops.zeCommandListClose = [](auto... args) { + return noop_stub(args...); + }; + libze_ops.zeCommandListAppendMemoryCopy = [](auto... args) { + return noop_stub(args...); + }; + libze_ops.zeCommandListAppendMemoryFill = [](auto... args) { + return noop_stub(args...); + }; + libze_ops.zeMemGetAllocProperties = [](auto... args) { + return noop_stub(args...); + }; + libze_ops.zeMemAllocDevice = [](auto... args) { + return noop_stub(args...); + }; + libze_ops.zeMemFree = [](auto... args) { + return noop_stub(args...); + }; utils_close_library(dlHandle); } } @@ -247,12 +306,34 @@ static int init_level_zero_lib(void) { return 0; } +UTIL_ONCE_FLAG level_zero_init_flag; +int InitResult; +void init_level_zero_once() { + InitResult = InitLevelZeroOps(); + if (InitResult != 0) { + return; + } + InitResult = init_level_zero_lib(); +} + +int init_level_zero() { + utils_init_once(&level_zero_init_flag, init_level_zero_once); + + return InitResult; +} + int get_drivers(uint32_t *drivers_num_, ze_driver_handle_t **drivers_) { int ret = 0; ze_result_t ze_result; ze_driver_handle_t *drivers = NULL; uint32_t drivers_num = 0; + ret = init_level_zero(); + if (ret != 0) { + fprintf(stderr, "init_level_zero() failed!\n"); + goto init_fail; + } + ze_result = libze_ops.zeDriverGet(&drivers_num, NULL); if (ze_result != ZE_RESULT_SUCCESS) { fprintf(stderr, "zeDriverGet() failed!\n"); @@ -288,6 +369,8 @@ int get_drivers(uint32_t *drivers_num_, ze_driver_handle_t **drivers_) { free(drivers); *drivers_ = NULL; } + +init_fail: return ret; } @@ -298,6 +381,12 @@ int get_devices(ze_driver_handle_t driver, uint32_t *devices_num_, uint32_t devices_num = 0; ze_device_handle_t *devices = NULL; + ret = init_level_zero(); + if (ret != 0) { + fprintf(stderr, "init_level_zero() failed!\n"); + goto init_fail; + } + ze_result = libze_ops.zeDeviceGet(driver, &devices_num, NULL); if (ze_result != ZE_RESULT_SUCCESS) { fprintf(stderr, "zeDeviceGet() failed!\n"); @@ -333,6 +422,7 @@ int get_devices(ze_driver_handle_t driver, uint32_t *devices_num_, free(devices); devices = NULL; } +init_fail: return ret; } @@ -649,66 +739,3 @@ ze_memory_type_t get_mem_type(ze_context_handle_t context, void *ptr) { libze_ops.zeMemGetAllocProperties(context, ptr, &alloc_props, &device); return alloc_props.type; } - -UTIL_ONCE_FLAG level_zero_init_flag; -int InitResult; -void init_level_zero_once() { - InitResult = InitLevelZeroOps(); - if (InitResult != 0) { - return; - } - InitResult = init_level_zero_lib(); -} - -int init_level_zero() { - utils_init_once(&level_zero_init_flag, init_level_zero_once); - - return InitResult; -} - -level_zero_memory_provider_params_t -create_level_zero_prov_params(umf_usm_memory_type_t memory_type) { - level_zero_memory_provider_params_t params = { - NULL, NULL, UMF_MEMORY_TYPE_UNKNOWN, NULL, 0}; - uint32_t driver_idx = 0; - ze_driver_handle_t hDriver; - ze_device_handle_t hDevice; - ze_context_handle_t hContext; - int ret = -1; - - ret = init_level_zero(); - if (ret != 0) { - // Return empty params. Test will be skipped. - return params; - } - - ret = find_driver_with_gpu(&driver_idx, &hDriver); - if (ret != 0 || hDriver == NULL) { - // Return empty params. Test will be skipped. - return params; - } - - ret = find_gpu_device(hDriver, &hDevice); - if (ret != 0 || hDevice == NULL) { - // Return empty params. Test will be skipped. - return params; - } - - ret = create_context(hDriver, &hContext); - if (ret != 0) { - // Return empty params. Test will be skipped. - return params; - } - - params.level_zero_context_handle = hContext; - - if (memory_type == UMF_MEMORY_TYPE_HOST) { - params.level_zero_device_handle = NULL; - } else { - params.level_zero_device_handle = hDevice; - } - - params.memory_type = memory_type; - - return params; -} \ No newline at end of file diff --git a/test/providers/level_zero_helpers.h b/test/providers/level_zero_helpers.h index 6cd452c1c..aa76f8f55 100644 --- a/test/providers/level_zero_helpers.h +++ b/test/providers/level_zero_helpers.h @@ -38,9 +38,6 @@ int destroy_context(ze_context_handle_t context); ze_memory_type_t get_mem_type(ze_context_handle_t context, void *ptr); -level_zero_memory_provider_params_t -create_level_zero_prov_params(umf_usm_memory_type_t memory_type); - #ifdef __cplusplus } #endif diff --git a/test/providers/provider_level_zero.cpp b/test/providers/provider_level_zero.cpp index 347fa9888..06742d102 100644 --- a/test/providers/provider_level_zero.cpp +++ b/test/providers/provider_level_zero.cpp @@ -19,6 +19,92 @@ using umf_test::test; using namespace umf_test; +class LevelZeroTestHelper { + public: + LevelZeroTestHelper(); + + ~LevelZeroTestHelper() { + if (hContext_) { + destroy_context(hContext_); + } + } + + ze_context_handle_t get_test_context() const { return hContext_; } + + ze_device_handle_t get_test_device() const { return hDevice_; } + + private: + ze_driver_handle_t hDriver_ = nullptr; + ze_context_handle_t hContext_ = nullptr; + ze_device_handle_t hDevice_ = nullptr; +}; + +LevelZeroTestHelper::LevelZeroTestHelper() { + uint32_t driver_idx = 0; + + int ret = find_driver_with_gpu(&driver_idx, &hDriver_); + if (ret != 0 || hDriver_ == NULL) { + fprintf(stderr, "find_driver_with_gpu() failed!\n"); + return; + } + + ret = find_gpu_device(hDriver_, &hDevice_); + if (ret != 0 || hDevice_ == NULL) { + fprintf(stderr, "find_gpu_device() failed!\n"); + return; + } + + ret = create_context(hDriver_, &hContext_); + if (ret != 0) { + fprintf(stderr, "create_context() failed!\n"); + return; + } +} + +using level_zero_params_unique_handle_t = + std::unique_ptr; + +level_zero_params_unique_handle_t +create_level_zero_prov_params(ze_context_handle_t context, + ze_device_handle_t device, + umf_usm_memory_type_t memory_type) { + umf_level_zero_memory_provider_params_handle_t params = nullptr; + + umf_result_t res = umfLevelZeroMemoryProviderParamsCreate(¶ms); + if (res != UMF_RESULT_SUCCESS) { + return level_zero_params_unique_handle_t( + nullptr, &umfLevelZeroMemoryProviderParamsDestroy); + } + + res = umfLevelZeroMemoryProviderParamsSetContext(params, context); + if (res != UMF_RESULT_SUCCESS) { + umfLevelZeroMemoryProviderParamsDestroy(params); + return level_zero_params_unique_handle_t( + nullptr, &umfLevelZeroMemoryProviderParamsDestroy); + ; + } + + res = umfLevelZeroMemoryProviderParamsSetDevice(params, device); + if (res != UMF_RESULT_SUCCESS) { + umfLevelZeroMemoryProviderParamsDestroy(params); + return level_zero_params_unique_handle_t( + nullptr, &umfLevelZeroMemoryProviderParamsDestroy); + ; + } + + res = umfLevelZeroMemoryProviderParamsSetMemoryType(params, memory_type); + if (res != UMF_RESULT_SUCCESS) { + umfLevelZeroMemoryProviderParamsDestroy(params); + return level_zero_params_unique_handle_t( + nullptr, &umfLevelZeroMemoryProviderParamsDestroy); + ; + } + + return level_zero_params_unique_handle_t( + params, &umfLevelZeroMemoryProviderParamsDestroy); +} + struct LevelZeroProviderInit : public test, public ::testing::WithParamInterface {}; @@ -28,18 +114,32 @@ INSTANTIATE_TEST_SUITE_P(, LevelZeroProviderInit, UMF_MEMORY_TYPE_DEVICE, UMF_MEMORY_TYPE_SHARED)); +LevelZeroTestHelper l0TestHelper; + TEST_P(LevelZeroProviderInit, FailNullContext) { umf_memory_provider_ops_t *ops = umfLevelZeroMemoryProviderOps(); ASSERT_NE(ops, nullptr); auto memory_type = GetParam(); - level_zero_memory_provider_params_t params = {nullptr, nullptr, memory_type, - nullptr, 0}; + umf_level_zero_memory_provider_params_handle_t hParams = nullptr; + umf_result_t result = umfLevelZeroMemoryProviderParamsCreate(&hParams); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + result = + umfLevelZeroMemoryProviderParamsSetMemoryType(hParams, memory_type); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + result = umfLevelZeroMemoryProviderParamsSetDevice( + hParams, l0TestHelper.get_test_device()); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + + result = umfLevelZeroMemoryProviderParamsSetContext(hParams, nullptr); + ASSERT_EQ(result, UMF_RESULT_ERROR_INVALID_ARGUMENT); umf_memory_provider_handle_t provider = nullptr; - umf_result_t result = umfMemoryProviderCreate(ops, ¶ms, &provider); + result = umfMemoryProviderCreate(ops, hParams, &provider); ASSERT_EQ(result, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + umfLevelZeroMemoryProviderParamsDestroy(hParams); } TEST_P(LevelZeroProviderInit, FailNullDevice) { @@ -51,12 +151,21 @@ TEST_P(LevelZeroProviderInit, FailNullDevice) { ASSERT_NE(ops, nullptr); auto memory_type = GetParam(); - auto params = create_level_zero_prov_params(memory_type); - params.level_zero_device_handle = nullptr; + umf_level_zero_memory_provider_params_handle_t hParams = nullptr; + umf_result_t result = umfLevelZeroMemoryProviderParamsCreate(&hParams); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + result = + umfLevelZeroMemoryProviderParamsSetMemoryType(hParams, memory_type); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + result = umfLevelZeroMemoryProviderParamsSetContext( + hParams, l0TestHelper.get_test_context()); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); umf_memory_provider_handle_t provider = nullptr; - umf_result_t result = umfMemoryProviderCreate(ops, ¶ms, &provider); + result = umfMemoryProviderCreate(ops, hParams, &provider); ASSERT_EQ(result, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + umfLevelZeroMemoryProviderParamsDestroy(hParams); } TEST_F(test, FailNonNullDevice) { @@ -65,41 +174,39 @@ TEST_F(test, FailNonNullDevice) { auto memory_type = UMF_MEMORY_TYPE_HOST; - // prepare params for device to get non-null device handle - auto params = create_level_zero_prov_params(UMF_MEMORY_TYPE_DEVICE); - params.memory_type = memory_type; + umf_level_zero_memory_provider_params_handle_t hParams = nullptr; + umf_result_t result = umfLevelZeroMemoryProviderParamsCreate(&hParams); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + result = + umfLevelZeroMemoryProviderParamsSetMemoryType(hParams, memory_type); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + result = umfLevelZeroMemoryProviderParamsSetContext( + hParams, l0TestHelper.get_test_context()); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + result = umfLevelZeroMemoryProviderParamsSetDevice( + hParams, l0TestHelper.get_test_device()); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); umf_memory_provider_handle_t provider = nullptr; - umf_result_t result = umfMemoryProviderCreate(ops, ¶ms, &provider); + result = umfMemoryProviderCreate(ops, hParams, &provider); ASSERT_EQ(result, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + umfLevelZeroMemoryProviderParamsDestroy(hParams); } TEST_F(test, FailMismatchedResidentHandlesCount) { umf_memory_provider_ops_t *ops = umfLevelZeroMemoryProviderOps(); ASSERT_NE(ops, nullptr); - auto memory_type = UMF_MEMORY_TYPE_DEVICE; - - auto params = create_level_zero_prov_params(memory_type); - params.resident_device_count = 99; + umf_level_zero_memory_provider_params_handle_t hParams = nullptr; + umf_result_t result = umfLevelZeroMemoryProviderParamsCreate(&hParams); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); - umf_memory_provider_handle_t provider = nullptr; - umf_result_t result = umfMemoryProviderCreate(ops, ¶ms, &provider); + result = umfLevelZeroMemoryProviderParamsSetResidentDevices(hParams, + nullptr, 99); ASSERT_EQ(result, UMF_RESULT_ERROR_INVALID_ARGUMENT); -} - -TEST_F(test, FailMismatchedResidentHandlesPtr) { - umf_memory_provider_ops_t *ops = umfLevelZeroMemoryProviderOps(); - ASSERT_NE(ops, nullptr); - - auto memory_type = UMF_MEMORY_TYPE_DEVICE; - - auto params = create_level_zero_prov_params(memory_type); - params.resident_device_handles = ¶ms.level_zero_device_handle; - umf_memory_provider_handle_t provider = nullptr; - umf_result_t result = umfMemoryProviderCreate(ops, ¶ms, &provider); - ASSERT_EQ(result, UMF_RESULT_ERROR_INVALID_ARGUMENT); + umfLevelZeroMemoryProviderParamsDestroy(hParams); } class LevelZeroMemoryAccessor : public MemoryAccessor { @@ -130,7 +237,8 @@ class LevelZeroMemoryAccessor : public MemoryAccessor { }; using LevelZeroProviderTestParams = - std::tuple; + std::tuple; struct umfLevelZeroProviderTest : umf_test::test, @@ -139,14 +247,14 @@ struct umfLevelZeroProviderTest void SetUp() override { test::SetUp(); - auto [l0_params, accessor] = this->GetParam(); + auto [l0_params, ze_context, memory_type, accessor] = this->GetParam(); params = l0_params; memAccessor = accessor; - hContext = (ze_context_handle_t)params.level_zero_context_handle; + hContext = ze_context; ASSERT_NE(hContext, nullptr); - switch (params.memory_type) { + switch (memory_type) { case UMF_MEMORY_TYPE_DEVICE: zeMemoryTypeExpected = ZE_MEMORY_TYPE_DEVICE; break; @@ -166,7 +274,7 @@ struct umfLevelZeroProviderTest void TearDown() override { test::TearDown(); } - level_zero_memory_provider_params_t params; + umf_level_zero_memory_provider_params_handle_t params; MemoryAccessor *memAccessor = nullptr; ze_context_handle_t hContext = nullptr; ze_memory_type_t zeMemoryTypeExpected = ZE_MEMORY_TYPE_UNKNOWN; @@ -181,7 +289,7 @@ TEST_P(umfLevelZeroProviderTest, basic) { // create Level Zero provider umf_memory_provider_handle_t provider = nullptr; umf_result_t umf_result = umfMemoryProviderCreate( - umfLevelZeroMemoryProviderOps(), ¶ms, &provider); + umfLevelZeroMemoryProviderOps(), params, &provider); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(provider, nullptr); @@ -213,7 +321,7 @@ TEST_P(umfLevelZeroProviderTest, basic) { TEST_P(umfLevelZeroProviderTest, getPageSize) { umf_memory_provider_handle_t provider = nullptr; umf_result_t umf_result = umfMemoryProviderCreate( - umfLevelZeroMemoryProviderOps(), ¶ms, &provider); + umfLevelZeroMemoryProviderOps(), params, &provider); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(provider, nullptr); @@ -237,7 +345,7 @@ TEST_P(umfLevelZeroProviderTest, getPageSize) { TEST_P(umfLevelZeroProviderTest, getName) { umf_memory_provider_handle_t provider = nullptr; umf_result_t umf_result = umfMemoryProviderCreate( - umfLevelZeroMemoryProviderOps(), ¶ms, &provider); + umfLevelZeroMemoryProviderOps(), params, &provider); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(provider, nullptr); @@ -250,7 +358,7 @@ TEST_P(umfLevelZeroProviderTest, getName) { TEST_P(umfLevelZeroProviderTest, allocInvalidSize) { umf_memory_provider_handle_t provider = nullptr; umf_result_t umf_result = umfMemoryProviderCreate( - umfLevelZeroMemoryProviderOps(), ¶ms, &provider); + umfLevelZeroMemoryProviderOps(), params, &provider); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(provider, nullptr); @@ -272,14 +380,14 @@ TEST_P(umfLevelZeroProviderTest, providerCreateInvalidArgs) { umfLevelZeroMemoryProviderOps(), nullptr, &provider); ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); - umf_result = umfMemoryProviderCreate(nullptr, ¶ms, nullptr); + umf_result = umfMemoryProviderCreate(nullptr, params, nullptr); ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); } TEST_P(umfLevelZeroProviderTest, getPageSizeInvalidArgs) { umf_memory_provider_handle_t provider = nullptr; umf_result_t umf_result = umfMemoryProviderCreate( - umfLevelZeroMemoryProviderOps(), ¶ms, &provider); + umfLevelZeroMemoryProviderOps(), params, &provider); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(provider, nullptr); @@ -292,36 +400,62 @@ TEST_P(umfLevelZeroProviderTest, getPageSizeInvalidArgs) { umfMemoryProviderDestroy(provider); } -// TODO add tests that mixes Level Zero Memory Provider and Disjoint Pool +TEST_P(umfLevelZeroProviderTest, levelZeroProviderNullParams) { + umf_result_t res = umfLevelZeroMemoryProviderParamsCreate(nullptr); + EXPECT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT); -level_zero_memory_provider_params_t l0Params_device_memory = - create_level_zero_prov_params(UMF_MEMORY_TYPE_DEVICE); -level_zero_memory_provider_params_t l0Params_shared_memory = - create_level_zero_prov_params(UMF_MEMORY_TYPE_SHARED); -level_zero_memory_provider_params_t l0Params_host_memory = - create_level_zero_prov_params(UMF_MEMORY_TYPE_HOST); + res = umfLevelZeroMemoryProviderParamsSetContext(nullptr, hContext); + EXPECT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT); -LevelZeroMemoryAccessor l0Accessor( - (ze_context_handle_t)l0Params_device_memory.level_zero_context_handle, - (ze_device_handle_t)l0Params_device_memory.level_zero_device_handle); + res = umfLevelZeroMemoryProviderParamsSetDevice(nullptr, nullptr); + EXPECT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + res = umfLevelZeroMemoryProviderParamsSetMemoryType(nullptr, + UMF_MEMORY_TYPE_DEVICE); + EXPECT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} + +// TODO add tests that mixes Level Zero Memory Provider and Disjoint Pool + +level_zero_params_unique_handle_t l0Params_device_memory = + create_level_zero_prov_params(l0TestHelper.get_test_context(), + l0TestHelper.get_test_device(), + UMF_MEMORY_TYPE_DEVICE); +level_zero_params_unique_handle_t l0Params_shared_memory = + create_level_zero_prov_params(l0TestHelper.get_test_context(), + l0TestHelper.get_test_device(), + UMF_MEMORY_TYPE_SHARED); +level_zero_params_unique_handle_t l0Params_host_memory = + create_level_zero_prov_params(l0TestHelper.get_test_context(), nullptr, + UMF_MEMORY_TYPE_HOST); + +LevelZeroMemoryAccessor + l0Accessor((ze_context_handle_t)l0TestHelper.get_test_context(), + (ze_device_handle_t)l0TestHelper.get_test_device()); HostMemoryAccessor hostAccessor; INSTANTIATE_TEST_SUITE_P( umfLevelZeroProviderTestSuite, umfLevelZeroProviderTest, ::testing::Values( - LevelZeroProviderTestParams{l0Params_device_memory, &l0Accessor}, - LevelZeroProviderTestParams{l0Params_shared_memory, &hostAccessor}, - LevelZeroProviderTestParams{l0Params_host_memory, &hostAccessor})); + LevelZeroProviderTestParams{l0Params_device_memory.get(), + l0TestHelper.get_test_context(), + UMF_MEMORY_TYPE_DEVICE, &l0Accessor}, + LevelZeroProviderTestParams{l0Params_shared_memory.get(), + l0TestHelper.get_test_context(), + UMF_MEMORY_TYPE_SHARED, &hostAccessor}, + LevelZeroProviderTestParams{l0Params_host_memory.get(), + l0TestHelper.get_test_context(), + UMF_MEMORY_TYPE_HOST, &hostAccessor})); // TODO: it looks like there is some problem with IPC implementation in Level // Zero on windows. Issue: #494 #ifdef _WIN32 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(umfIpcTest); #else -INSTANTIATE_TEST_SUITE_P(umfLevelZeroProviderTestSuite, umfIpcTest, - ::testing::Values(ipcTestParams{ - umfProxyPoolOps(), nullptr, - umfLevelZeroMemoryProviderOps(), - &l0Params_device_memory, &l0Accessor, false})); +INSTANTIATE_TEST_SUITE_P( + umfLevelZeroProviderTestSuite, umfIpcTest, + ::testing::Values(ipcTestParams{ + umfProxyPoolOps(), nullptr, umfLevelZeroMemoryProviderOps(), + l0Params_device_memory.get(), &l0Accessor, false})); #endif From fb78bb6c96f894874894b7979706b1d2d47abc23 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Tue, 26 Nov 2024 08:56:20 +0100 Subject: [PATCH 319/352] Update Ubuntu versions End of Life of Ubuntu 24.04 LTS (Noble Numbat) is April 2036. End of Life of Ubuntu 22.04 LTS (Jammy Jellyfish) is April 2034. End of Life of Ubuntu 23.04 (Lunar Lobster) was January 25, 2024. Signed-off-by: Lukasz Dorau --- .github/workflows/nightly.yml | 2 +- .github/workflows/reusable_qemu.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 9fa036118..7a7363942 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -190,4 +190,4 @@ jobs: uses: ./.github/workflows/reusable_qemu.yml with: short_run: false - os: "['ubuntu-23.04', 'ubuntu-24.04']" + os: "['ubuntu-22.04', 'ubuntu-24.04']" diff --git a/.github/workflows/reusable_qemu.yml b/.github/workflows/reusable_qemu.yml index 8d9e00d64..36c125ea9 100644 --- a/.github/workflows/reusable_qemu.yml +++ b/.github/workflows/reusable_qemu.yml @@ -11,7 +11,7 @@ on: os: description: List of OSes type: string - default: '["ubuntu-23.04"]' + default: '["ubuntu-24.04"]' permissions: contents: read From ca14801424f1b661357d8b3651d24945c2a2d53b Mon Sep 17 00:00:00 2001 From: Rafal Rudnicki Date: Tue, 26 Nov 2024 09:47:00 +0100 Subject: [PATCH 320/352] disable ICX tests in nightly builds --- .github/workflows/nightly.yml | 175 +++++++++++++++++----------------- 1 file changed, 88 insertions(+), 87 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 7a7363942..2c11fcc4b 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -89,92 +89,93 @@ jobs: - name: Run tests under valgrind run: ${{github.workspace}}/test/test_valgrind.sh ${{github.workspace}} ${{github.workspace}}/build ${{matrix.tool}} - icx: - name: ICX - env: - VCPKG_PATH: "${{github.workspace}}/build/vcpkg/packages/hwloc_x64-windows;${{github.workspace}}/build/vcpkg/packages/tbb_x64-windows;${{github.workspace}}/build/vcpkg/packages/jemalloc_x64-windows" - BUILD_DIR : "${{github.workspace}}/build" - strategy: - matrix: - os: ['windows-2019', 'windows-2022'] - build_type: [Debug] - compiler: [{c: icx, cxx: icx}] - shared_library: ['ON', 'OFF'] - include: - - os: windows-2022 - build_type: Release - compiler: {c: icx, cxx: icx} - shared_library: 'ON' - - runs-on: ${{matrix.os}} - - steps: - - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - fetch-depth: 0 - - - name: Initialize vcpkg - uses: lukka/run-vcpkg@5e0cab206a5ea620130caf672fce3e4a6b5666a1 # v11.5 - with: - vcpkgGitCommitId: 3dd44b931481d7a8e9ba412621fa810232b66289 - vcpkgDirectory: ${{env.BUILD_DIR}}/vcpkg - vcpkgJsonGlob: '**/vcpkg.json' - - - name: Install dependencies - run: vcpkg install - - - name: Install Ninja - uses: seanmiddleditch/gha-setup-ninja@96bed6edff20d1dd61ecff9b75cc519d516e6401 # v5 - - - name: Download icx compiler - env: - # Link source: https://www.intel.com/content/www/us/en/developer/tools/oneapi/dpc-compiler-download.html - CMPLR_LINK: "https://registrationcenter-download.intel.com/akdlm/IRC_NAS/15a35578-2f9a-4f39-804b-3906e0a5f8fc/w_dpcpp-cpp-compiler_p_2024.2.1.83_offline.exe" - run: | - Invoke-WebRequest -Uri "${{ env.CMPLR_LINK }}" -OutFile compiler_install.exe - - - name: Install icx compiler - shell: cmd - run: | - start /b /wait .\compiler_install.exe -s -x -f extracted --log extract.log - extracted\bootstrapper.exe -s --action install --eula=accept -p=NEED_VS2017_INTEGRATION=0 ^ - -p=NEED_VS2019_INTEGRATION=0 -p=NEED_VS2022_INTEGRATION=0 --log-dir=. - - - name: Configure build - shell: cmd - run: | - call "C:\Program Files (x86)\Intel\oneAPI\setvars.bat" - call "C:\Program Files (x86)\Intel\oneAPI\setvars-vcvarsall.bat" - cmake ^ - -B ${{env.BUILD_DIR}} ^ - -DCMAKE_PREFIX_PATH="${{env.VCPKG_PATH}}" ^ - -DCMAKE_C_COMPILER=${{matrix.compiler.c}} ^ - -DCMAKE_CXX_COMPILER=${{matrix.compiler.cxx}} ^ - -G Ninja ^ - -DUMF_BUILD_SHARED_LIBRARY=${{matrix.shared_library}} ^ - -DUMF_FORMAT_CODE_STYLE=OFF ^ - -DUMF_DEVELOPER_MODE=ON ^ - -DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON ^ - -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON ^ - -DUMF_BUILD_LEVEL_ZERO_PROVIDER=ON ^ - -DUMF_BUILD_CUDA_PROVIDER=ON ^ - -DUMF_TESTS_FAIL_ON_SKIP=ON - - - name: Build UMF - shell: cmd - run: | - call "C:\Program Files (x86)\Intel\oneAPI\setvars.bat" - call "C:\Program Files (x86)\Intel\oneAPI\setvars-vcvarsall.bat" - cmake --build ${{env.BUILD_DIR}} --config ${{matrix.build_type}} -j %NUMBER_OF_PROCESSORS% - - - name: Run tests - shell: cmd - working-directory: ${{env.BUILD_DIR}} - run: | - call "C:\Program Files (x86)\Intel\oneAPI\setvars.bat" - call "C:\Program Files (x86)\Intel\oneAPI\setvars-vcvarsall.bat" - ctest -C ${{matrix.build_type}} --output-on-failure --test-dir test + # TODO fix #843 + #icx: + # name: ICX + # env: + # VCPKG_PATH: "${{github.workspace}}/build/vcpkg/packages/hwloc_x64-windows;${{github.workspace}}/build/vcpkg/packages/tbb_x64-windows;${{github.workspace}}/build/vcpkg/packages/jemalloc_x64-windows" + # BUILD_DIR : "${{github.workspace}}/build" + # strategy: + # matrix: + # os: ['windows-2019', 'windows-2022'] + # build_type: [Debug] + # compiler: [{c: icx, cxx: icx}] + # shared_library: ['ON', 'OFF'] + # include: + # - os: windows-2022 + # build_type: Release + # compiler: {c: icx, cxx: icx} + # shared_library: 'ON' + # + # runs-on: ${{matrix.os}} + # + # steps: + # - name: Checkout + # uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + # with: + # fetch-depth: 0 + # + # - name: Initialize vcpkg + # uses: lukka/run-vcpkg@5e0cab206a5ea620130caf672fce3e4a6b5666a1 # v11.5 + # with: + # vcpkgGitCommitId: 3dd44b931481d7a8e9ba412621fa810232b66289 + # vcpkgDirectory: ${{env.BUILD_DIR}}/vcpkg + # vcpkgJsonGlob: '**/vcpkg.json' + # + # - name: Install dependencies + # run: vcpkg install + # + # - name: Install Ninja + # uses: seanmiddleditch/gha-setup-ninja@96bed6edff20d1dd61ecff9b75cc519d516e6401 # v5 + # + # - name: Download icx compiler + # env: + # # Link source: https://www.intel.com/content/www/us/en/developer/tools/oneapi/dpc-compiler-download.html + # CMPLR_LINK: "https://registrationcenter-download.intel.com/akdlm/IRC_NAS/15a35578-2f9a-4f39-804b-3906e0a5f8fc/w_dpcpp-cpp-compiler_p_2024.2.1.83_offline.exe" + # run: | + # Invoke-WebRequest -Uri "${{ env.CMPLR_LINK }}" -OutFile compiler_install.exe + # + # - name: Install icx compiler + # shell: cmd + # run: | + # start /b /wait .\compiler_install.exe -s -x -f extracted --log extract.log + # extracted\bootstrapper.exe -s --action install --eula=accept -p=NEED_VS2017_INTEGRATION=0 ^ + # -p=NEED_VS2019_INTEGRATION=0 -p=NEED_VS2022_INTEGRATION=0 --log-dir=. + # + # - name: Configure build + # shell: cmd + # run: | + # call "C:\Program Files (x86)\Intel\oneAPI\setvars.bat" + # call "C:\Program Files (x86)\Intel\oneAPI\setvars-vcvarsall.bat" + # cmake ^ + # -B ${{env.BUILD_DIR}} ^ + # -DCMAKE_PREFIX_PATH="${{env.VCPKG_PATH}}" ^ + # -DCMAKE_C_COMPILER=${{matrix.compiler.c}} ^ + # -DCMAKE_CXX_COMPILER=${{matrix.compiler.cxx}} ^ + # -G Ninja ^ + # -DUMF_BUILD_SHARED_LIBRARY=${{matrix.shared_library}} ^ + # -DUMF_FORMAT_CODE_STYLE=OFF ^ + # -DUMF_DEVELOPER_MODE=ON ^ + # -DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON ^ + # -DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON ^ + # -DUMF_BUILD_LEVEL_ZERO_PROVIDER=ON ^ + # -DUMF_BUILD_CUDA_PROVIDER=ON ^ + # -DUMF_TESTS_FAIL_ON_SKIP=ON + # + # - name: Build UMF + # shell: cmd + # run: | + # call "C:\Program Files (x86)\Intel\oneAPI\setvars.bat" + # call "C:\Program Files (x86)\Intel\oneAPI\setvars-vcvarsall.bat" + # cmake --build ${{env.BUILD_DIR}} --config ${{matrix.build_type}} -j %NUMBER_OF_PROCESSORS% + # + # - name: Run tests + # shell: cmd + # working-directory: ${{env.BUILD_DIR}} + # run: | + # call "C:\Program Files (x86)\Intel\oneAPI\setvars.bat" + # call "C:\Program Files (x86)\Intel\oneAPI\setvars-vcvarsall.bat" + # ctest -C ${{matrix.build_type}} --output-on-failure --test-dir test L0: uses: ./.github/workflows/reusable_gpu.yml @@ -185,7 +186,7 @@ jobs: with: name: "CUDA" - # Full exeuction of QEMU tests + # Full execution of QEMU tests QEMU: uses: ./.github/workflows/reusable_qemu.yml with: From c063605f67c3bae69cfe23a45db8fa877323d95e Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Fri, 22 Nov 2024 13:55:53 +0100 Subject: [PATCH 321/352] Update File provider config API --- examples/dram_and_fsdax/dram_and_fsdax.c | 20 ++- include/umf/providers/provider_file_memory.h | 60 +++++--- src/libumf.def | 5 + src/libumf.map | 5 + src/provider/provider_file_memory.c | 147 +++++++++++++++++++ test/ipc_file_prov_consumer.c | 32 +++- test/ipc_file_prov_producer.c | 32 +++- test/pools/jemalloc_coarse_file.cpp | 20 ++- test/pools/scalable_coarse_file.cpp | 20 ++- test/provider_file_memory.cpp | 136 ++++++++++++++--- test/provider_file_memory_ipc.cpp | 67 ++++++--- 11 files changed, 465 insertions(+), 79 deletions(-) diff --git a/examples/dram_and_fsdax/dram_and_fsdax.c b/examples/dram_and_fsdax/dram_and_fsdax.c index 0d21ce620..ef11c186e 100644 --- a/examples/dram_and_fsdax/dram_and_fsdax.c +++ b/examples/dram_and_fsdax/dram_and_fsdax.c @@ -48,13 +48,25 @@ static umf_memory_pool_handle_t create_fsdax_pool(const char *path) { umf_memory_pool_handle_t pool_fsdax; umf_result_t umf_result; - umf_file_memory_provider_params_t params_fsdax = - umfFileMemoryProviderParamsDefault(path); + umf_file_memory_provider_params_handle_t params_fsdax = NULL; + umf_result = umfFileMemoryProviderParamsCreate(¶ms_fsdax, path); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to create the File Memory Provider params"); + return NULL; + } // FSDAX requires mapping the UMF_MEM_MAP_SHARED flag - params_fsdax.visibility = UMF_MEM_MAP_SHARED; + umf_result = umfFileMemoryProviderParamsSetVisibility(params_fsdax, + UMF_MEM_MAP_SHARED); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, + "Failed to set the visibility of the FSDAX file provider"); + umfFileMemoryProviderParamsDestroy(params_fsdax); + return NULL; + } umf_result = umfMemoryProviderCreate(umfFileMemoryProviderOps(), - ¶ms_fsdax, &provider_fsdax); + params_fsdax, &provider_fsdax); + umfFileMemoryProviderParamsDestroy(params_fsdax); if (umf_result != UMF_RESULT_SUCCESS) { fprintf(stderr, "Failed to create the FSDAX file provider"); return NULL; diff --git a/include/umf/providers/provider_file_memory.h b/include/umf/providers/provider_file_memory.h index 4b5b59b81..f652e2cb8 100644 --- a/include/umf/providers/provider_file_memory.h +++ b/include/umf/providers/provider_file_memory.h @@ -18,15 +18,45 @@ extern "C" { #define UMF_FILE_RESULTS_START_FROM 3000 /// @endcond -/// @brief Memory provider settings struct -typedef struct umf_file_memory_provider_params_t { - /// a path to the file (of maximum length PATH_MAX characters) - const char *path; - /// combination of 'umf_mem_protection_flags_t' flags - unsigned protection; - /// memory visibility mode - umf_memory_visibility_t visibility; -} umf_file_memory_provider_params_t; +struct umf_file_memory_provider_params_t; + +typedef struct umf_file_memory_provider_params_t + *umf_file_memory_provider_params_handle_t; + +/// @brief Create a struct to store parameters of the File Memory Provider. +/// @param hParams [out] handle to the newly created parameters struct. +/// @param path path to the file. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfFileMemoryProviderParamsCreate( + umf_file_memory_provider_params_handle_t *hParams, const char *path); + +/// @brief Destroy parameters struct. +/// @param hParams handle to the parameters of the File Memory Provider. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfFileMemoryProviderParamsDestroy( + umf_file_memory_provider_params_handle_t hParams); + +/// @brief Set the path in the parameters struct. +/// @param hParams handle to the parameters of the File Memory Provider. +/// @param path path to the file. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfFileMemoryProviderParamsSetPath( + umf_file_memory_provider_params_handle_t hParams, const char *path); + +/// @brief Set the protection in the parameters struct. +/// @param hParams handle to the parameters of the File Memory Provider. +/// @param protection protection. Combination of \p umf_mem_protection_flags_t flags +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfFileMemoryProviderParamsSetProtection( + umf_file_memory_provider_params_handle_t hParams, unsigned protection); + +/// @brief Set the visibility in the parameters struct. +/// @param hParams handle to the parameters of the File Memory Provider. +/// @param visibility memory visibility mode. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfFileMemoryProviderParamsSetVisibility( + umf_file_memory_provider_params_handle_t hParams, + umf_memory_visibility_t visibility); /// @brief File Memory Provider operation results typedef enum umf_file_memory_provider_native_error { @@ -38,18 +68,6 @@ typedef enum umf_file_memory_provider_native_error { umf_memory_provider_ops_t *umfFileMemoryProviderOps(void); -/// @brief Create default params for the file memory provider -static inline umf_file_memory_provider_params_t -umfFileMemoryProviderParamsDefault(const char *path) { - umf_file_memory_provider_params_t params = { - path, /* a path to the file */ - UMF_PROTECTION_READ | UMF_PROTECTION_WRITE, /* protection */ - UMF_MEM_MAP_PRIVATE, /* visibility mode */ - }; - - return params; -} - #ifdef __cplusplus } #endif diff --git a/src/libumf.def b/src/libumf.def index 42a924bd7..abb25204c 100644 --- a/src/libumf.def +++ b/src/libumf.def @@ -25,6 +25,11 @@ EXPORTS umfDevDaxMemoryProviderOps umfFree umfFileMemoryProviderOps + umfFileMemoryProviderParamsCreate + umfFileMemoryProviderParamsDestroy + umfFileMemoryProviderParamsSetPath + umfFileMemoryProviderParamsSetProtection + umfFileMemoryProviderParamsSetVisibility umfGetIPCHandle umfGetLastFailedMemoryProvider umfLevelZeroMemoryProviderOps diff --git a/src/libumf.map b/src/libumf.map index 443194e55..3a5e73f44 100644 --- a/src/libumf.map +++ b/src/libumf.map @@ -19,6 +19,11 @@ UMF_1.0 { umfDevDaxMemoryProviderOps; umfFree; umfFileMemoryProviderOps; + umfFileMemoryProviderParamsCreate; + umfFileMemoryProviderParamsDestroy; + umfFileMemoryProviderParamsSetPath; + umfFileMemoryProviderParamsSetProtection; + umfFileMemoryProviderParamsSetVisibility; umfGetIPCHandle; umfGetLastFailedMemoryProvider; umfLevelZeroMemoryProviderOps; diff --git a/src/provider/provider_file_memory.c b/src/provider/provider_file_memory.c index 09d50a625..32383a5ec 100644 --- a/src/provider/provider_file_memory.c +++ b/src/provider/provider_file_memory.c @@ -25,10 +25,46 @@ umf_memory_provider_ops_t *umfFileMemoryProviderOps(void) { return NULL; } +umf_result_t umfFileMemoryProviderParamsCreate( + umf_file_memory_provider_params_handle_t *hParams, const char *path) { + (void)hParams; + (void)path; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + +umf_result_t umfFileMemoryProviderParamsDestroy( + umf_file_memory_provider_params_handle_t hParams) { + (void)hParams; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + +umf_result_t umfFileMemoryProviderParamsSetPath( + umf_file_memory_provider_params_handle_t hParams, const char *path) { + (void)hParams; + (void)path; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + +umf_result_t umfFileMemoryProviderParamsSetProtection( + umf_file_memory_provider_params_handle_t hParams, unsigned protection) { + (void)hParams; + (void)protection; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + +umf_result_t umfFileMemoryProviderParamsSetVisibility( + umf_file_memory_provider_params_handle_t hParams, + umf_memory_visibility_t visibility) { + (void)hParams; + (void)visibility; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + #else // !defined(_WIN32) && !defined(UMF_NO_HWLOC) #include "base_alloc_global.h" #include "critnib.h" +#include "libumf.h" #include "utils_common.h" #include "utils_concurrency.h" #include "utils_log.h" @@ -67,6 +103,13 @@ typedef struct file_memory_provider_t { critnib *fd_offset_map; } file_memory_provider_t; +// File Memory Provider settings struct +typedef struct umf_file_memory_provider_params_t { + char *path; + unsigned protection; + umf_memory_visibility_t visibility; +} umf_file_memory_provider_params_t; + typedef struct file_last_native_error_t { int32_t native_error; int errno_value; @@ -748,4 +791,108 @@ umf_memory_provider_ops_t *umfFileMemoryProviderOps(void) { return &UMF_FILE_MEMORY_PROVIDER_OPS; } +umf_result_t umfFileMemoryProviderParamsCreate( + umf_file_memory_provider_params_handle_t *hParams, const char *path) { + libumfInit(); + if (hParams == NULL) { + LOG_ERR("File Memory Provider params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + if (path == NULL) { + LOG_ERR("File path is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + umf_file_memory_provider_params_handle_t params = + umf_ba_global_alloc(sizeof(*params)); + if (params == NULL) { + LOG_ERR("allocating memory for File Memory Provider params failed"); + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + params->path = NULL; + params->protection = UMF_PROTECTION_READ | UMF_PROTECTION_WRITE; + params->visibility = UMF_MEM_MAP_PRIVATE; + + umf_result_t res = umfFileMemoryProviderParamsSetPath(params, path); + if (res != UMF_RESULT_SUCCESS) { + umf_ba_global_free(params); + return res; + } + + *hParams = params; + + return UMF_RESULT_SUCCESS; +} + +umf_result_t umfFileMemoryProviderParamsDestroy( + umf_file_memory_provider_params_handle_t hParams) { + if (hParams != NULL) { + umf_ba_global_free(hParams->path); + umf_ba_global_free(hParams); + } + + return UMF_RESULT_SUCCESS; +} + +umf_result_t umfFileMemoryProviderParamsSetPath( + umf_file_memory_provider_params_handle_t hParams, const char *path) { + if (hParams == NULL) { + LOG_ERR("File Memory Provider params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + if (path == NULL) { + LOG_ERR("File path is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + size_t len = strlen(path); + if (len == 0) { + LOG_ERR("File path is empty"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + len += 1; // for the null terminator + char *new_path = NULL; + new_path = umf_ba_global_alloc(len); + if (new_path == NULL) { + LOG_ERR("allocating memory for the file path failed"); + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + strncpy(new_path, path, len); + + umf_ba_global_free(hParams->path); + hParams->path = new_path; + + return UMF_RESULT_SUCCESS; +} + +umf_result_t umfFileMemoryProviderParamsSetProtection( + umf_file_memory_provider_params_handle_t hParams, unsigned protection) { + if (hParams == NULL) { + LOG_ERR("File Memory Provider params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + hParams->protection = protection; + + return UMF_RESULT_SUCCESS; +} + +umf_result_t umfFileMemoryProviderParamsSetVisibility( + umf_file_memory_provider_params_handle_t hParams, + umf_memory_visibility_t visibility) { + if (hParams == NULL) { + LOG_ERR("File Memory Provider params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + hParams->visibility = visibility; + + return UMF_RESULT_SUCCESS; +} + #endif // !defined(_WIN32) && !defined(UMF_NO_HWLOC) diff --git a/test/ipc_file_prov_consumer.c b/test/ipc_file_prov_consumer.c index 6333552a2..0c50991a9 100644 --- a/test/ipc_file_prov_consumer.c +++ b/test/ipc_file_prov_consumer.c @@ -22,16 +22,36 @@ int main(int argc, char *argv[]) { return -1; } + int ret = 0; int port = atoi(argv[1]); char *file_name = argv[2]; - umf_file_memory_provider_params_t file_params; - file_params = umfFileMemoryProviderParamsDefault(file_name); - file_params.visibility = UMF_MEM_MAP_SHARED; + umf_file_memory_provider_params_handle_t file_params = NULL; + umf_result_t umf_result = + umfFileMemoryProviderParamsCreate(&file_params, file_name); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf( + stderr, + "[consumer] ERROR: creating File Memory Provider params failed\n"); + return -1; + } + + umf_result = umfFileMemoryProviderParamsSetVisibility(file_params, + UMF_MEM_MAP_SHARED); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "[consumer] ERROR: setting File Memory Provider " + "visibility failed\n"); + ret = -1; + goto destroy_provider_params; + } void *pool_params = NULL; - return run_consumer(port, umfScalablePoolOps(), pool_params, - umfFileMemoryProviderOps(), &file_params, memcopy, - NULL); + ret = run_consumer(port, umfScalablePoolOps(), pool_params, + umfFileMemoryProviderOps(), file_params, memcopy, NULL); + +destroy_provider_params: + umfFileMemoryProviderParamsDestroy(file_params); + + return ret; } diff --git a/test/ipc_file_prov_producer.c b/test/ipc_file_prov_producer.c index efcbdd3bf..c620437e0 100644 --- a/test/ipc_file_prov_producer.c +++ b/test/ipc_file_prov_producer.c @@ -22,16 +22,36 @@ int main(int argc, char *argv[]) { return -1; } + int ret = 0; int port = atoi(argv[1]); char *file_name = argv[2]; - umf_file_memory_provider_params_t file_params; - file_params = umfFileMemoryProviderParamsDefault(file_name); - file_params.visibility = UMF_MEM_MAP_SHARED; + umf_file_memory_provider_params_handle_t file_params = NULL; + umf_result_t umf_result = + umfFileMemoryProviderParamsCreate(&file_params, file_name); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf( + stderr, + "[producer] ERROR: creating File Memory Provider params failed\n"); + return -1; + } + + umf_result = umfFileMemoryProviderParamsSetVisibility(file_params, + UMF_MEM_MAP_SHARED); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "[producer] ERROR: setting File Memory Provider " + "visibility failed\n"); + ret = -1; + goto destroy_provider_params; + } void *pool_params = NULL; - return run_producer(port, umfScalablePoolOps(), pool_params, - umfFileMemoryProviderOps(), &file_params, memcopy, - NULL); + ret = run_producer(port, umfScalablePoolOps(), pool_params, + umfFileMemoryProviderOps(), file_params, memcopy, NULL); + +destroy_provider_params: + umfFileMemoryProviderParamsDestroy(file_params); + + return ret; } diff --git a/test/pools/jemalloc_coarse_file.cpp b/test/pools/jemalloc_coarse_file.cpp index 7eb904903..74ad36d56 100644 --- a/test/pools/jemalloc_coarse_file.cpp +++ b/test/pools/jemalloc_coarse_file.cpp @@ -7,11 +7,27 @@ #include "pool_coarse.hpp" +using file_params_unique_handle_t = + std::unique_ptr; + +file_params_unique_handle_t get_file_params_default(char *path) { + umf_file_memory_provider_params_handle_t file_params = NULL; + umf_result_t res = umfFileMemoryProviderParamsCreate(&file_params, path); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error( + "Failed to create File Memory Provider params"); + } + + return file_params_unique_handle_t(file_params, + &umfFileMemoryProviderParamsDestroy); +} + auto coarseParams = umfCoarseMemoryProviderParamsDefault(); -auto fileParams = umfFileMemoryProviderParamsDefault(FILE_PATH); +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, + umfFileMemoryProviderOps(), fileParams.get(), &coarseParams})); diff --git a/test/pools/scalable_coarse_file.cpp b/test/pools/scalable_coarse_file.cpp index b83a12338..b45c112be 100644 --- a/test/pools/scalable_coarse_file.cpp +++ b/test/pools/scalable_coarse_file.cpp @@ -7,11 +7,27 @@ #include "pool_coarse.hpp" +using file_params_unique_handle_t = + std::unique_ptr; + +file_params_unique_handle_t get_file_params_default(char *path) { + umf_file_memory_provider_params_handle_t file_params = NULL; + umf_result_t res = umfFileMemoryProviderParamsCreate(&file_params, path); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error( + "Failed to create File Memory Provider params"); + } + + return file_params_unique_handle_t(file_params, + &umfFileMemoryProviderParamsDestroy); +} + auto coarseParams = umfCoarseMemoryProviderParamsDefault(); -auto fileParams = umfFileMemoryProviderParamsDefault(FILE_PATH); +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, + umfFileMemoryProviderOps(), fileParams.get(), &coarseParams})); diff --git a/test/provider_file_memory.cpp b/test/provider_file_memory.cpp index eba7e8205..d3124aa11 100644 --- a/test/provider_file_memory.cpp +++ b/test/provider_file_memory.cpp @@ -136,11 +136,17 @@ TEST_F(test, test_if_mapped_with_MAP_SYNC) { GTEST_SKIP() << "Test skipped, UMF_TESTS_FSDAX_PATH is not set"; } - auto params = umfFileMemoryProviderParamsDefault(path); - params.visibility = UMF_MEM_MAP_SHARED; + umf_file_memory_provider_params_handle_t params = nullptr; + umf_result = umfFileMemoryProviderParamsCreate(¶ms, path); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(params, nullptr); - umf_result = umfMemoryProviderCreate(umfFileMemoryProviderOps(), ¶ms, - &hProvider); + umf_result = + umfFileMemoryProviderParamsSetVisibility(params, UMF_MEM_MAP_SHARED); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_result = + umfMemoryProviderCreate(umfFileMemoryProviderOps(), params, &hProvider); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(hProvider, nullptr); @@ -163,23 +169,52 @@ TEST_F(test, test_if_mapped_with_MAP_SYNC) { // positive tests using test_alloc_free_success -umf_file_memory_provider_params_t file_params_default = - umfFileMemoryProviderParamsDefault(FILE_PATH); +using file_params_unique_handle_t = + std::unique_ptr; + +file_params_unique_handle_t get_file_params_default(char *path) { + umf_file_memory_provider_params_handle_t file_params = NULL; + umf_result_t res = umfFileMemoryProviderParamsCreate(&file_params, path); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error( + "Failed to create File Memory Provider params"); + } + + return file_params_unique_handle_t(file_params, + &umfFileMemoryProviderParamsDestroy); +} + +file_params_unique_handle_t file_params_default = + get_file_params_default(FILE_PATH); + +file_params_unique_handle_t get_file_params_shared(char *path) { + umf_file_memory_provider_params_handle_t file_params = NULL; + umf_result_t res = umfFileMemoryProviderParamsCreate(&file_params, path); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error( + "Failed to create File Memory Provider params"); + } + + res = umfFileMemoryProviderParamsSetVisibility(file_params, + UMF_MEM_MAP_SHARED); + if (res != UMF_RESULT_SUCCESS) { + umfFileMemoryProviderParamsDestroy(file_params); + throw std::runtime_error("Failed to set visibility to shared for File " + "Memory Provider params"); + } -umf_file_memory_provider_params_t get_file_params_shared(char *path) { - umf_file_memory_provider_params_t file_params = - umfFileMemoryProviderParamsDefault(path); - file_params.visibility = UMF_MEM_MAP_SHARED; - return file_params; + return file_params_unique_handle_t(file_params, + &umfFileMemoryProviderParamsDestroy); } -umf_file_memory_provider_params_t file_params_shared = +file_params_unique_handle_t file_params_shared = get_file_params_shared(FILE_PATH); INSTANTIATE_TEST_SUITE_P(fileProviderTest, FileProviderParamsDefault, ::testing::Values(providerCreateExtParams{ umfFileMemoryProviderOps(), - &file_params_default})); + file_params_default.get()})); TEST_P(FileProviderParamsDefault, create_destroy) {} @@ -341,14 +376,74 @@ TEST_P(FileProviderParamsDefault, free_NULL) { // other negative tests +TEST_F(test, params_null_handle) { + umf_result_t umf_result = + umfFileMemoryProviderParamsCreate(nullptr, FILE_PATH); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + umf_result = umfFileMemoryProviderParamsDestroy(nullptr); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_result = umfFileMemoryProviderParamsSetPath(nullptr, FILE_PATH); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + umf_result = + umfFileMemoryProviderParamsSetProtection(nullptr, UMF_PROTECTION_READ); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + umf_result = + umfFileMemoryProviderParamsSetVisibility(nullptr, UMF_MEM_MAP_PRIVATE); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} + TEST_F(test, create_empty_path) { - umf_memory_provider_handle_t hProvider = nullptr; const char *path = ""; - auto wrong_params = umfFileMemoryProviderParamsDefault((char *)path); - auto ret = umfMemoryProviderCreate(umfFileMemoryProviderOps(), - &wrong_params, &hProvider); - EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); - EXPECT_EQ(hProvider, nullptr); + + umf_file_memory_provider_params_handle_t wrong_params = nullptr; + umf_result_t umf_result = + umfFileMemoryProviderParamsCreate(&wrong_params, path); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); + ASSERT_EQ(wrong_params, nullptr); +} + +TEST_F(test, create_null_path) { + const char *path = nullptr; + + umf_file_memory_provider_params_handle_t wrong_params = nullptr; + umf_result_t umf_result = + umfFileMemoryProviderParamsCreate(&wrong_params, path); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); + ASSERT_EQ(wrong_params, nullptr); +} + +TEST_F(test, set_empty_path) { + const char *empty_path = ""; + + umf_file_memory_provider_params_handle_t params = nullptr; + umf_result_t umf_result = + umfFileMemoryProviderParamsCreate(¶ms, FILE_PATH); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_result = umfFileMemoryProviderParamsSetPath(params, empty_path); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + umf_result = umfFileMemoryProviderParamsDestroy(params); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); +} + +TEST_F(test, set_null_path) { + const char *null_path = nullptr; + + umf_file_memory_provider_params_handle_t params = nullptr; + umf_result_t umf_result = + umfFileMemoryProviderParamsCreate(¶ms, FILE_PATH); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_result = umfFileMemoryProviderParamsSetPath(params, null_path); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + umf_result = umfFileMemoryProviderParamsDestroy(params); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); } TEST_P(FileProviderParamsDefault, free_INVALID_POINTER_SIZE_GT_0) { @@ -376,7 +471,8 @@ TEST_P(FileProviderParamsDefault, purge_force_INVALID_POINTER) { INSTANTIATE_TEST_SUITE_P(fileProviderTest, FileProviderParamsShared, ::testing::Values(providerCreateExtParams{ - umfFileMemoryProviderOps(), &file_params_shared})); + umfFileMemoryProviderOps(), + file_params_shared.get()})); TEST_P(FileProviderParamsShared, IPC_base_success_test) { umf_result_t umf_result; diff --git a/test/provider_file_memory_ipc.cpp b/test/provider_file_memory_ipc.cpp index 5bba5de50..ee7ab6c8f 100644 --- a/test/provider_file_memory_ipc.cpp +++ b/test/provider_file_memory_ipc.cpp @@ -17,24 +17,55 @@ using umf_test::test; #define FILE_PATH ((char *)"tmp_file") -umf_file_memory_provider_params_t get_file_params_shared(char *path) { - umf_file_memory_provider_params_t file_params = - umfFileMemoryProviderParamsDefault(path); - file_params.visibility = UMF_MEM_MAP_SHARED; - return file_params; +using file_params_unique_handle_t = + std::unique_ptr; + +file_params_unique_handle_t get_file_params_shared(char *path) { + umf_file_memory_provider_params_handle_t file_params = NULL; + umf_result_t res = umfFileMemoryProviderParamsCreate(&file_params, path); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error( + "Failed to create File Memory Provider params"); + } + + res = umfFileMemoryProviderParamsSetVisibility(file_params, + UMF_MEM_MAP_SHARED); + if (res != UMF_RESULT_SUCCESS) { + umfFileMemoryProviderParamsDestroy(file_params); + throw std::runtime_error("Failed to set visibility to shared for File " + "Memory Provider params"); + } + + return file_params_unique_handle_t(file_params, + &umfFileMemoryProviderParamsDestroy); } -umf_file_memory_provider_params_t file_params_shared = +file_params_unique_handle_t file_params_shared = get_file_params_shared(FILE_PATH); -umf_file_memory_provider_params_t get_file_params_fsdax(char *path) { - umf_file_memory_provider_params_t file_params = - umfFileMemoryProviderParamsDefault(path); - file_params.visibility = UMF_MEM_MAP_SHARED; - return file_params; +file_params_unique_handle_t get_file_params_fsdax(char *path) { + umf_file_memory_provider_params_handle_t file_params = NULL; + umf_result_t res = umfFileMemoryProviderParamsCreate(&file_params, path); + if (res != UMF_RESULT_SUCCESS) { + //test will be skipped. + return file_params_unique_handle_t(nullptr, + &umfFileMemoryProviderParamsDestroy); + } + + res = umfFileMemoryProviderParamsSetVisibility(file_params, + UMF_MEM_MAP_SHARED); + if (res != UMF_RESULT_SUCCESS) { + umfFileMemoryProviderParamsDestroy(file_params); + throw std::runtime_error("Failed to set visibility to shared for File " + "Memory Provider params"); + } + + return file_params_unique_handle_t(file_params, + &umfFileMemoryProviderParamsDestroy); } -umf_file_memory_provider_params_t file_params_fsdax = +file_params_unique_handle_t file_params_fsdax = get_file_params_fsdax(getenv("UMF_TESTS_FSDAX_PATH")); HostMemoryAccessor hostAccessor; @@ -42,14 +73,14 @@ HostMemoryAccessor hostAccessor; static std::vector ipcManyPoolsTestParamsList = { // TODO: enable it when sizes of allocations in ipcFixtures.hpp are fixed // {umfProxyPoolOps(), nullptr, umfFileMemoryProviderOps(), -// &file_params_shared, &hostAccessor, true}, +// file_params_shared.get(), &hostAccessor, true}, #ifdef UMF_POOL_JEMALLOC_ENABLED {umfJemallocPoolOps(), nullptr, umfFileMemoryProviderOps(), - &file_params_shared, &hostAccessor, false}, + file_params_shared.get(), &hostAccessor, false}, #endif #ifdef UMF_POOL_SCALABLE_ENABLED {umfScalablePoolOps(), nullptr, umfFileMemoryProviderOps(), - &file_params_shared, &hostAccessor, false}, + file_params_shared.get(), &hostAccessor, false}, #endif }; @@ -65,14 +96,14 @@ static std::vector getIpcFsDaxTestParamsList(void) { ipcFsDaxTestParamsList = { // TODO: enable it when sizes of allocations in ipcFixtures.hpp are fixed // {umfProxyPoolOps(), nullptr, umfFileMemoryProviderOps(), -// &file_params_fsdax, &hostAccessor, true}, +// file_params_fsdax.get(), &hostAccessor, true}, #ifdef UMF_POOL_JEMALLOC_ENABLED {umfJemallocPoolOps(), nullptr, umfFileMemoryProviderOps(), - &file_params_fsdax, &hostAccessor, false}, + file_params_fsdax.get(), &hostAccessor, false}, #endif #ifdef UMF_POOL_SCALABLE_ENABLED {umfScalablePoolOps(), nullptr, umfFileMemoryProviderOps(), - &file_params_fsdax, &hostAccessor, false}, + file_params_fsdax.get(), &hostAccessor, false}, #endif }; From 31372be8ce1199f924eee9e5a79b845c58bbeff2 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Tue, 26 Nov 2024 10:26:57 +0100 Subject: [PATCH 322/352] Add test for not implemented file provider --- test/CMakeLists.txt | 5 ++++ test/provider_file_memory_not_impl.cpp | 33 ++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 test/provider_file_memory_not_impl.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 1f2ef5959..051e75949 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -338,6 +338,11 @@ if(LINUX AND (NOT UMF_DISABLE_HWLOC)) # OS-specific functions are implemented if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND UMF_BUILD_FUZZTESTS) add_subdirectory(fuzz) endif() +else() + add_umf_test( + NAME provider_file_memory_not_impl + SRCS provider_file_memory_not_impl.cpp + LIBS ${UMF_UTILS_FOR_TEST}) endif() if(UMF_BUILD_GPU_TESTS AND UMF_BUILD_LEVEL_ZERO_PROVIDER) diff --git a/test/provider_file_memory_not_impl.cpp b/test/provider_file_memory_not_impl.cpp new file mode 100644 index 000000000..c82b8163c --- /dev/null +++ b/test/provider_file_memory_not_impl.cpp @@ -0,0 +1,33 @@ +// Copyright (C) 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 "base.hpp" + +#include + +using umf_test::test; + +TEST_F(test, file_provider_not_implemented) { + umf_file_memory_provider_params_handle_t params = nullptr; + umf_result_t umf_result = + umfFileMemoryProviderParamsCreate(¶ms, "path"); + EXPECT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); + EXPECT_EQ(params, nullptr); + + umf_result = umfFileMemoryProviderParamsDestroy(nullptr); + EXPECT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); + + umf_result = umfFileMemoryProviderParamsSetPath(nullptr, "path"); + EXPECT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); + + umf_result = umfFileMemoryProviderParamsSetProtection(nullptr, 0); + EXPECT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); + + umf_result = + umfFileMemoryProviderParamsSetVisibility(nullptr, UMF_MEM_MAP_PRIVATE); + EXPECT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); + + umf_memory_provider_ops_t *ops = umfFileMemoryProviderOps(); + EXPECT_EQ(ops, nullptr); +} \ No newline at end of file From c1cb0d28dc152c0e74ffd73fd283b25c8e04f8e9 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Tue, 26 Nov 2024 11:34:30 +0100 Subject: [PATCH 323/352] Add tests for utils_posix_common.c Ref: #923 Signed-off-by: Lukasz Dorau --- src/utils/utils_common.h | 8 ++- src/utils/utils_posix_common.c | 13 +++-- src/utils/utils_windows_common.c | 10 ++++ test/utils/utils_linux.cpp | 92 ++++++++++++++++++++++++++++++++ 4 files changed, 115 insertions(+), 8 deletions(-) diff --git a/src/utils/utils_common.h b/src/utils/utils_common.h index 6920d97cf..9ef2b3cf1 100644 --- a/src/utils/utils_common.h +++ b/src/utils/utils_common.h @@ -23,8 +23,10 @@ extern "C" { #endif typedef enum umf_purge_advise_t { - UMF_PURGE_LAZY, + UMF_PURGE_LAZY = 1, UMF_PURGE_FORCE, + + UMF_PURGE_MAX, // must be the last one } umf_purge_advise_t; #define DO_WHILE_EMPTY \ @@ -117,6 +119,8 @@ int utils_gettid(void); // close file descriptor int utils_close_fd(int fd); +umf_result_t utils_errno_to_umf_result(int err); + // obtain a duplicate of another process's file descriptor umf_result_t utils_duplicate_fd(int pid, int fd_in, int *fd_out); @@ -130,6 +134,8 @@ umf_result_t utils_translate_flags(unsigned in_flags, unsigned max, umf_result_t utils_translate_mem_protection_flags(unsigned in_protection, unsigned *out_protection); +int utils_translate_purge_advise(umf_purge_advise_t advise); + umf_result_t utils_translate_mem_visibility_flag(umf_memory_visibility_t in_flag, unsigned *out_flag); diff --git a/src/utils/utils_posix_common.c b/src/utils/utils_posix_common.c index b0add36b9..4a60cbb1f 100644 --- a/src/utils/utils_posix_common.c +++ b/src/utils/utils_posix_common.c @@ -64,8 +64,7 @@ int utils_gettid(void) { int utils_close_fd(int fd) { return close(fd); } -#ifndef __APPLE__ -static umf_result_t errno_to_umf_result(int err) { +umf_result_t utils_errno_to_umf_result(int err) { switch (err) { case EBADF: case EINVAL: @@ -83,7 +82,6 @@ static umf_result_t errno_to_umf_result(int err) { return UMF_RESULT_ERROR_UNKNOWN; } } -#endif umf_result_t utils_duplicate_fd(int pid, int fd_in, int *fd_out) { #ifdef __APPLE__ @@ -102,14 +100,14 @@ umf_result_t utils_duplicate_fd(int pid, int fd_in, int *fd_out) { int pid_fd = syscall(__NR_pidfd_open, pid, 0); if (pid_fd == -1) { LOG_PERR("__NR_pidfd_open"); - return errno_to_umf_result(errno); + return utils_errno_to_umf_result(errno); } int fd_dup = syscall(__NR_pidfd_getfd, pid_fd, fd_in, 0); close(pid_fd); if (fd_dup == -1) { LOG_PERR("__NR_pidfd_open"); - return errno_to_umf_result(errno); + return utils_errno_to_umf_result(errno); } *fd_out = fd_dup; @@ -147,14 +145,15 @@ umf_result_t utils_translate_mem_protection_flags(unsigned in_protection, out_protection); } -static int utils_translate_purge_advise(umf_purge_advise_t advise) { +int utils_translate_purge_advise(umf_purge_advise_t advise) { switch (advise) { case UMF_PURGE_LAZY: return MADV_FREE; case UMF_PURGE_FORCE: return MADV_DONTNEED; + default: + return -1; } - return -1; } void *utils_mmap(void *hint_addr, size_t length, int prot, int flag, int fd, diff --git a/src/utils/utils_windows_common.c b/src/utils/utils_windows_common.c index e941b317d..b6c5b0b4e 100644 --- a/src/utils/utils_windows_common.c +++ b/src/utils/utils_windows_common.c @@ -45,6 +45,11 @@ int utils_close_fd(int fd) { return -1; } +umf_result_t utils_errno_to_umf_result(int err) { + (void)err; // unused + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + umf_result_t utils_duplicate_fd(int pid, int fd_in, int *fd_out) { (void)pid; // unused (void)fd_in; // unused @@ -87,6 +92,11 @@ umf_result_t utils_translate_mem_protection_flags(unsigned in_protection, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } +int utils_translate_purge_advise(umf_purge_advise_t advise) { + (void)advise; // unused + return -1; +} + umf_result_t utils_translate_mem_visibility_flag(umf_memory_visibility_t in_flag, unsigned *out_flag) { diff --git a/test/utils/utils_linux.cpp b/test/utils/utils_linux.cpp index cbe99ae74..7aa0a9d83 100644 --- a/test/utils/utils_linux.cpp +++ b/test/utils/utils_linux.cpp @@ -2,6 +2,8 @@ // Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include + #include "base.hpp" #include "utils/utils_common.h" @@ -77,3 +79,93 @@ TEST_F(test, utils_get_size_threshold) { EXPECT_EQ(utils_get_size_threshold((char *)"size.threshold=abc"), -1); EXPECT_EQ(utils_get_size_threshold((char *)"size.threshold=-111"), -1); } + +TEST_F(test, utils_errno_to_umf_result) { + EXPECT_EQ(utils_errno_to_umf_result(EBADF), + UMF_RESULT_ERROR_INVALID_ARGUMENT); + EXPECT_EQ(utils_errno_to_umf_result(EINVAL), + UMF_RESULT_ERROR_INVALID_ARGUMENT); + EXPECT_EQ(utils_errno_to_umf_result(ESRCH), + UMF_RESULT_ERROR_INVALID_ARGUMENT); + EXPECT_EQ(utils_errno_to_umf_result(EPERM), + UMF_RESULT_ERROR_INVALID_ARGUMENT); + + EXPECT_EQ(utils_errno_to_umf_result(EMFILE), + UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY); + EXPECT_EQ(utils_errno_to_umf_result(ENOMEM), + UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY); + + EXPECT_EQ(utils_errno_to_umf_result(ENODEV), + UMF_RESULT_ERROR_NOT_SUPPORTED); + EXPECT_EQ(utils_errno_to_umf_result(ENOSYS), + UMF_RESULT_ERROR_NOT_SUPPORTED); + EXPECT_EQ(utils_errno_to_umf_result(ENOTSUP), + UMF_RESULT_ERROR_NOT_SUPPORTED); + + EXPECT_EQ(utils_errno_to_umf_result(E2BIG), UMF_RESULT_ERROR_UNKNOWN); +} + +TEST_F(test, utils_translate_mem_protection_flags) { + umf_result_t umf_result; + unsigned out_protection; + + umf_result = utils_translate_mem_protection_flags(UMF_PROTECTION_NONE, + &out_protection); + EXPECT_EQ(umf_result, UMF_RESULT_SUCCESS); + EXPECT_EQ(out_protection, PROT_NONE); + + umf_result = utils_translate_mem_protection_flags(UMF_PROTECTION_READ, + &out_protection); + EXPECT_EQ(umf_result, UMF_RESULT_SUCCESS); + EXPECT_EQ(out_protection, PROT_READ); + + umf_result = utils_translate_mem_protection_flags(UMF_PROTECTION_WRITE, + &out_protection); + EXPECT_EQ(umf_result, UMF_RESULT_SUCCESS); + EXPECT_EQ(out_protection, PROT_WRITE); + + umf_result = utils_translate_mem_protection_flags(UMF_PROTECTION_EXEC, + &out_protection); + EXPECT_EQ(umf_result, UMF_RESULT_SUCCESS); + EXPECT_EQ(out_protection, PROT_EXEC); + + umf_result = utils_translate_mem_protection_flags( + UMF_PROTECTION_READ | UMF_PROTECTION_WRITE, &out_protection); + EXPECT_EQ(umf_result, UMF_RESULT_SUCCESS); + EXPECT_EQ(out_protection, PROT_READ | PROT_WRITE); + + umf_result = utils_translate_mem_protection_flags( + UMF_PROTECTION_READ | UMF_PROTECTION_WRITE | UMF_PROTECTION_EXEC, + &out_protection); + EXPECT_EQ(umf_result, UMF_RESULT_SUCCESS); + EXPECT_EQ(out_protection, PROT_READ | PROT_WRITE | PROT_EXEC); + + umf_result = utils_translate_mem_protection_flags( + UMF_PROTECTION_READ | UMF_PROTECTION_EXEC, &out_protection); + EXPECT_EQ(umf_result, UMF_RESULT_SUCCESS); + EXPECT_EQ(out_protection, PROT_READ | PROT_EXEC); + + umf_result = utils_translate_mem_protection_flags( + UMF_PROTECTION_WRITE | UMF_PROTECTION_EXEC, &out_protection); + EXPECT_EQ(umf_result, UMF_RESULT_SUCCESS); + EXPECT_EQ(out_protection, PROT_WRITE | PROT_EXEC); + + // see https://github.com/oneapi-src/unified-memory-framework/issues/923 + out_protection = 0; + umf_result = utils_translate_mem_protection_flags( + 0xFFFF & ~(((UMF_PROTECTION_MAX - 1) << 1) - 1), &out_protection); + EXPECT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); + EXPECT_EQ(out_protection, 0); +} + +TEST_F(test, utils_translate_purge_advise) { + EXPECT_EQ(utils_translate_purge_advise(UMF_PURGE_LAZY), MADV_FREE); + EXPECT_EQ(utils_translate_purge_advise(UMF_PURGE_FORCE), MADV_DONTNEED); + EXPECT_EQ(utils_translate_purge_advise(UMF_PURGE_MAX), -1); +} + +TEST_F(test, utils_open) { + EXPECT_EQ(utils_devdax_open(NULL), -1); + EXPECT_EQ(utils_file_open(NULL), -1); + EXPECT_EQ(utils_file_open_or_create(NULL), -1); +} From 9dfe4c9caef93686c4f2921fd168da804668c20e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Mon, 4 Nov 2024 16:46:40 +0100 Subject: [PATCH 324/352] Bump Level Zero Loader version to v1.19.2 --- CMakeLists.txt | 2 +- examples/ipc_level_zero/CMakeLists.txt | 2 +- examples/level_zero_shared_memory/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d647ef2a3..cc3a24e5f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -231,7 +231,7 @@ if(UMF_BUILD_LEVEL_ZERO_PROVIDER AND (NOT UMF_LEVEL_ZERO_INCLUDE_DIR)) include(FetchContent) set(LEVEL_ZERO_LOADER_REPO "https://github.com/oneapi-src/level-zero.git") - set(LEVEL_ZERO_LOADER_TAG v1.17.39) + set(LEVEL_ZERO_LOADER_TAG v1.19.2) message( STATUS diff --git a/examples/ipc_level_zero/CMakeLists.txt b/examples/ipc_level_zero/CMakeLists.txt index 01c96d875..78d0e667a 100644 --- a/examples/ipc_level_zero/CMakeLists.txt +++ b/examples/ipc_level_zero/CMakeLists.txt @@ -24,7 +24,7 @@ endif() include(FetchContent) set(LEVEL_ZERO_LOADER_REPO "https://github.com/oneapi-src/level-zero.git") -set(LEVEL_ZERO_LOADER_TAG v1.17.39) +set(LEVEL_ZERO_LOADER_TAG v1.19.2) message( STATUS diff --git a/examples/level_zero_shared_memory/CMakeLists.txt b/examples/level_zero_shared_memory/CMakeLists.txt index 042879c5c..21edf9a84 100644 --- a/examples/level_zero_shared_memory/CMakeLists.txt +++ b/examples/level_zero_shared_memory/CMakeLists.txt @@ -24,7 +24,7 @@ endif() include(FetchContent) set(LEVEL_ZERO_LOADER_REPO "https://github.com/oneapi-src/level-zero.git") -set(LEVEL_ZERO_LOADER_TAG v1.17.39) +set(LEVEL_ZERO_LOADER_TAG v1.19.2) message( STATUS From 67127a581ae59fd233e2a87c862b4ebca9530a28 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Wed, 27 Nov 2024 02:08:36 -0800 Subject: [PATCH 325/352] Fix failure with destructor order in CUDA params --- src/provider/provider_cuda.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/provider/provider_cuda.c b/src/provider/provider_cuda.c index 3c4e39451..baccbd023 100644 --- a/src/provider/provider_cuda.c +++ b/src/provider/provider_cuda.c @@ -68,6 +68,7 @@ umf_memory_provider_ops_t *umfCUDAMemoryProviderOps(void) { #endif // _MSC_VER #include "base_alloc_global.h" +#include "libumf.h" #include "utils_assert.h" #include "utils_common.h" #include "utils_concurrency.h" @@ -201,6 +202,7 @@ static void init_cu_global_state(void) { umf_result_t umfCUDAMemoryProviderParamsCreate( umf_cuda_memory_provider_params_handle_t *hParams) { + libumfInit(); if (!hParams) { LOG_ERR("CUDA Memory Provider params handle is NULL"); return UMF_RESULT_ERROR_INVALID_ARGUMENT; From 942d2fd79b1a8f126199af67f19afde26bd078d7 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Thu, 21 Nov 2024 23:47:45 +0100 Subject: [PATCH 326/352] Update OS provider config API --- benchmark/multithread.cpp | 13 +- benchmark/ubench.c | 76 +++-- examples/basic/basic.c | 11 +- examples/dram_and_fsdax/dram_and_fsdax.c | 11 +- examples/ipc_ipcapi/ipc_ipcapi_consumer.c | 29 +- examples/ipc_ipcapi/ipc_ipcapi_producer.c | 29 +- include/umf/providers/provider_os_memory.h | 114 ++++--- src/libumf.def | 9 + src/libumf.map | 9 + src/memtargets/memtarget_numa.c | 90 +++-- src/provider/provider_os_memory.c | 273 +++++++++++++++ src/proxy_lib/proxy_lib.c | 41 ++- test/c_api/multi_pool.c | 10 +- test/fuzz/umfFuzz.cpp | 11 +- test/ipc_os_prov_consumer.c | 38 ++- test/ipc_os_prov_producer.c | 38 ++- test/pools/jemalloc_pool.cpp | 30 +- test/pools/scalable_pool.cpp | 18 +- test/provider_os_memory.cpp | 89 +++-- test/provider_os_memory_config.cpp | 161 +++++++-- ...provider_os_memory_multiple_numa_nodes.cpp | 321 +++++++++++++----- 21 files changed, 1129 insertions(+), 292 deletions(-) diff --git a/benchmark/multithread.cpp b/benchmark/multithread.cpp index c698ed045..efb46729c 100644 --- a/benchmark/multithread.cpp +++ b/benchmark/multithread.cpp @@ -91,7 +91,12 @@ static void mt_alloc_free(poolCreateExtParams params, } int main() { - auto osParams = umfOsMemoryProviderParamsDefault(); + umf_os_memory_provider_params_handle_t osParams = nullptr; + umf_result_t res = umfOsMemoryProviderParamsCreate(&osParams); + if (res != UMF_RESULT_SUCCESS) { + std::cerr << "os memory provider params create failed" << std::endl; + return -1; + } #if defined(UMF_POOL_SCALABLE_ENABLED) @@ -102,7 +107,7 @@ int main() { std::cout << "scalable_pool mt_alloc_free: "; mt_alloc_free(poolCreateExtParams{umfScalablePoolOps(), nullptr, - umfOsMemoryProviderOps(), &osParams}, + umfOsMemoryProviderOps(), osParams}, params); #else std::cout << "skipping scalable_pool mt_alloc_free" << std::endl; @@ -111,7 +116,7 @@ int main() { #if defined(UMF_BUILD_LIBUMF_POOL_JEMALLOC) std::cout << "jemalloc_pool mt_alloc_free: "; mt_alloc_free(poolCreateExtParams{umfJemallocPoolOps(), nullptr, - umfOsMemoryProviderOps(), &osParams}); + umfOsMemoryProviderOps(), osParams}); #else std::cout << "skipping jemalloc_pool mt_alloc_free" << std::endl; #endif @@ -126,7 +131,7 @@ int main() { std::cout << "disjoint_pool mt_alloc_free: "; mt_alloc_free(poolCreateExtParams{umfDisjointPoolOps(), hDisjointParams, - umfOsMemoryProviderOps(), &osParams}); + umfOsMemoryProviderOps(), osParams}); #else std::cout << "skipping disjoint_pool mt_alloc_free" << std::endl; #endif diff --git a/benchmark/ubench.c b/benchmark/ubench.c index 645ddb743..1deabde0c 100644 --- a/benchmark/ubench.c +++ b/benchmark/ubench.c @@ -124,22 +124,6 @@ UBENCH_EX(simple, glibc_malloc) { ////////////////// OS MEMORY PROVIDER -static umf_os_memory_provider_params_t UMF_OS_MEMORY_PROVIDER_PARAMS = { - /* .protection = */ UMF_PROTECTION_READ | UMF_PROTECTION_WRITE, - /* .visibility = */ UMF_MEM_MAP_PRIVATE, - /* .shm_name = */ NULL, - - // NUMA config - /* .numa_list = */ NULL, - /* .numa_list_len = */ 0, - - /* .numa_mode = */ UMF_NUMA_MODE_DEFAULT, - /* .part_size = */ 0, - - /* .partitions = */ NULL, - /* .partitions_len = */ 0, -}; - static void *w_umfMemoryProviderAlloc(void *provider, size_t size, size_t alignment) { void *ptr = NULL; @@ -171,9 +155,17 @@ UBENCH_EX(simple, os_memory_provider) { umf_result_t umf_result; umf_memory_provider_handle_t os_memory_provider = NULL; - umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), - &UMF_OS_MEMORY_PROVIDER_PARAMS, + umf_os_memory_provider_params_handle_t os_params = NULL; + + umf_result = umfOsMemoryProviderParamsCreate(&os_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "error: umfOsMemoryProviderParamsCreate() failed\n"); + exit(-1); + } + + umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), os_params, &os_memory_provider); + umfOsMemoryProviderParamsDestroy(os_params); if (umf_result != UMF_RESULT_SUCCESS) { fprintf(stderr, "error: umfMemoryProviderCreate() failed\n"); exit(-1); @@ -215,9 +207,17 @@ UBENCH_EX(simple, proxy_pool_with_os_memory_provider) { umf_result_t umf_result; umf_memory_provider_handle_t os_memory_provider = NULL; - umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), - &UMF_OS_MEMORY_PROVIDER_PARAMS, + umf_os_memory_provider_params_handle_t os_params = NULL; + + umf_result = umfOsMemoryProviderParamsCreate(&os_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "error: umfOsMemoryProviderParamsCreate() failed\n"); + exit(-1); + } + + umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), os_params, &os_memory_provider); + umfOsMemoryProviderParamsDestroy(os_params); if (umf_result != UMF_RESULT_SUCCESS) { fprintf(stderr, "error: umfMemoryProviderCreate() failed\n"); exit(-1); @@ -252,9 +252,17 @@ UBENCH_EX(simple, disjoint_pool_with_os_memory_provider) { umf_result_t umf_result; umf_memory_provider_handle_t os_memory_provider = NULL; - umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), - &UMF_OS_MEMORY_PROVIDER_PARAMS, + umf_os_memory_provider_params_handle_t os_params = NULL; + + umf_result = umfOsMemoryProviderParamsCreate(&os_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "error: umfOsMemoryProviderParamsCreate() failed\n"); + exit(-1); + } + + umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), os_params, &os_memory_provider); + umfOsMemoryProviderParamsDestroy(os_params); if (umf_result != UMF_RESULT_SUCCESS) { fprintf(stderr, "error: umfMemoryProviderCreate() failed\n"); exit(-1); @@ -329,9 +337,17 @@ UBENCH_EX(simple, jemalloc_pool_with_os_memory_provider) { umf_result_t umf_result; umf_memory_provider_handle_t os_memory_provider = NULL; - umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), - &UMF_OS_MEMORY_PROVIDER_PARAMS, + umf_os_memory_provider_params_handle_t os_params = NULL; + + umf_result = umfOsMemoryProviderParamsCreate(&os_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "error: umfOsMemoryProviderParamsCreate() failed\n"); + exit(-1); + } + + umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), os_params, &os_memory_provider); + umfOsMemoryProviderParamsDestroy(os_params); if (umf_result != UMF_RESULT_SUCCESS) { fprintf(stderr, "error: umfMemoryProviderCreate() failed\n"); exit(-1); @@ -367,9 +383,17 @@ UBENCH_EX(simple, scalable_pool_with_os_memory_provider) { umf_result_t umf_result; umf_memory_provider_handle_t os_memory_provider = NULL; - umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), - &UMF_OS_MEMORY_PROVIDER_PARAMS, + umf_os_memory_provider_params_handle_t os_params = NULL; + + umf_result = umfOsMemoryProviderParamsCreate(&os_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "error: umfOsMemoryProviderParamsCreate() failed\n"); + exit(-1); + } + + umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), os_params, &os_memory_provider); + umfOsMemoryProviderParamsDestroy(os_params); if (umf_result != UMF_RESULT_SUCCESS) { fprintf(stderr, "error: umfMemoryProviderCreate() failed\n"); exit(-1); diff --git a/examples/basic/basic.c b/examples/basic/basic.c index d886c4af8..846e71eda 100644 --- a/examples/basic/basic.c +++ b/examples/basic/basic.c @@ -23,10 +23,17 @@ int main(void) { // in an mmap call like this: // mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0) umf_memory_provider_ops_t *provider_ops = umfOsMemoryProviderOps(); - umf_os_memory_provider_params_t params = umfOsMemoryProviderParamsDefault(); + umf_os_memory_provider_params_handle_t params = NULL; umf_memory_provider_handle_t provider; - res = umfMemoryProviderCreate(provider_ops, ¶ms, &provider); + res = umfOsMemoryProviderParamsCreate(¶ms); + if (res != UMF_RESULT_SUCCESS) { + printf("Failed to create OS memory provider params!\n"); + return -1; + } + + res = umfMemoryProviderCreate(provider_ops, params, &provider); + umfOsMemoryProviderParamsDestroy(params); if (res != UMF_RESULT_SUCCESS) { printf("Failed to create a memory provider!\n"); return -1; diff --git a/examples/dram_and_fsdax/dram_and_fsdax.c b/examples/dram_and_fsdax/dram_and_fsdax.c index ef11c186e..26f451728 100644 --- a/examples/dram_and_fsdax/dram_and_fsdax.c +++ b/examples/dram_and_fsdax/dram_and_fsdax.c @@ -21,11 +21,16 @@ static umf_memory_pool_handle_t create_dram_pool(void) { umf_memory_pool_handle_t pool_dram; umf_result_t umf_result; - umf_os_memory_provider_params_t params_dram = - umfOsMemoryProviderParamsDefault(); + umf_os_memory_provider_params_handle_t params_dram = NULL; + umf_result = umfOsMemoryProviderParamsCreate(¶ms_dram); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to create OS memory provider params!\n"); + return NULL; + } - umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), ¶ms_dram, + umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), params_dram, &provider_dram); + umfOsMemoryProviderParamsDestroy(params_dram); if (umf_result != UMF_RESULT_SUCCESS) { fprintf(stderr, "Creation of the OS memory provider failed"); return NULL; diff --git a/examples/ipc_ipcapi/ipc_ipcapi_consumer.c b/examples/ipc_ipcapi/ipc_ipcapi_consumer.c index 05596bd16..1739e005a 100644 --- a/examples/ipc_ipcapi/ipc_ipcapi_consumer.c +++ b/examples/ipc_ipcapi/ipc_ipcapi_consumer.c @@ -99,17 +99,33 @@ int main(int argc, char *argv[]) { int port = atoi(argv[1]); umf_memory_provider_handle_t OS_memory_provider = NULL; - umf_os_memory_provider_params_t os_params; + umf_os_memory_provider_params_handle_t os_params = NULL; enum umf_result_t umf_result; - os_params = umfOsMemoryProviderParamsDefault(); - os_params.visibility = UMF_MEM_MAP_SHARED; + umf_result = umfOsMemoryProviderParamsCreate(&os_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf( + stderr, + "[consumer] ERROR: creating OS memory provider params failed\n"); + return -1; + } + umf_result = + umfOsMemoryProviderParamsSetVisibility(os_params, UMF_MEM_MAP_SHARED); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "[consumer] ERROR: setting visibility mode failed\n"); + goto err_destroy_OS_params; + } if (argc >= 3) { - os_params.shm_name = argv[2]; + umf_result = umfOsMemoryProviderParamsSetShmName(os_params, argv[2]); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, + "[consumer] ERROR: setting shared memory name failed\n"); + goto err_destroy_OS_params; + } } // create OS memory provider - umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), &os_params, + umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), os_params, &OS_memory_provider); if (umf_result != UMF_RESULT_SUCCESS) { fprintf(stderr, @@ -267,6 +283,9 @@ int main(int argc, char *argv[]) { err_destroy_OS_memory_provider: umfMemoryProviderDestroy(OS_memory_provider); +err_destroy_OS_params: + umfOsMemoryProviderParamsDestroy(os_params); + if (ret == 0) { fprintf(stderr, "[consumer] Shutting down (status OK) ...\n"); } else if (ret == 1) { diff --git a/examples/ipc_ipcapi/ipc_ipcapi_producer.c b/examples/ipc_ipcapi/ipc_ipcapi_producer.c index fcb73650f..4157e8284 100644 --- a/examples/ipc_ipcapi/ipc_ipcapi_producer.c +++ b/examples/ipc_ipcapi/ipc_ipcapi_producer.c @@ -70,17 +70,33 @@ int main(int argc, char *argv[]) { int port = atoi(argv[1]); umf_memory_provider_handle_t OS_memory_provider = NULL; - umf_os_memory_provider_params_t os_params; + umf_os_memory_provider_params_handle_t os_params = NULL; enum umf_result_t umf_result; - os_params = umfOsMemoryProviderParamsDefault(); - os_params.visibility = UMF_MEM_MAP_SHARED; + umf_result = umfOsMemoryProviderParamsCreate(&os_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf( + stderr, + "[producer] ERROR: creating OS memory provider params failed\n"); + return -1; + } + umf_result = + umfOsMemoryProviderParamsSetVisibility(os_params, UMF_MEM_MAP_SHARED); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "[producer] ERROR: setting visibility mode failed\n"); + goto err_destroy_OS_params; + } if (argc >= 3) { - os_params.shm_name = argv[2]; + umf_result = umfOsMemoryProviderParamsSetShmName(os_params, argv[2]); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, + "[producer] ERROR: setting shared memory name failed\n"); + goto err_destroy_OS_params; + } } // create OS memory provider - umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), &os_params, + umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), os_params, &OS_memory_provider); if (umf_result != UMF_RESULT_SUCCESS) { fprintf(stderr, @@ -240,6 +256,9 @@ int main(int argc, char *argv[]) { err_destroy_OS_memory_provider: umfMemoryProviderDestroy(OS_memory_provider); +err_destroy_OS_params: + umfOsMemoryProviderParamsDestroy(os_params); + if (ret == 0) { fprintf(stderr, "[producer] Shutting down (status OK) ...\n"); } else if (ret == 1) { diff --git a/include/umf/providers/provider_os_memory.h b/include/umf/providers/provider_os_memory.h index e175aaa6a..a6bf43a7d 100644 --- a/include/umf/providers/provider_os_memory.h +++ b/include/umf/providers/provider_os_memory.h @@ -60,32 +60,77 @@ typedef struct umf_numa_split_partition_t { unsigned target; } umf_numa_split_partition_t; -/// @brief Memory provider settings struct -typedef struct umf_os_memory_provider_params_t { - /// Combination of 'umf_mem_protection_flags_t' flags - unsigned protection; - /// memory visibility mode - umf_memory_visibility_t visibility; - /// (optional) a name of a shared memory file (valid only in case of the shared memory visibility) - char *shm_name; - - // NUMA config - /// ordered list of numa nodes - unsigned *numa_list; - /// length of numa_list - unsigned numa_list_len; - - /// Describes how node list is interpreted - umf_numa_mode_t numa_mode; - /// part size for interleave mode - 0 means default (system specific) - /// It might be rounded up because of HW constraints - size_t part_size; - - /// ordered list of the partitions for the split mode - umf_numa_split_partition_t *partitions; - /// len of the partitions array - unsigned partitions_len; -} umf_os_memory_provider_params_t; +struct umf_os_memory_provider_params_t; + +typedef struct umf_os_memory_provider_params_t + *umf_os_memory_provider_params_handle_t; + +/// @brief Create a struct to store parameters of the OS memory provider. +/// @param hParams [out] handle to the newly created parameters struct. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfOsMemoryProviderParamsCreate( + umf_os_memory_provider_params_handle_t *hParams); + +/// @brief Destroy parameters struct. +/// @param hParams handle to the parameters of the OS memory provider. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfOsMemoryProviderParamsDestroy( + umf_os_memory_provider_params_handle_t hParams); + +/// @brief Set protection flags for the OS memory provider. +/// @param hParams handle to the parameters of the OS memory provider. +/// @param protection combination of \p umf_mem_protection_flags_t flags. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfOsMemoryProviderParamsSetProtection( + umf_os_memory_provider_params_handle_t hParams, unsigned protection); + +/// @brief Set visibility mode for the OS memory provider. +/// @param hParams handle to the parameters of the OS memory provider. +/// @param visibility memory visibility mode. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfOsMemoryProviderParamsSetVisibility( + umf_os_memory_provider_params_handle_t hParams, + umf_memory_visibility_t visibility); + +/// @brief Set a name of a shared memory file for the OS memory provider. +/// @param hParams handle to the parameters of the OS memory provider. +/// @param shm_name a name of a shared memory file. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfOsMemoryProviderParamsSetShmName( + umf_os_memory_provider_params_handle_t hParams, const char *shm_name); + +/// @brief Set NUMA nodes for the OS memory provider. +/// @param hParams handle to the parameters of the OS memory provider. +/// @param numa_list ordered list of NUMA nodes. +/// @param numa_list_len length of the numa_list. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfOsMemoryProviderParamsSetNumaList( + umf_os_memory_provider_params_handle_t hParams, unsigned *numa_list, + unsigned numa_list_len); + +/// @brief Set NUMA mode for the OS memory provider. +/// @param hParams handle to the parameters of the OS memory provider. +/// @param numa_mode NUMA mode. Describes how node list is interpreted. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfOsMemoryProviderParamsSetNumaMode( + umf_os_memory_provider_params_handle_t hParams, umf_numa_mode_t numa_mode); + +/// @brief Set part size for the interleave mode. 0 means default (system specific) +/// It might be rounded up because of HW constraints. +/// @param hParams handle to the parameters of the OS memory provider. +/// @param part_size part size for interleave mode. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfOsMemoryProviderParamsSetPartSize( + umf_os_memory_provider_params_handle_t hParams, size_t part_size); + +/// @brief Set partitions for the split mode. +/// @param hParams handle to the parameters of the OS memory provider. +/// @param partitions ordered list of the partitions for the split mode. +/// @param partitions_len length of the partitions array. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfOsMemoryProviderParamsSetPartitions( + umf_os_memory_provider_params_handle_t hParams, + umf_numa_split_partition_t *partitions, unsigned partitions_len); /// @brief OS Memory Provider operation results typedef enum umf_os_memory_provider_native_error { @@ -101,23 +146,6 @@ typedef enum umf_os_memory_provider_native_error { umf_memory_provider_ops_t *umfOsMemoryProviderOps(void); -/// @brief Create default params for os memory provider -static inline umf_os_memory_provider_params_t -umfOsMemoryProviderParamsDefault(void) { - umf_os_memory_provider_params_t params = { - UMF_PROTECTION_READ | UMF_PROTECTION_WRITE, /* protection */ - UMF_MEM_MAP_PRIVATE, /* visibility mode */ - NULL, /* (optional) a name of a shared memory file (valid only in case of the shared memory visibility) */ - NULL, /* numa_list */ - 0, /* numa_list_len */ - UMF_NUMA_MODE_DEFAULT, /* numa_mode */ - 0, /* part_size */ - NULL, /* partitions */ - 0}; /* partitions_len*/ - - return params; -} - #ifdef __cplusplus } #endif diff --git a/src/libumf.def b/src/libumf.def index abb25204c..ae1ba6809 100644 --- a/src/libumf.def +++ b/src/libumf.def @@ -82,6 +82,15 @@ EXPORTS umfMemtargetGetType umfOpenIPCHandle umfOsMemoryProviderOps + umfOsMemoryProviderParamsCreate + umfOsMemoryProviderParamsDestroy + umfOsMemoryProviderParamsSetProtection + umfOsMemoryProviderParamsSetVisibility + umfOsMemoryProviderParamsSetShmName + umfOsMemoryProviderParamsSetNumaList + umfOsMemoryProviderParamsSetNumaMode + umfOsMemoryProviderParamsSetPartSize + umfOsMemoryProviderParamsSetPartitions umfPoolAlignedMalloc umfPoolByPtr umfPoolCalloc diff --git a/src/libumf.map b/src/libumf.map index 3a5e73f44..923112384 100644 --- a/src/libumf.map +++ b/src/libumf.map @@ -76,6 +76,15 @@ UMF_1.0 { umfMemtargetGetType; umfOpenIPCHandle; umfOsMemoryProviderOps; + umfOsMemoryProviderParamsCreate; + umfOsMemoryProviderParamsDestroy; + umfOsMemoryProviderParamsSetProtection; + umfOsMemoryProviderParamsSetVisibility; + umfOsMemoryProviderParamsSetShmName; + umfOsMemoryProviderParamsSetNumaList; + umfOsMemoryProviderParamsSetNumaMode; + umfOsMemoryProviderParamsSetPartSize; + umfOsMemoryProviderParamsSetPartitions; umfPoolAlignedMalloc; umfPoolByPtr; umfPoolCalloc; diff --git a/src/memtargets/memtarget_numa.c b/src/memtargets/memtarget_numa.c index 34ba7fc10..f32774ebb 100644 --- a/src/memtargets/memtarget_numa.c +++ b/src/memtargets/memtarget_numa.c @@ -69,22 +69,27 @@ static umf_result_t numa_memory_provider_create_from_memspace( return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - umf_os_memory_provider_params_t params = umfOsMemoryProviderParamsDefault(); + umf_numa_mode_t numa_mode = UMF_NUMA_MODE_DEFAULT; + size_t part_size = 0; + umf_numa_split_partition_t *partitions = NULL; + unsigned partitions_len = 0; + unsigned *numa_list = NULL; + unsigned numa_list_len = 0; if (policy) { switch (policy->type) { case UMF_MEMPOLICY_INTERLEAVE: - params.numa_mode = UMF_NUMA_MODE_INTERLEAVE; - params.part_size = policy->ops.interleave.part_size; + numa_mode = UMF_NUMA_MODE_INTERLEAVE; + part_size = policy->ops.interleave.part_size; break; case UMF_MEMPOLICY_BIND: - params.numa_mode = UMF_NUMA_MODE_BIND; + numa_mode = UMF_NUMA_MODE_BIND; break; case UMF_MEMPOLICY_PREFERRED: - params.numa_mode = UMF_NUMA_MODE_PREFERRED; + numa_mode = UMF_NUMA_MODE_PREFERRED; break; case UMF_MEMPOLICY_SPLIT: - params.numa_mode = UMF_NUMA_MODE_SPLIT; + numa_mode = UMF_NUMA_MODE_SPLIT; // compile time check to ensure we can just cast // umf_mempolicy_split_partition_t to @@ -98,9 +103,8 @@ static umf_result_t numa_memory_provider_create_from_memspace( offsetof(umf_mempolicy_split_partition_t, target) != offsetof(umf_numa_split_partition_t, target)); - params.partitions = - (umf_numa_split_partition_t *)policy->ops.split.part; - params.partitions_len = (unsigned)policy->ops.split.part_len; + partitions = (umf_numa_split_partition_t *)policy->ops.split.part; + partitions_len = (unsigned)policy->ops.split.part_len; break; default: return UMF_RESULT_ERROR_INVALID_ARGUMENT; @@ -109,44 +113,80 @@ static umf_result_t numa_memory_provider_create_from_memspace( if (memspace == umfMemspaceHostAllGet()) { // For the default memspace, we use the default mode without any // call to mbind - params.numa_mode = UMF_NUMA_MODE_DEFAULT; + numa_mode = UMF_NUMA_MODE_DEFAULT; } else { - params.numa_mode = UMF_NUMA_MODE_BIND; + numa_mode = UMF_NUMA_MODE_BIND; } } if (memspace == umfMemspaceHostAllGet() && policy == NULL) { // For default memspace with default policy we use all numa nodes so // simply left numa list empty - params.numa_list_len = 0; - params.numa_list = NULL; + numa_list_len = 0; + numa_list = NULL; } else { - params.numa_list = - umf_ba_global_alloc(sizeof(*params.numa_list) * numNodesProvider); + numa_list = umf_ba_global_alloc(sizeof(*numa_list) * numNodesProvider); - if (!params.numa_list) { + if (!numa_list) { return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; } for (size_t i = 0; i < numNodesProvider; i++) { - params.numa_list[i] = numaTargets[i]->physical_id; + numa_list[i] = numaTargets[i]->physical_id; } - params.numa_list_len = (unsigned)numNodesProvider; + numa_list_len = (unsigned)numNodesProvider; } - umf_memory_provider_handle_t numaProvider = NULL; - int ret = umfMemoryProviderCreate(umfOsMemoryProviderOps(), ¶ms, - &numaProvider); + umf_os_memory_provider_params_handle_t params = NULL; + umf_result_t ret = umfOsMemoryProviderParamsCreate(¶ms); + if (ret != UMF_RESULT_SUCCESS) { + LOG_ERR("Creating OS memory provider params failed"); + goto destroy_numa_list; + } - umf_ba_global_free(params.numa_list); + ret = umfOsMemoryProviderParamsSetNumaMode(params, numa_mode); + if (ret != UMF_RESULT_SUCCESS) { + LOG_ERR("Setting NUMA mode failed"); + goto destroy_provider_params; + } - if (ret) { - return ret; + ret = + umfOsMemoryProviderParamsSetNumaList(params, numa_list, numa_list_len); + if (ret != UMF_RESULT_SUCCESS) { + LOG_ERR("Setting NUMA list failed"); + goto destroy_provider_params; + } + + ret = umfOsMemoryProviderParamsSetPartitions(params, partitions, + partitions_len); + if (ret != UMF_RESULT_SUCCESS) { + LOG_ERR("Setting partitions failed"); + goto destroy_provider_params; + } + + ret = umfOsMemoryProviderParamsSetPartSize(params, part_size); + if (ret != UMF_RESULT_SUCCESS) { + LOG_ERR("Setting part size failed"); + goto destroy_provider_params; + } + + umf_memory_provider_handle_t numaProvider = NULL; + ret = umfMemoryProviderCreate(umfOsMemoryProviderOps(), params, + &numaProvider); + if (ret != UMF_RESULT_SUCCESS) { + LOG_ERR("Creating OS memory provider failed"); + goto destroy_provider_params; } *provider = numaProvider; - return UMF_RESULT_SUCCESS; +destroy_provider_params: + umfOsMemoryProviderParamsDestroy(params); + +destroy_numa_list: + umf_ba_global_free(numa_list); + + return ret; } static umf_result_t numa_pool_create_from_memspace( diff --git a/src/provider/provider_os_memory.c b/src/provider/provider_os_memory.c index dae947651..4c19944a9 100644 --- a/src/provider/provider_os_memory.c +++ b/src/provider/provider_os_memory.c @@ -22,10 +22,77 @@ umf_memory_provider_ops_t *umfOsMemoryProviderOps(void) { return NULL; } +umf_result_t umfOsMemoryProviderParamsCreate( + umf_os_memory_provider_params_handle_t *hParams) { + (void)hParams; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + +umf_result_t umfOsMemoryProviderParamsDestroy( + umf_os_memory_provider_params_handle_t hParams) { + (void)hParams; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + +umf_result_t umfOsMemoryProviderParamsSetProtection( + umf_os_memory_provider_params_handle_t hParams, unsigned protection) { + (void)hParams; + (void)protection; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + +umf_result_t umfOsMemoryProviderParamsSetVisibility( + umf_os_memory_provider_params_handle_t hParams, + umf_memory_visibility_t visibility) { + (void)hParams; + (void)visibility; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + +umf_result_t umfOsMemoryProviderParamsSetShmName( + umf_os_memory_provider_params_handle_t hParams, const char *shm_name) { + (void)hParams; + (void)shm_name; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + +umf_result_t umfOsMemoryProviderParamsSetNumaList( + umf_os_memory_provider_params_handle_t hParams, unsigned *numa_list, + unsigned numa_list_len) { + (void)hParams; + (void)numa_list; + (void)numa_list_len; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + +umf_result_t umfOsMemoryProviderParamsSetNumaMode( + umf_os_memory_provider_params_handle_t hParams, umf_numa_mode_t numa_mode) { + (void)hParams; + (void)numa_mode; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + +umf_result_t umfOsMemoryProviderParamsSetPartSize( + umf_os_memory_provider_params_handle_t hParams, size_t part_size) { + (void)hParams; + (void)part_size; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + +umf_result_t umfOsMemoryProviderParamsSetPartitions( + umf_os_memory_provider_params_handle_t hParams, + umf_numa_split_partition_t *partitions, unsigned partitions_len) { + (void)hParams; + (void)partitions; + (void)partitions_len; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + #else // !defined(UMF_NO_HWLOC) #include "base_alloc_global.h" #include "critnib.h" +#include "libumf.h" #include "provider_os_memory_internal.h" #include "utils_common.h" #include "utils_concurrency.h" @@ -35,6 +102,32 @@ umf_memory_provider_ops_t *umfOsMemoryProviderOps(void) { return NULL; } #define TLS_MSG_BUF_LEN 1024 +typedef struct umf_os_memory_provider_params_t { + // Combination of 'umf_mem_protection_flags_t' flags + unsigned protection; + /// memory visibility mode + umf_memory_visibility_t visibility; + /// (optional) a name of a shared memory file (valid only in case of the shared memory visibility) + char *shm_name; + + // NUMA config + /// ordered list of numa nodes + unsigned *numa_list; + /// length of numa_list + unsigned numa_list_len; + + /// Describes how node list is interpreted + umf_numa_mode_t numa_mode; + /// part size for interleave mode - 0 means default (system specific) + /// It might be rounded up because of HW constraints + size_t part_size; + + /// ordered list of the partitions for the split mode + umf_numa_split_partition_t *partitions; + /// len of the partitions array + unsigned partitions_len; +} umf_os_memory_provider_params_t; + typedef struct os_last_native_error_t { int32_t native_error; int errno_value; @@ -1334,4 +1427,184 @@ umf_memory_provider_ops_t *umfOsMemoryProviderOps(void) { return &UMF_OS_MEMORY_PROVIDER_OPS; } +umf_result_t umfOsMemoryProviderParamsCreate( + umf_os_memory_provider_params_handle_t *hParams) { + libumfInit(); + if (hParams == NULL) { + LOG_ERR("OS memory provider params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + umf_os_memory_provider_params_handle_t params = + umf_ba_global_alloc(sizeof(*params)); + if (params == NULL) { + LOG_ERR("allocating memory for OS memory provider params failed"); + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + params->protection = UMF_PROTECTION_READ | UMF_PROTECTION_WRITE; + params->visibility = UMF_MEM_MAP_PRIVATE; + params->shm_name = NULL; + params->numa_list = NULL; + params->numa_list_len = 0; + params->numa_mode = UMF_NUMA_MODE_DEFAULT; + params->part_size = 0; + params->partitions = NULL; + params->partitions_len = 0; + + *hParams = params; + + return UMF_RESULT_SUCCESS; +} + +umf_result_t umfOsMemoryProviderParamsDestroy( + umf_os_memory_provider_params_handle_t hParams) { + if (hParams != NULL) { + umf_ba_global_free(hParams->shm_name); + umf_ba_global_free(hParams->numa_list); + umf_ba_global_free(hParams->partitions); + } + + umf_ba_global_free(hParams); + + return UMF_RESULT_SUCCESS; +} + +umf_result_t umfOsMemoryProviderParamsSetProtection( + umf_os_memory_provider_params_handle_t hParams, unsigned protection) { + if (hParams == NULL) { + LOG_ERR("OS memory provider params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + hParams->protection = protection; + + return UMF_RESULT_SUCCESS; +} + +umf_result_t umfOsMemoryProviderParamsSetVisibility( + umf_os_memory_provider_params_handle_t hParams, + umf_memory_visibility_t visibility) { + if (hParams == NULL) { + LOG_ERR("OS memory provider params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + hParams->visibility = visibility; + + return UMF_RESULT_SUCCESS; +} + +umf_result_t umfOsMemoryProviderParamsSetShmName( + umf_os_memory_provider_params_handle_t hParams, const char *shm_name) { + if (hParams == NULL) { + LOG_ERR("OS memory provider params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + char *name = NULL; + if (shm_name) { + size_t len = strlen(shm_name) + 1; + name = umf_ba_global_alloc(len); + if (name == NULL) { + LOG_ERR("allocating memory for the shared memory name failed"); + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + strncpy(name, shm_name, len); + } + umf_ba_global_free(hParams->shm_name); + hParams->shm_name = name; + + return UMF_RESULT_SUCCESS; +} + +umf_result_t umfOsMemoryProviderParamsSetNumaList( + umf_os_memory_provider_params_handle_t hParams, unsigned *numa_list, + unsigned numa_list_len) { + if (hParams == NULL) { + LOG_ERR("OS memory provider params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + if (numa_list_len && !numa_list) { + LOG_ERR("numa_list_len is not 0, but numa_list is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + unsigned *new_list = NULL; + if (numa_list_len) { + new_list = umf_ba_global_alloc(numa_list_len * sizeof(*new_list)); + if (new_list == NULL) { + LOG_ERR("allocating memory for the NUMA list failed"); + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + memcpy(new_list, numa_list, numa_list_len * sizeof(*new_list)); + } + + umf_ba_global_free(hParams->numa_list); + hParams->numa_list = new_list; + hParams->numa_list_len = numa_list_len; + + return UMF_RESULT_SUCCESS; +} + +umf_result_t umfOsMemoryProviderParamsSetNumaMode( + umf_os_memory_provider_params_handle_t hParams, umf_numa_mode_t numa_mode) { + if (hParams == NULL) { + LOG_ERR("OS memory provider params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + hParams->numa_mode = numa_mode; + + return UMF_RESULT_SUCCESS; +} + +umf_result_t umfOsMemoryProviderParamsSetPartSize( + umf_os_memory_provider_params_handle_t hParams, size_t part_size) { + if (hParams == NULL) { + LOG_ERR("OS memory provider params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + hParams->part_size = part_size; + + return UMF_RESULT_SUCCESS; +} + +umf_result_t umfOsMemoryProviderParamsSetPartitions( + umf_os_memory_provider_params_handle_t hParams, + umf_numa_split_partition_t *partitions, unsigned partitions_len) { + if (hParams == NULL) { + LOG_ERR("OS memory provider params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + if (partitions_len && !partitions) { + LOG_ERR("partitions_len is not 0, but partitions is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + umf_numa_split_partition_t *new_partitions = NULL; + if (partitions_len) { + new_partitions = + umf_ba_global_alloc(partitions_len * sizeof(*new_partitions)); + if (new_partitions == NULL) { + LOG_ERR("allocating memory for the partitions failed"); + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + memcpy(new_partitions, partitions, + partitions_len * sizeof(*new_partitions)); + } + + umf_ba_global_free(hParams->partitions); + hParams->partitions = new_partitions; + hParams->partitions_len = partitions_len; + + return UMF_RESULT_SUCCESS; +} + #endif // !defined(UMF_NO_HWLOC) diff --git a/src/proxy_lib/proxy_lib.c b/src/proxy_lib/proxy_lib.c index 3320f2898..4b168ab80 100644 --- a/src/proxy_lib/proxy_lib.c +++ b/src/proxy_lib/proxy_lib.c @@ -183,10 +183,15 @@ static int get_system_allocator_symbols(void) { void proxy_lib_create_common(void) { utils_log_init(); - umf_os_memory_provider_params_t os_params = - umfOsMemoryProviderParamsDefault(); + umf_os_memory_provider_params_handle_t os_params = NULL; umf_result_t umf_result; + umf_result = umfOsMemoryProviderParamsCreate(&os_params); + if (umf_result != UMF_RESULT_SUCCESS) { + LOG_ERR("creating OS memory provider params failed"); + exit(-1); + } + #ifndef _WIN32 size_t _threshold = get_size_threshold(); if (_threshold > 0) { @@ -203,26 +208,44 @@ void proxy_lib_create_common(void) { if (utils_env_var_has_str("UMF_PROXY", "page.disposition=shared-fd")) { LOG_INFO("proxy_lib: using the MAP_SHARED visibility mode with the " "file descriptor duplication"); - os_params.visibility = UMF_MEM_MAP_SHARED; - os_params.shm_name = NULL; - + umf_result = umfOsMemoryProviderParamsSetVisibility(os_params, + UMF_MEM_MAP_SHARED); + if (umf_result != UMF_RESULT_SUCCESS) { + LOG_ERR("setting visibility mode failed"); + exit(-1); + } + umf_result = umfOsMemoryProviderParamsSetShmName(os_params, NULL); + if (umf_result != UMF_RESULT_SUCCESS) { + LOG_ERR("setting shared memory name failed"); + exit(-1); + } } else if (utils_env_var_has_str("UMF_PROXY", "page.disposition=shared-shm")) { - os_params.visibility = UMF_MEM_MAP_SHARED; + umf_result = umfOsMemoryProviderParamsSetVisibility(os_params, + UMF_MEM_MAP_SHARED); + if (umf_result != UMF_RESULT_SUCCESS) { + LOG_ERR("setting visibility mode failed"); + exit(-1); + } char shm_name[NAME_MAX]; memset(shm_name, 0, NAME_MAX); sprintf(shm_name, "umf_proxy_lib_shm_pid_%i", utils_getpid()); - os_params.shm_name = shm_name; + umf_result = umfOsMemoryProviderParamsSetShmName(os_params, shm_name); + if (umf_result != UMF_RESULT_SUCCESS) { + LOG_ERR("setting shared memory name failed"); + exit(-1); + } LOG_INFO("proxy_lib: using the MAP_SHARED visibility mode with the " "named shared memory: %s", - os_params.shm_name); + shm_name); } #endif /* _WIN32 */ - umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), &os_params, + umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), os_params, &OS_memory_provider); + umfOsMemoryProviderParamsDestroy(os_params); if (umf_result != UMF_RESULT_SUCCESS) { LOG_ERR("creating OS memory provider failed"); exit(-1); diff --git a/test/c_api/multi_pool.c b/test/c_api/multi_pool.c index 518f992ea..bbd838312 100644 --- a/test/c_api/multi_pool.c +++ b/test/c_api/multi_pool.c @@ -60,11 +60,15 @@ createScalablePool(umf_memory_provider_handle_t provider) { #define ALLOC_SIZE 64 int main(void) { - umf_os_memory_provider_params_t params = umfOsMemoryProviderParamsDefault(); + umf_os_memory_provider_params_handle_t params = NULL; + umf_result_t ret = umfOsMemoryProviderParamsCreate(¶ms); + UT_ASSERTeq(ret, UMF_RESULT_SUCCESS); umf_memory_provider_handle_t hProvider; - umf_result_t ret = - umfMemoryProviderCreate(umfOsMemoryProviderOps(), ¶ms, &hProvider); + ret = umfMemoryProviderCreate(umfOsMemoryProviderOps(), params, &hProvider); + UT_ASSERTeq(ret, UMF_RESULT_SUCCESS); + + ret = umfOsMemoryProviderParamsDestroy(params); UT_ASSERTeq(ret, UMF_RESULT_SUCCESS); umf_memory_pool_handle_t pools[4]; diff --git a/test/fuzz/umfFuzz.cpp b/test/fuzz/umfFuzz.cpp index ac52c96b5..360184c73 100644 --- a/test/fuzz/umfFuzz.cpp +++ b/test/fuzz/umfFuzz.cpp @@ -13,10 +13,15 @@ constexpr int MAX_PROVIDER_ALLOC_SIZE = 100 * 1024; // 100 kB int umf_memory_provider_create(TestState &test_state) { umf_memory_provider_ops_t *provider_ops = umfOsMemoryProviderOps(); - umf_os_memory_provider_params_t params = umfOsMemoryProviderParamsDefault(); - umf_result_t res = - umfMemoryProviderCreate(provider_ops, ¶ms, &test_state.provider); + umf_os_memory_provider_params_handle_t params = NULL; + + umf_result_t res = umfOsMemoryProviderParamsCreate(¶ms); + if (res != UMF_RESULT_SUCCESS) { + return -1; + } + res = umfMemoryProviderCreate(provider_ops, params, &test_state.provider); + umfOsMemoryProviderParamsDestroy(params); if (res != UMF_RESULT_SUCCESS) { return -1; } diff --git a/test/ipc_os_prov_consumer.c b/test/ipc_os_prov_consumer.c index 34f51fe1c..f3f8d0090 100644 --- a/test/ipc_os_prov_consumer.c +++ b/test/ipc_os_prov_consumer.c @@ -19,18 +19,44 @@ int main(int argc, char *argv[]) { return -1; } + int ret = 0; int port = atoi(argv[1]); - umf_os_memory_provider_params_t os_params; + umf_os_memory_provider_params_handle_t os_params = NULL; + + umf_result_t umf_result = umfOsMemoryProviderParamsCreate(&os_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf( + stderr, + "[consumer] ERROR: creating OS memory provider params failed\n"); + return -1; + } + + umf_result = + umfOsMemoryProviderParamsSetVisibility(os_params, UMF_MEM_MAP_SHARED); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "[consumer] ERROR: setting visibility mode failed\n"); + ret = -1; + goto destroy_provider_params; + } - os_params = umfOsMemoryProviderParamsDefault(); - os_params.visibility = UMF_MEM_MAP_SHARED; if (argc >= 3) { - os_params.shm_name = argv[2]; + umf_result = umfOsMemoryProviderParamsSetShmName(os_params, argv[2]); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, + "[consumer] ERROR: setting shared memory name failed\n"); + ret = -1; + goto destroy_provider_params; + } } void *pool_params = NULL; - return run_consumer(port, umfScalablePoolOps(), pool_params, - umfOsMemoryProviderOps(), &os_params, memcopy, NULL); + ret = run_consumer(port, umfScalablePoolOps(), pool_params, + umfOsMemoryProviderOps(), os_params, memcopy, NULL); + +destroy_provider_params: + umfOsMemoryProviderParamsDestroy(os_params); + + return ret; } diff --git a/test/ipc_os_prov_producer.c b/test/ipc_os_prov_producer.c index 623244902..890f1eb3e 100644 --- a/test/ipc_os_prov_producer.c +++ b/test/ipc_os_prov_producer.c @@ -19,18 +19,44 @@ int main(int argc, char *argv[]) { return -1; } + int ret = 0; int port = atoi(argv[1]); - umf_os_memory_provider_params_t os_params; + umf_os_memory_provider_params_handle_t os_params = NULL; + + umf_result_t umf_result = umfOsMemoryProviderParamsCreate(&os_params); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf( + stderr, + "[producer] ERROR: creating OS memory provider params failed\n"); + return -1; + } + + umf_result = + umfOsMemoryProviderParamsSetVisibility(os_params, UMF_MEM_MAP_SHARED); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "[producer] ERROR: setting visibility mode failed\n"); + ret = -1; + goto destroy_provider_params; + } - os_params = umfOsMemoryProviderParamsDefault(); - os_params.visibility = UMF_MEM_MAP_SHARED; if (argc >= 3) { - os_params.shm_name = argv[2]; + umf_result = umfOsMemoryProviderParamsSetShmName(os_params, argv[2]); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, + "[producer] ERROR: setting shared memory name failed\n"); + ret = -1; + goto destroy_provider_params; + } } void *pool_params = NULL; - return run_producer(port, umfScalablePoolOps(), pool_params, - umfOsMemoryProviderOps(), &os_params, memcopy, NULL); + ret = run_producer(port, umfScalablePoolOps(), pool_params, + umfOsMemoryProviderOps(), os_params, memcopy, NULL); + +destroy_provider_params: + umfOsMemoryProviderParamsDestroy(os_params); + + return ret; } diff --git a/test/pools/jemalloc_pool.cpp b/test/pools/jemalloc_pool.cpp index 3a78c5371..4dddbcd32 100644 --- a/test/pools/jemalloc_pool.cpp +++ b/test/pools/jemalloc_pool.cpp @@ -11,11 +11,25 @@ using umf_test::test; using namespace umf_test; -auto defaultParams = umfOsMemoryProviderParamsDefault(); +using os_params_unique_handle_t = + std::unique_ptr; + +os_params_unique_handle_t createOsMemoryProviderParams() { + umf_os_memory_provider_params_handle_t params = nullptr; + umf_result_t res = umfOsMemoryProviderParamsCreate(¶ms); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error("Failed to create os memory provider params"); + } + + return os_params_unique_handle_t(params, &umfOsMemoryProviderParamsDestroy); +} +auto defaultParams = createOsMemoryProviderParams(); + INSTANTIATE_TEST_SUITE_P(jemallocPoolTest, umfPoolTest, ::testing::Values(poolCreateExtParams{ umfJemallocPoolOps(), nullptr, - umfOsMemoryProviderOps(), &defaultParams, + umfOsMemoryProviderOps(), defaultParams.get(), nullptr})); // this test makes sure that jemalloc does not use @@ -28,12 +42,18 @@ TEST_F(test, metadataNotAllocatedUsingProvider) { // set coarse grain allocations to PROT_NONE so that we can be sure // jemalloc does not touch any of the allocated memory - auto params = umfOsMemoryProviderParamsDefault(); - params.protection = UMF_PROTECTION_NONE; + umf_os_memory_provider_params_handle_t params = nullptr; + umf_result_t res = umfOsMemoryProviderParamsCreate(¶ms); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); + res = umfOsMemoryProviderParamsSetProtection(params, UMF_PROTECTION_NONE); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); auto pool = poolCreateExtUnique({umfJemallocPoolOps(), nullptr, - umfOsMemoryProviderOps(), ¶ms, nullptr}); + umfOsMemoryProviderOps(), params, nullptr}); + + res = umfOsMemoryProviderParamsDestroy(params); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); std::vector> allocs; for (size_t i = 0; i < numAllocs; i++) { diff --git a/test/pools/scalable_pool.cpp b/test/pools/scalable_pool.cpp index 0066f75e3..3edacd965 100644 --- a/test/pools/scalable_pool.cpp +++ b/test/pools/scalable_pool.cpp @@ -9,11 +9,25 @@ #include "poolFixtures.hpp" #include "provider.hpp" -auto defaultParams = umfOsMemoryProviderParamsDefault(); +using os_params_unique_handle_t = + std::unique_ptr; + +os_params_unique_handle_t createOsMemoryProviderParams() { + umf_os_memory_provider_params_handle_t params = nullptr; + umf_result_t res = umfOsMemoryProviderParamsCreate(¶ms); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error("Failed to create os memory provider params"); + } + + return os_params_unique_handle_t(params, &umfOsMemoryProviderParamsDestroy); +} +auto defaultParams = createOsMemoryProviderParams(); + INSTANTIATE_TEST_SUITE_P(scalablePoolTest, umfPoolTest, ::testing::Values(poolCreateExtParams{ umfScalablePoolOps(), nullptr, - umfOsMemoryProviderOps(), &defaultParams, + umfOsMemoryProviderOps(), defaultParams.get(), nullptr})); using scalablePoolParams = std::tuple; diff --git a/test/provider_os_memory.cpp b/test/provider_os_memory.cpp index fc6469a0d..57bce46d2 100644 --- a/test/provider_os_memory.cpp +++ b/test/provider_os_memory.cpp @@ -138,16 +138,23 @@ static umf_result_t create_os_provider_with_mode(umf_numa_mode_t mode, unsigned node_list_size) { umf_result_t umf_result; umf_memory_provider_handle_t os_memory_provider = nullptr; - umf_os_memory_provider_params_t os_memory_provider_params = - umfOsMemoryProviderParamsDefault(); + umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr; - os_memory_provider_params.numa_mode = mode; - os_memory_provider_params.numa_list = node_list; - os_memory_provider_params.numa_list_len = node_list_size; + umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params); + EXPECT_EQ(umf_result, UMF_RESULT_SUCCESS); - umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), - &os_memory_provider_params, - &os_memory_provider); + umf_result = + umfOsMemoryProviderParamsSetNumaMode(os_memory_provider_params, mode); + EXPECT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_result = umfOsMemoryProviderParamsSetNumaList( + os_memory_provider_params, node_list, node_list_size); + EXPECT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_result = + umfMemoryProviderCreate(umfOsMemoryProviderOps(), + os_memory_provider_params, &os_memory_provider); + umfOsMemoryProviderParamsDestroy(os_memory_provider_params); if (umf_result == UMF_RESULT_SUCCESS) { EXPECT_NE(os_memory_provider, nullptr); umfMemoryProviderDestroy(os_memory_provider); @@ -193,29 +200,53 @@ TEST_F(test, create_ZERO_WEIGHT_PARTITION) { umf_numa_split_partition_t p = {0, 0}; umf_result_t umf_result; umf_memory_provider_handle_t os_memory_provider = nullptr; - umf_os_memory_provider_params_t os_memory_provider_params = - umfOsMemoryProviderParamsDefault(); + umf_os_memory_provider_params_handle_t os_memory_provider_params = NULL; + + umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params); + EXPECT_EQ(umf_result, UMF_RESULT_SUCCESS); - os_memory_provider_params.numa_mode = UMF_NUMA_MODE_SPLIT; - os_memory_provider_params.numa_list = &valid_list; - os_memory_provider_params.numa_list_len = valid_list_len; - os_memory_provider_params.partitions = &p; - os_memory_provider_params.partitions_len = 1; + umf_result = umfOsMemoryProviderParamsSetNumaMode(os_memory_provider_params, + UMF_NUMA_MODE_SPLIT); + EXPECT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_result = umfOsMemoryProviderParamsSetNumaList( + os_memory_provider_params, &valid_list, valid_list_len); + EXPECT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_result = umfOsMemoryProviderParamsSetPartitions( + os_memory_provider_params, &p, 1); + EXPECT_EQ(umf_result, UMF_RESULT_SUCCESS); umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), &os_memory_provider_params, &os_memory_provider); + umfOsMemoryProviderParamsDestroy(os_memory_provider_params); + EXPECT_EQ(os_memory_provider, nullptr); ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); } // positive tests using test_alloc_free_success -auto defaultParams = umfOsMemoryProviderParamsDefault(); +using os_params_unique_handle_t = + std::unique_ptr; + +os_params_unique_handle_t createOsMemoryProviderParams() { + umf_os_memory_provider_params_handle_t params = nullptr; + umf_result_t res = umfOsMemoryProviderParamsCreate(¶ms); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error("Failed to create os memory provider params"); + } + + return os_params_unique_handle_t(params, &umfOsMemoryProviderParamsDestroy); +} +auto defaultParams = createOsMemoryProviderParams(); + INSTANTIATE_TEST_SUITE_P(osProviderTest, umfProviderTest, ::testing::Values(providerCreateExtParams{ - umfOsMemoryProviderOps(), &defaultParams})); + umfOsMemoryProviderOps(), defaultParams.get()})); TEST_P(umfProviderTest, create_destroy) {} @@ -376,10 +407,22 @@ TEST_P(umfProviderTest, close_ipc_handle_wrong_visibility) { GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(umfIpcTest); -umf_os_memory_provider_params_t osMemoryProviderParamsShared() { - auto params = umfOsMemoryProviderParamsDefault(); - params.visibility = UMF_MEM_MAP_SHARED; - return params; +using os_params_unique_handle_t = + std::unique_ptr; + +os_params_unique_handle_t osMemoryProviderParamsShared() { + umf_os_memory_provider_params_handle_t params = nullptr; + umf_result_t res = umfOsMemoryProviderParamsCreate(¶ms); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error("Failed to create os memory provider params"); + } + res = umfOsMemoryProviderParamsSetVisibility(params, UMF_MEM_MAP_SHARED); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error("Failed to set protection"); + } + + return os_params_unique_handle_t(params, &umfOsMemoryProviderParamsDestroy); } auto os_params = osMemoryProviderParamsShared(); @@ -422,10 +465,10 @@ disjoint_params_unique_handle_t disjointParams = disjointPoolParams(); static std::vector ipcTestParamsList = { #if (defined UMF_POOL_DISJOINT_ENABLED) {umfDisjointPoolOps(), disjointParams.get(), umfOsMemoryProviderOps(), - &os_params, &hostAccessor, false}, + os_params.get(), &hostAccessor, false}, #endif #ifdef UMF_POOL_JEMALLOC_ENABLED - {umfJemallocPoolOps(), nullptr, umfOsMemoryProviderOps(), &os_params, + {umfJemallocPoolOps(), nullptr, umfOsMemoryProviderOps(), os_params.get(), &hostAccessor, false}, #endif }; diff --git a/test/provider_os_memory_config.cpp b/test/provider_os_memory_config.cpp index 78008f898..ed3456618 100644 --- a/test/provider_os_memory_config.cpp +++ b/test/provider_os_memory_config.cpp @@ -22,13 +22,16 @@ struct providerConfigTest : testing::Test { const size_t size = 128; void *ptr = nullptr; std::string dest = "destination"; - umf_os_memory_provider_params_t params = umfOsMemoryProviderParamsDefault(); + umf_os_memory_provider_params_handle_t params = nullptr; void SetUp() override { int ret = numa_available(); if (ret) { GTEST_SKIP() << "Test skipped, NUMA not available"; } + + auto res = umfOsMemoryProviderParamsCreate(¶ms); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); } void TearDown() override { @@ -38,9 +41,11 @@ struct providerConfigTest : testing::Test { if (provider) { umfMemoryProviderDestroy(provider); } + + umfOsMemoryProviderParamsDestroy(params); } - void create_provider(umf_os_memory_provider_params_t *params) { + void create_provider(umf_os_memory_provider_params_handle_t params) { auto res = umfMemoryProviderCreate(umfOsMemoryProviderOps(), params, &provider); ASSERT_EQ(res, UMF_RESULT_SUCCESS); @@ -68,9 +73,9 @@ struct providerConfigTest : testing::Test { TEST_F(providerConfigTest, protection_flag_none) { // pages may not be accessed - PROT_NONE - params.protection = UMF_PROTECTION_NONE; + umfOsMemoryProviderParamsSetProtection(params, UMF_PROTECTION_NONE); - create_provider(¶ms); + create_provider(params); allocate_memory(); // read failure @@ -82,9 +87,9 @@ TEST_F(providerConfigTest, protection_flag_none) { TEST_F(providerConfigTest, protection_flag_read) { // pages may be read - PROT_READ - params.protection = UMF_PROTECTION_READ; + umfOsMemoryProviderParamsSetProtection(params, UMF_PROTECTION_READ); - create_provider(¶ms); + create_provider(params); allocate_memory(); // read success @@ -96,9 +101,9 @@ TEST_F(providerConfigTest, protection_flag_read) { TEST_F(providerConfigTest, protection_flag_write) { // pages may be written to - PROT_WRITE - params.protection = UMF_PROTECTION_WRITE; + umfOsMemoryProviderParamsSetProtection(params, UMF_PROTECTION_WRITE); - create_provider(¶ms); + create_provider(params); allocate_memory(); // write success @@ -107,9 +112,10 @@ TEST_F(providerConfigTest, protection_flag_write) { TEST_F(providerConfigTest, protection_flag_read_write) { // pages may be read and written to - PROT_READ | PROT_WRITE - params.protection = UMF_PROTECTION_READ | UMF_PROTECTION_WRITE; + umfOsMemoryProviderParamsSetProtection(params, UMF_PROTECTION_READ | + UMF_PROTECTION_WRITE); - create_provider(¶ms); + create_provider(params); allocate_memory(); // read success @@ -119,21 +125,115 @@ TEST_F(providerConfigTest, protection_flag_read_write) { write_memory("write string"); } +TEST_F(providerConfigTest, set_params_null_params_handle) { + umf_result_t res = umfOsMemoryProviderParamsCreate(nullptr); + ASSERT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + res = umfOsMemoryProviderParamsDestroy(nullptr); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); + + res = umfOsMemoryProviderParamsSetProtection(nullptr, UMF_PROTECTION_READ); + ASSERT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + res = umfOsMemoryProviderParamsSetVisibility(nullptr, UMF_MEM_MAP_PRIVATE); + ASSERT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + res = umfOsMemoryProviderParamsSetShmName(nullptr, "shm_name"); + ASSERT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + res = umfOsMemoryProviderParamsSetNumaList(nullptr, nullptr, 0); + ASSERT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + res = umfOsMemoryProviderParamsSetNumaMode(nullptr, UMF_NUMA_MODE_DEFAULT); + ASSERT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + res = umfOsMemoryProviderParamsSetPartSize(nullptr, 0); + ASSERT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + res = umfOsMemoryProviderParamsSetPartitions(nullptr, nullptr, 0); + ASSERT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} + +TEST_F(providerConfigTest, set_params_shm_name) { + umf_result_t res = umfOsMemoryProviderParamsSetShmName(params, nullptr); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); + + res = umfOsMemoryProviderParamsSetShmName(params, "shm_name"); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); + + res = umfOsMemoryProviderParamsSetShmName(params, ""); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); + + res = umfOsMemoryProviderParamsSetShmName(params, nullptr); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); +} + +TEST_F(providerConfigTest, set_params_numa_list) { + unsigned numa_list[1] = {0}; + + umf_result_t res = umfOsMemoryProviderParamsSetNumaList(params, nullptr, 0); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); + + res = umfOsMemoryProviderParamsSetNumaList(params, numa_list, 1); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); + + res = umfOsMemoryProviderParamsSetNumaList(params, nullptr, 1); + ASSERT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + res = umfOsMemoryProviderParamsSetNumaList(params, numa_list, 0); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); + + // repeat the valid set to check memory leaks under Valgrind + res = umfOsMemoryProviderParamsSetNumaList(params, numa_list, 1); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); +} + +TEST_F(providerConfigTest, set_params_partitions) { + umf_numa_split_partition_t partitions[1] = {{0, 1}}; + + umf_result_t res = + umfOsMemoryProviderParamsSetPartitions(params, nullptr, 0); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); + + res = umfOsMemoryProviderParamsSetPartitions(params, partitions, 1); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); + + res = umfOsMemoryProviderParamsSetPartitions(params, nullptr, 1); + ASSERT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + res = umfOsMemoryProviderParamsSetPartitions(params, partitions, 0); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); + + // repeat the valid set to check memory leaks under Valgrind + res = umfOsMemoryProviderParamsSetPartitions(params, partitions, 1); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); +} + struct providerConfigTestNumaMode : providerConfigTest, testing::WithParamInterface { struct bitmask *allowed_nodes = nullptr; - umf_os_memory_provider_params_t params = umfOsMemoryProviderParamsDefault(); + umf_numa_mode_t expected_numa_mode; void SetUp() override { providerConfigTest::SetUp(); - params.numa_mode = GetParam(); + + if (::providerConfigTest::IsSkipped()) { + GTEST_SKIP(); + } + + expected_numa_mode = GetParam(); + + auto res = + umfOsMemoryProviderParamsSetNumaMode(params, expected_numa_mode); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); } void TearDown() override { if (allowed_nodes) { numa_bitmask_free(allowed_nodes); } + providerConfigTest::TearDown(); } }; @@ -152,24 +252,27 @@ INSTANTIATE_TEST_SUITE_P(numa_modes, providerConfigTestNumaMode, #endif TEST_P(providerConfigTestNumaMode, numa_modes) { - if (params.numa_mode != UMF_NUMA_MODE_DEFAULT && - params.numa_mode != UMF_NUMA_MODE_LOCAL) { + unsigned numa_list_len = 0; + unsigned *numa_list = nullptr; + if (expected_numa_mode != UMF_NUMA_MODE_DEFAULT && + expected_numa_mode != UMF_NUMA_MODE_LOCAL) { allowed_nodes = numa_get_mems_allowed(); // convert bitmask to array of nodes - params.numa_list_len = numa_bitmask_weight(allowed_nodes); - params.numa_list = (unsigned *)malloc(params.numa_list_len * - sizeof(*params.numa_list)); - ASSERT_NE(params.numa_list, nullptr); + numa_list_len = numa_bitmask_weight(allowed_nodes); + numa_list = (unsigned *)malloc(numa_list_len * sizeof(*numa_list)); + ASSERT_NE(numa_list, nullptr); unsigned count = 0; - for (unsigned i = 0; i < params.numa_list_len; i++) { + for (unsigned i = 0; i < numa_list_len; i++) { if (numa_bitmask_isbitset(allowed_nodes, i)) { - params.numa_list[count++] = i; + numa_list[count++] = i; } } - ASSERT_EQ(count, params.numa_list_len); + ASSERT_EQ(count, numa_list_len); + + umfOsMemoryProviderParamsSetNumaList(params, numa_list, numa_list_len); } - create_provider(¶ms); + create_provider(params); allocate_memory(); write_memory("write string"); @@ -177,25 +280,25 @@ TEST_P(providerConfigTestNumaMode, numa_modes) { long ret = get_mempolicy(&actual_mode, nullptr, 0, ptr, MPOL_F_ADDR); ASSERT_EQ(ret, 0); - if (params.numa_mode == UMF_NUMA_MODE_DEFAULT) { + if (expected_numa_mode == UMF_NUMA_MODE_DEFAULT) { ASSERT_EQ(actual_mode, MPOL_DEFAULT); - } else if (params.numa_mode == UMF_NUMA_MODE_BIND) { + } else if (expected_numa_mode == UMF_NUMA_MODE_BIND) { ASSERT_EQ(actual_mode, MPOL_BIND); - } else if (params.numa_mode == UMF_NUMA_MODE_INTERLEAVE) { + } else if (expected_numa_mode == UMF_NUMA_MODE_INTERLEAVE) { ASSERT_EQ(actual_mode, MPOL_INTERLEAVE); - } else if (params.numa_mode == UMF_NUMA_MODE_PREFERRED) { + } else if (expected_numa_mode == UMF_NUMA_MODE_PREFERRED) { // MPOL_PREFERRED_MANY is equivalent to MPOL_PREFERRED if a single node is set if (actual_mode != MPOL_PREFERRED_MANY) { ASSERT_EQ(actual_mode, MPOL_PREFERRED); } - } else if (params.numa_mode == UMF_NUMA_MODE_LOCAL) { + } else if (expected_numa_mode == UMF_NUMA_MODE_LOCAL) { // MPOL_PREFERRED_* is equivalent to MPOL_LOCAL if no node is set if (actual_mode == MPOL_PREFERRED || actual_mode == MPOL_PREFERRED_MANY) { - ASSERT_EQ(params.numa_list_len, 0); + ASSERT_EQ(numa_list_len, 0); } else { ASSERT_EQ(actual_mode, MPOL_LOCAL); } } - free(params.numa_list); + free(numa_list); } diff --git a/test/provider_os_memory_multiple_numa_nodes.cpp b/test/provider_os_memory_multiple_numa_nodes.cpp index 7f0a1401b..e493a427c 100644 --- a/test/provider_os_memory_multiple_numa_nodes.cpp +++ b/test/provider_os_memory_multiple_numa_nodes.cpp @@ -14,9 +14,6 @@ #include -static umf_os_memory_provider_params_t UMF_OS_MEMORY_PROVIDER_PARAMS_TEST = - umfOsMemoryProviderParamsDefault(); - std::vector get_available_numa_nodes() { if (numa_available() == -1 || numa_all_nodes_ptr == nullptr) { return std::vector(); @@ -85,11 +82,11 @@ struct testNuma : testing::Test { ASSERT_NE(nodemask, nullptr); } - void - initOsProvider(umf_os_memory_provider_params_t os_memory_provider_params) { + void initOsProvider( + umf_os_memory_provider_params_handle_t os_memory_provider_params) { umf_result_t umf_result; umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), - &os_memory_provider_params, + os_memory_provider_params, &os_memory_provider); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(os_memory_provider, nullptr); @@ -157,16 +154,25 @@ INSTANTIATE_TEST_SUITE_P(testNumaNodesAllocations, testNumaOnEachNode, TEST_P(testNumaOnEachNode, checkNumaNodesAllocations) { unsigned numa_node_number = GetParam(); ASSERT_GE(numa_node_number, 0); + umf_result_t umf_result; - umf_os_memory_provider_params_t os_memory_provider_params = - UMF_OS_MEMORY_PROVIDER_PARAMS_TEST; + umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr; + + umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_result = umfOsMemoryProviderParamsSetNumaList(os_memory_provider_params, + &numa_node_number, 1); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_result = umfOsMemoryProviderParamsSetNumaMode(os_memory_provider_params, + UMF_NUMA_MODE_BIND); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - os_memory_provider_params.numa_list = &numa_node_number; - os_memory_provider_params.numa_list_len = 1; - os_memory_provider_params.numa_mode = UMF_NUMA_MODE_BIND; initOsProvider(os_memory_provider_params); - umf_result_t umf_result; + umfOsMemoryProviderParamsDestroy(os_memory_provider_params); + umf_result = umfMemoryProviderAlloc(os_memory_provider, alloc_size, 0, &ptr); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); @@ -181,16 +187,25 @@ TEST_P(testNumaOnEachNode, checkNumaNodesAllocations) { // on each of the available numa nodes. TEST_P(testNumaOnEachNode, checkModePreferred) { unsigned numa_node_number = GetParam(); - umf_os_memory_provider_params_t os_memory_provider_params = - UMF_OS_MEMORY_PROVIDER_PARAMS_TEST; + umf_result_t umf_result; + umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr; + + umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - os_memory_provider_params.numa_list = &numa_node_number; + umf_result = umfOsMemoryProviderParamsSetNumaList(os_memory_provider_params, + &numa_node_number, 1); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); numa_bitmask_setbit(nodemask, numa_node_number); - os_memory_provider_params.numa_list_len = 1; - os_memory_provider_params.numa_mode = UMF_NUMA_MODE_PREFERRED; + + umf_result = umfOsMemoryProviderParamsSetNumaMode(os_memory_provider_params, + UMF_NUMA_MODE_PREFERRED); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + initOsProvider(os_memory_provider_params); - umf_result_t umf_result; + umfOsMemoryProviderParamsDestroy(os_memory_provider_params); + umf_result = umfMemoryProviderAlloc(os_memory_provider, alloc_size, 0, &ptr); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); @@ -207,14 +222,19 @@ TEST_P(testNumaOnEachNode, checkModePreferred) { TEST_P(testNumaOnEachNode, checkModeDefaultSetMempolicy) { unsigned numa_node_number = GetParam(); numa_bitmask_setbit(nodemask, numa_node_number); - umf_os_memory_provider_params_t os_memory_provider_params = - UMF_OS_MEMORY_PROVIDER_PARAMS_TEST; + umf_result_t umf_result; + umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr; + + umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + initOsProvider(os_memory_provider_params); + umfOsMemoryProviderParamsDestroy(os_memory_provider_params); + long ret = set_mempolicy(MPOL_BIND, nodemask->maskp, nodemask->size); ASSERT_EQ(ret, 0); - umf_result_t umf_result; umf_result = umfMemoryProviderAlloc(os_memory_provider, alloc_size, 0, &ptr); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); @@ -232,15 +252,24 @@ TEST_P(testNumaOnEachNode, checkModeInterleaveSingleNode) { constexpr int pages_num = 1024; size_t page_size = sysconf(_SC_PAGE_SIZE); - umf_os_memory_provider_params_t os_memory_provider_params = - UMF_OS_MEMORY_PROVIDER_PARAMS_TEST; + umf_result_t umf_result; + umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr; + + umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_result = umfOsMemoryProviderParamsSetNumaList(os_memory_provider_params, + &numa_node_number, 1); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_result = umfOsMemoryProviderParamsSetNumaMode(os_memory_provider_params, + UMF_NUMA_MODE_INTERLEAVE); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - os_memory_provider_params.numa_list = &numa_node_number; - os_memory_provider_params.numa_list_len = 1; - os_memory_provider_params.numa_mode = UMF_NUMA_MODE_INTERLEAVE; initOsProvider(os_memory_provider_params); - umf_result_t umf_result; + umfOsMemoryProviderParamsDestroy(os_memory_provider_params); + umf_result = umfMemoryProviderAlloc(os_memory_provider, pages_num * page_size, 0, &ptr); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); @@ -282,12 +311,20 @@ TEST_P(testNumaOnEachCpu, checkModePreferredEmptyNodeset) { ASSERT_EQ(ret, 0); - umf_os_memory_provider_params_t os_memory_provider_params = - UMF_OS_MEMORY_PROVIDER_PARAMS_TEST; - os_memory_provider_params.numa_mode = UMF_NUMA_MODE_PREFERRED; + umf_result_t umf_result; + umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr; + + umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_result = umfOsMemoryProviderParamsSetNumaMode(os_memory_provider_params, + UMF_NUMA_MODE_PREFERRED); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + initOsProvider(os_memory_provider_params); - umf_result_t umf_result; + umfOsMemoryProviderParamsDestroy(os_memory_provider_params); + umf_result = umfMemoryProviderAlloc(os_memory_provider, alloc_size, 0, &ptr); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); @@ -319,12 +356,20 @@ TEST_P(testNumaOnEachCpu, checkModeLocal) { ASSERT_EQ(ret, 0); - umf_os_memory_provider_params_t os_memory_provider_params = - UMF_OS_MEMORY_PROVIDER_PARAMS_TEST; - os_memory_provider_params.numa_mode = UMF_NUMA_MODE_LOCAL; + umf_result_t umf_result; + umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr; + + umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_result = umfOsMemoryProviderParamsSetNumaMode(os_memory_provider_params, + UMF_NUMA_MODE_LOCAL); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + initOsProvider(os_memory_provider_params); - umf_result_t umf_result; + umfOsMemoryProviderParamsDestroy(os_memory_provider_params); + umf_result = umfMemoryProviderAlloc(os_memory_provider, alloc_size, 0, &ptr); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); @@ -347,11 +392,16 @@ TEST_P(testNumaOnEachCpu, checkModeLocal) { // default policy - it allocates pages on the node of the CPU that triggered // the allocation. TEST_F(testNuma, checkModeDefault) { - umf_os_memory_provider_params_t os_memory_provider_params = - UMF_OS_MEMORY_PROVIDER_PARAMS_TEST; + umf_result_t umf_result; + umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr; + + umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + initOsProvider(os_memory_provider_params); - umf_result_t umf_result; + umfOsMemoryProviderParamsDestroy(os_memory_provider_params); + umf_result = umfMemoryProviderAlloc(os_memory_provider, alloc_size, 0, &ptr); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); @@ -371,18 +421,27 @@ TEST_F(testNuma, checkModeDefault) { TEST_F(testNuma, checkModeInterleave) { constexpr int pages_num = 1024; size_t page_size = sysconf(_SC_PAGE_SIZE); - umf_os_memory_provider_params_t os_memory_provider_params = - UMF_OS_MEMORY_PROVIDER_PARAMS_TEST; + umf_result_t umf_result; + umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr; + + umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); std::vector numa_nodes = get_available_numa_nodes(); set_all_available_nodemask_bits(nodemask); - os_memory_provider_params.numa_list = numa_nodes.data(); - os_memory_provider_params.numa_list_len = numa_nodes.size(); - os_memory_provider_params.numa_mode = UMF_NUMA_MODE_INTERLEAVE; + umf_result = umfOsMemoryProviderParamsSetNumaList( + os_memory_provider_params, numa_nodes.data(), numa_nodes.size()); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_result = umfOsMemoryProviderParamsSetNumaMode(os_memory_provider_params, + UMF_NUMA_MODE_INTERLEAVE); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + initOsProvider(os_memory_provider_params); - umf_result_t umf_result; + umfOsMemoryProviderParamsDestroy(os_memory_provider_params); + umf_result = umfMemoryProviderAlloc(os_memory_provider, pages_num * page_size, 0, &ptr); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); @@ -432,20 +491,32 @@ TEST_F(testNuma, checkModeInterleaveCustomPartSize) { ASSERT_GT(_page_size, 0); size_t page_size = _page_size; size_t part_size = page_size * 100; - umf_os_memory_provider_params_t os_memory_provider_params = - UMF_OS_MEMORY_PROVIDER_PARAMS_TEST; + umf_result_t umf_result; + umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr; + + umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); std::vector numa_nodes = get_available_numa_nodes(); - os_memory_provider_params.numa_list = numa_nodes.data(); - os_memory_provider_params.numa_list_len = numa_nodes.size(); - os_memory_provider_params.numa_mode = UMF_NUMA_MODE_INTERLEAVE; + umf_result = umfOsMemoryProviderParamsSetNumaList( + os_memory_provider_params, numa_nodes.data(), numa_nodes.size()); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_result = umfOsMemoryProviderParamsSetNumaMode(os_memory_provider_params, + UMF_NUMA_MODE_INTERLEAVE); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + // part size do not need to be multiple of page size - os_memory_provider_params.part_size = part_size - 1; + umf_result = umfOsMemoryProviderParamsSetPartSize(os_memory_provider_params, + part_size - 1); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + initOsProvider(os_memory_provider_params); + umfOsMemoryProviderParamsDestroy(os_memory_provider_params); + size_t size = part_num * part_size; - umf_result_t umf_result; umf_result = umfMemoryProviderAlloc(os_memory_provider, size, 0, &ptr); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(ptr, nullptr); @@ -601,9 +672,12 @@ TEST_P(testNumaSplit, checkModeSplit) { ASSERT_GT(_page_size, 0); size_t page_size = _page_size; auto [required_numa_nodes, pages, in, out] = param; + umf_result_t umf_result; + + umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr; - umf_os_memory_provider_params_t os_memory_provider_params = - UMF_OS_MEMORY_PROVIDER_PARAMS_TEST; + umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); std::vector numa_nodes = get_available_numa_nodes(); @@ -622,16 +696,24 @@ TEST_P(testNumaSplit, checkModeSplit) { numa_nodes.begin() + required_numa_nodes, g); } - os_memory_provider_params.numa_list = numa_nodes.data(); - os_memory_provider_params.numa_list_len = required_numa_nodes; - os_memory_provider_params.numa_mode = UMF_NUMA_MODE_SPLIT; + umf_result = umfOsMemoryProviderParamsSetNumaList( + os_memory_provider_params, numa_nodes.data(), required_numa_nodes); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_result = umfOsMemoryProviderParamsSetNumaMode(os_memory_provider_params, + UMF_NUMA_MODE_SPLIT); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_result = umfOsMemoryProviderParamsSetPartitions( + os_memory_provider_params, in.data(), in.size()); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - os_memory_provider_params.partitions = in.data(); - os_memory_provider_params.partitions_len = in.size(); initOsProvider(os_memory_provider_params); + umfOsMemoryProviderParamsDestroy(os_memory_provider_params); + size_t size = page_size * pages; - umf_result_t umf_result; + umf_result = umfMemoryProviderAlloc(os_memory_provider, size, 0, &ptr); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(ptr, nullptr); @@ -665,17 +747,26 @@ TEST_P(testNumaSplit, checkModeSplit) { // Test for allocations on all numa nodes with BIND mode. // According to mbind it should go to the closest node. TEST_F(testNuma, checkModeBindOnAllNodes) { - umf_os_memory_provider_params_t os_memory_provider_params = - UMF_OS_MEMORY_PROVIDER_PARAMS_TEST; + umf_result_t umf_result; + umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr; + + umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); std::vector numa_nodes = get_available_numa_nodes(); - os_memory_provider_params.numa_list = numa_nodes.data(); - os_memory_provider_params.numa_list_len = numa_nodes.size(); - os_memory_provider_params.numa_mode = UMF_NUMA_MODE_BIND; + umf_result = umfOsMemoryProviderParamsSetNumaList( + os_memory_provider_params, numa_nodes.data(), numa_nodes.size()); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_result = umfOsMemoryProviderParamsSetNumaMode(os_memory_provider_params, + UMF_NUMA_MODE_BIND); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + initOsProvider(os_memory_provider_params); - umf_result_t umf_result; + umfOsMemoryProviderParamsDestroy(os_memory_provider_params); + umf_result = umfMemoryProviderAlloc(os_memory_provider, alloc_size, 0, &ptr); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); @@ -709,19 +800,28 @@ TEST_F(testNuma, checkModeBindOnAllNodes) { // Local mode enabled when numa_list is set. // For the local mode the nodeset must be empty. TEST_F(testNuma, checkModeLocalIllegalArgSet) { - umf_os_memory_provider_params_t os_memory_provider_params = - UMF_OS_MEMORY_PROVIDER_PARAMS_TEST; + umf_result_t umf_result; + umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr; + + umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); std::vector numa_nodes = get_available_numa_nodes(); - os_memory_provider_params.numa_list = numa_nodes.data(); - os_memory_provider_params.numa_list_len = numa_nodes.size(); - os_memory_provider_params.numa_mode = UMF_NUMA_MODE_LOCAL; + umf_result = umfOsMemoryProviderParamsSetNumaList( + os_memory_provider_params, numa_nodes.data(), numa_nodes.size()); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_result = umfOsMemoryProviderParamsSetNumaMode(os_memory_provider_params, + UMF_NUMA_MODE_LOCAL); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - umf_result_t umf_result; umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), &os_memory_provider_params, &os_memory_provider); + + umfOsMemoryProviderParamsDestroy(os_memory_provider_params); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); ASSERT_EQ(os_memory_provider, nullptr); } @@ -729,18 +829,24 @@ TEST_F(testNuma, checkModeLocalIllegalArgSet) { // Default mode enabled when numa_list is set. // For the default mode the nodeset must be empty. TEST_F(testNuma, checkModeDefaultIllegalArgSet) { - umf_os_memory_provider_params_t os_memory_provider_params = - UMF_OS_MEMORY_PROVIDER_PARAMS_TEST; + umf_result_t umf_result; + umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr; + + umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); std::vector numa_nodes = get_available_numa_nodes(); - os_memory_provider_params.numa_list = numa_nodes.data(); - os_memory_provider_params.numa_list_len = numa_nodes.size(); + umf_result = umfOsMemoryProviderParamsSetNumaList( + os_memory_provider_params, numa_nodes.data(), numa_nodes.size()); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); - umf_result_t umf_result; umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), &os_memory_provider_params, &os_memory_provider); + + umfOsMemoryProviderParamsDestroy(os_memory_provider_params); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); ASSERT_EQ(os_memory_provider, nullptr); } @@ -748,14 +854,22 @@ TEST_F(testNuma, checkModeDefaultIllegalArgSet) { // Bind mode enabled when numa_list is not set. // For the bind mode the nodeset must be non-empty. TEST_F(testNuma, checkModeBindIllegalArgSet) { - umf_os_memory_provider_params_t os_memory_provider_params = - UMF_OS_MEMORY_PROVIDER_PARAMS_TEST; - os_memory_provider_params.numa_mode = UMF_NUMA_MODE_BIND; - umf_result_t umf_result; + umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr; + + umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_result = umfOsMemoryProviderParamsSetNumaMode(os_memory_provider_params, + UMF_NUMA_MODE_BIND); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), &os_memory_provider_params, &os_memory_provider); + + umfOsMemoryProviderParamsDestroy(os_memory_provider_params); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); ASSERT_EQ(os_memory_provider, nullptr); } @@ -763,14 +877,22 @@ TEST_F(testNuma, checkModeBindIllegalArgSet) { // Interleave mode enabled numa_list is not set. // For the interleave mode the nodeset must be non-empty. TEST_F(testNuma, checkModeInterleaveIllegalArgSet) { - umf_os_memory_provider_params_t os_memory_provider_params = - UMF_OS_MEMORY_PROVIDER_PARAMS_TEST; - os_memory_provider_params.numa_mode = UMF_NUMA_MODE_INTERLEAVE; - umf_result_t umf_result; + umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr; + + umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_result = umfOsMemoryProviderParamsSetNumaMode(os_memory_provider_params, + UMF_NUMA_MODE_INTERLEAVE); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), &os_memory_provider_params, &os_memory_provider); + + umfOsMemoryProviderParamsDestroy(os_memory_provider_params); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); ASSERT_EQ(os_memory_provider, nullptr); } @@ -779,16 +901,29 @@ TEST_F(testNuma, checkModeInterleaveIllegalArgSet) { TEST_F(testNuma, maxPartSize) { std::vector numa_nodes = get_available_numa_nodes(); - umf_os_memory_provider_params_t os_memory_provider_params = - UMF_OS_MEMORY_PROVIDER_PARAMS_TEST; - os_memory_provider_params.numa_mode = UMF_NUMA_MODE_INTERLEAVE; - os_memory_provider_params.part_size = SIZE_MAX; - os_memory_provider_params.numa_list = numa_nodes.data(); - os_memory_provider_params.numa_list_len = numa_nodes.size(); + umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr; + + auto res = umfOsMemoryProviderParamsCreate(&os_memory_provider_params); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); + + res = umfOsMemoryProviderParamsSetNumaMode(os_memory_provider_params, + UMF_NUMA_MODE_INTERLEAVE); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); + + res = umfOsMemoryProviderParamsSetPartSize(os_memory_provider_params, + SIZE_MAX); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); + + res = umfOsMemoryProviderParamsSetNumaList( + os_memory_provider_params, numa_nodes.data(), numa_nodes.size()); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); + + res = umfMemoryProviderCreate(umfOsMemoryProviderOps(), + &os_memory_provider_params, + &os_memory_provider); + + umfOsMemoryProviderParamsDestroy(os_memory_provider_params); - auto res = umfMemoryProviderCreate(umfOsMemoryProviderOps(), - &os_memory_provider_params, - &os_memory_provider); ASSERT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT); ASSERT_EQ(os_memory_provider, nullptr); } From 6c2ebb16af48f91f72aee99f7957cd51e3c596bb Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Thu, 21 Nov 2024 23:57:42 +0100 Subject: [PATCH 327/352] Update docs for the basic example --- scripts/docs_config/examples.rst | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/scripts/docs_config/examples.rst b/scripts/docs_config/examples.rst index 5e2ff71fa..a84dd3aa2 100644 --- a/scripts/docs_config/examples.rst +++ b/scripts/docs_config/examples.rst @@ -31,11 +31,20 @@ the OS Memory Provider API:: #include "umf/providers/provider_os_memory.h" -Get a pointer to the OS memory provider operations struct and -a copy of default parameters:: +Get a pointer to the OS memory provider operations struct:: umf_memory_provider_ops_t *provider_ops = umfOsMemoryProviderOps(); - umf_os_memory_provider_params_t params = umfOsMemoryProviderParamsDefault(); + +Get a default OS memory provider parameters. The handle to the parameters object +is returned by the :any:`umfOsMemoryProviderParamsCreate` function:: + + umf_os_memory_provider_params_handle_t params = NULL; + + res = umfOsMemoryProviderParamsCreate(¶ms); + if (res != UMF_RESULT_SUCCESS) { + printf("Failed to create OS memory provider params!\n"); + return -1; + } The handle to created memory ``provider`` object is returned as the last argument of :any:`umfMemoryProviderCreate`:: @@ -43,7 +52,10 @@ of :any:`umfMemoryProviderCreate`:: umf_memory_provider_handle_t provider; umfMemoryProviderCreate(provider_ops, ¶ms, &provider); -With this handle we can allocate a chunk of memory, call :any:`umfMemoryProviderAlloc`:: +The ``params`` object can be destroyed after the provider is created:: + umfOsMemoryProviderParamsDestroy(params); + +With the ``provider`` handle we can allocate a chunk of memory, call :any:`umfMemoryProviderAlloc`:: size_t alloc_size = 5000; size_t alignment = 0; From dcf04528d00b82b674fdd874b8632c5e54bf683e Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Tue, 26 Nov 2024 16:08:37 +0100 Subject: [PATCH 328/352] Add test for not implemented Level Zero provider --- test/CMakeLists.txt | 7 ++++ .../provider_level_zero_not_impl.cpp | 36 +++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 test/providers/provider_level_zero_not_impl.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 051e75949..adf967f1d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -368,6 +368,13 @@ if(UMF_BUILD_GPU_TESTS AND UMF_BUILD_LEVEL_ZERO_PROVIDER) PRIVATE ${LEVEL_ZERO_INCLUDE_DIRS}) endif() +if(NOT UMF_BUILD_LEVEL_ZERO_PROVIDER) + add_umf_test( + NAME provider_level_zero_not_impl + SRCS providers/provider_level_zero_not_impl.cpp + LIBS ${UMF_UTILS_FOR_TEST}) +endif() + if(UMF_BUILD_GPU_TESTS AND UMF_BUILD_CUDA_PROVIDER) if(UMF_CUDA_ENABLED) # we have two test binaries here that use the same sources, but differ diff --git a/test/providers/provider_level_zero_not_impl.cpp b/test/providers/provider_level_zero_not_impl.cpp new file mode 100644 index 000000000..bea1acbe7 --- /dev/null +++ b/test/providers/provider_level_zero_not_impl.cpp @@ -0,0 +1,36 @@ +// Copyright (C) 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 "base.hpp" + +#include + +using umf_test::test; + +TEST_F(test, level_zero_provider_not_implemented) { + umf_level_zero_memory_provider_params_handle_t hParams = nullptr; + umf_result_t result = umfLevelZeroMemoryProviderParamsCreate(&hParams); + ASSERT_EQ(result, UMF_RESULT_ERROR_NOT_SUPPORTED); + + result = umfLevelZeroMemoryProviderParamsDestroy(hParams); + ASSERT_EQ(result, UMF_RESULT_ERROR_NOT_SUPPORTED); + + result = umfLevelZeroMemoryProviderParamsSetContext(hParams, nullptr); + ASSERT_EQ(result, UMF_RESULT_ERROR_NOT_SUPPORTED); + + result = umfLevelZeroMemoryProviderParamsSetDevice(hParams, nullptr); + ASSERT_EQ(result, UMF_RESULT_ERROR_NOT_SUPPORTED); + + result = umfLevelZeroMemoryProviderParamsSetMemoryType( + hParams, UMF_MEMORY_TYPE_DEVICE); + ASSERT_EQ(result, UMF_RESULT_ERROR_NOT_SUPPORTED); + + ze_device_handle_t hDevices[1]; + result = umfLevelZeroMemoryProviderParamsSetResidentDevices(hParams, + hDevices, 1); + ASSERT_EQ(result, UMF_RESULT_ERROR_NOT_SUPPORTED); + + umf_memory_provider_ops_t *ops = umfLevelZeroMemoryProviderOps(); + ASSERT_EQ(ops, nullptr); +} From 4de4ebfab1df629cf2b94c829baa8e0974e4e3a3 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Tue, 26 Nov 2024 16:16:59 +0100 Subject: [PATCH 329/352] Add test for not implemented CUDA provider --- test/CMakeLists.txt | 7 +++++ test/providers/provider_cuda_not_impl.cpp | 31 +++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 test/providers/provider_cuda_not_impl.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index adf967f1d..68d6018f9 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -407,6 +407,13 @@ if(UMF_BUILD_GPU_TESTS AND UMF_BUILD_CUDA_PROVIDER) endif() endif() +if(NOT UMF_BUILD_CUDA_PROVIDER) + add_umf_test( + NAME provider_cuda_not_impl + SRCS providers/provider_cuda_not_impl.cpp + LIBS ${UMF_UTILS_FOR_TEST}) +endif() + add_umf_test( NAME base_alloc SRCS ${BA_SOURCES_FOR_TEST} test_base_alloc.cpp diff --git a/test/providers/provider_cuda_not_impl.cpp b/test/providers/provider_cuda_not_impl.cpp new file mode 100644 index 000000000..30fc373ca --- /dev/null +++ b/test/providers/provider_cuda_not_impl.cpp @@ -0,0 +1,31 @@ +// Copyright (C) 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 "base.hpp" + +#include + +using umf_test::test; + +TEST_F(test, cuda_provider_not_implemented) { + umf_cuda_memory_provider_params_handle_t hParams = nullptr; + umf_result_t result = umfCUDAMemoryProviderParamsCreate(&hParams); + ASSERT_EQ(result, UMF_RESULT_ERROR_NOT_SUPPORTED); + + result = umfCUDAMemoryProviderParamsDestroy(hParams); + ASSERT_EQ(result, UMF_RESULT_ERROR_NOT_SUPPORTED); + + result = umfCUDAMemoryProviderParamsSetContext(hParams, nullptr); + ASSERT_EQ(result, UMF_RESULT_ERROR_NOT_SUPPORTED); + + result = umfCUDAMemoryProviderParamsSetDevice(hParams, 0); + ASSERT_EQ(result, UMF_RESULT_ERROR_NOT_SUPPORTED); + + result = umfCUDAMemoryProviderParamsSetMemoryType(hParams, + UMF_MEMORY_TYPE_DEVICE); + ASSERT_EQ(result, UMF_RESULT_ERROR_NOT_SUPPORTED); + + umf_memory_provider_ops_t *ops = umfCUDAMemoryProviderOps(); + ASSERT_EQ(ops, nullptr); +} From 109cc50f7c9552622c5e2490e1bd0860ef6d823f Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Wed, 27 Nov 2024 04:43:55 -0800 Subject: [PATCH 330/352] Add libumfInit call to the umfScalablePoolParamsCreate --- src/pool/pool_scalable.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pool/pool_scalable.c b/src/pool/pool_scalable.c index 7f355161c..6ee364344 100644 --- a/src/pool/pool_scalable.c +++ b/src/pool/pool_scalable.c @@ -19,6 +19,7 @@ #include #include "base_alloc_global.h" +#include "libumf.h" #include "utils_common.h" #include "utils_concurrency.h" #include "utils_load_library.h" @@ -175,6 +176,7 @@ static void tbb_raw_free_wrapper(intptr_t pool_id, void *ptr, size_t bytes) { umf_result_t umfScalablePoolParamsCreate(umf_scalable_pool_params_handle_t *hParams) { + libumfInit(); if (!hParams) { LOG_ERR("scalable pool params handle is NULL"); return UMF_RESULT_ERROR_INVALID_ARGUMENT; From 40a3aecd29818710bfa182c2999a694ea49aeafe Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 27 Nov 2024 15:40:13 +0100 Subject: [PATCH 331/352] Remove not needed code Signed-off-by: Lukasz Dorau --- src/proxy_lib/proxy_lib.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/proxy_lib/proxy_lib.c b/src/proxy_lib/proxy_lib.c index 4b168ab80..572e99143 100644 --- a/src/proxy_lib/proxy_lib.c +++ b/src/proxy_lib/proxy_lib.c @@ -170,13 +170,6 @@ static int get_system_allocator_symbols(void) { return 0; } - *((void **)(&System_aligned_alloc)) = NULL; - *((void **)(&System_calloc)) = NULL; - *((void **)(&System_free)) = NULL; - *((void **)(&System_malloc)) = NULL; - *((void **)(&System_malloc_usable_size)) = NULL; - *((void **)(&System_realloc)) = NULL; - return -1; } #endif /* _WIN32 */ From 98745dde5c2cc2b444881cbaa3997bb43c90a06e Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Wed, 27 Nov 2024 15:41:47 +0100 Subject: [PATCH 332/352] Use unused ba_leak_aligned_alloc() Use unused ba_leak_aligned_alloc() in ba_leak_malloc() and ba_leak_calloc(). Signed-off-by: Lukasz Dorau --- src/proxy_lib/proxy_lib.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/proxy_lib/proxy_lib.c b/src/proxy_lib/proxy_lib.c index 572e99143..f8bae304d 100644 --- a/src/proxy_lib/proxy_lib.c +++ b/src/proxy_lib/proxy_lib.c @@ -316,15 +316,21 @@ static void ba_leak_init_once(void) { utils_init_once(&Base_alloc_leak_initialized, ba_leak_create); } -static inline void *ba_leak_malloc(size_t size) { +static inline void *ba_leak_aligned_alloc(size_t alignment, size_t size) { ba_leak_init_once(); - return umf_ba_linear_alloc(Base_alloc_leak, size); + void *ptr = umf_ba_linear_alloc(Base_alloc_leak, size + alignment); + return (void *)ALIGN_UP_SAFE((uintptr_t)ptr, alignment); +} + +static inline void *ba_leak_malloc(size_t size) { + return ba_leak_aligned_alloc(0, size); } static inline void *ba_leak_calloc(size_t nmemb, size_t size) { ba_leak_init_once(); // umf_ba_linear_alloc() returns zeroed memory - return umf_ba_linear_alloc(Base_alloc_leak, nmemb * size); + // so ba_leak_aligned_alloc() does too + return ba_leak_aligned_alloc(0, nmemb * size); } static inline void *ba_leak_realloc(void *ptr, size_t size, size_t max_size) { @@ -332,12 +338,6 @@ static inline void *ba_leak_realloc(void *ptr, size_t size, size_t max_size) { return ba_generic_realloc(Base_alloc_leak, ptr, size, max_size); } -static inline void *ba_leak_aligned_alloc(size_t alignment, size_t size) { - ba_leak_init_once(); - void *ptr = umf_ba_linear_alloc(Base_alloc_leak, size + alignment); - return (void *)ALIGN_UP_SAFE((uintptr_t)ptr, alignment); -} - static inline int ba_leak_free(void *ptr) { ba_leak_init_once(); return umf_ba_linear_free(Base_alloc_leak, ptr); From 9dc364d0eb95bd5f9424b7a6a2cf6a47b2f033c6 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Wed, 27 Nov 2024 15:44:43 +0100 Subject: [PATCH 333/352] Add test for not implemented OS provider --- test/CMakeLists.txt | 7 +++++ test/provider_os_memory_not_impl.cpp | 46 ++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 test/provider_os_memory_not_impl.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 68d6018f9..6ce94654a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -345,6 +345,13 @@ else() LIBS ${UMF_UTILS_FOR_TEST}) endif() +if(UMF_DISABLE_HWLOC) + add_umf_test( + NAME provider_os_memory_not_impl + SRCS provider_os_memory_not_impl.cpp + LIBS ${UMF_UTILS_FOR_TEST}) +endif() + if(UMF_BUILD_GPU_TESTS AND UMF_BUILD_LEVEL_ZERO_PROVIDER) # we have two test binaries here that use the same sources, but differ in # the way they are linked to the Level Zero (statically or at runtime using diff --git a/test/provider_os_memory_not_impl.cpp b/test/provider_os_memory_not_impl.cpp new file mode 100644 index 000000000..13c123fb7 --- /dev/null +++ b/test/provider_os_memory_not_impl.cpp @@ -0,0 +1,46 @@ +// Copyright (C) 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 "base.hpp" + +#include + +using umf_test::test; + +TEST_F(test, os_provider_not_implemented) { + umf_os_memory_provider_params_handle_t params = nullptr; + umf_result_t umf_result = umfOsMemoryProviderParamsCreate(¶ms); + EXPECT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); + EXPECT_EQ(params, nullptr); + + umf_result = umfOsMemoryProviderParamsDestroy(params); + EXPECT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); + + umf_result = umfOsMemoryProviderParamsSetProtection(params, 0); + EXPECT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); + + umf_result = + umfOsMemoryProviderParamsSetVisibility(params, UMF_MEM_MAP_PRIVATE); + EXPECT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); + + umf_result = umfOsMemoryProviderParamsSetShmName(params, "shm_name"); + EXPECT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); + + umf_result = umfOsMemoryProviderParamsSetNumaList(params, nullptr, 0); + EXPECT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); + + umf_result = + umfOsMemoryProviderParamsSetNumaMode(params, UMF_NUMA_MODE_DEFAULT); + EXPECT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); + + umf_result = umfOsMemoryProviderParamsSetPartSize(params, 4096); + EXPECT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); + + umf_numa_split_partition_t partitions[1]; + umf_result = umfOsMemoryProviderParamsSetPartitions(params, partitions, 1); + EXPECT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); + + umf_memory_provider_ops_t *ops = umfOsMemoryProviderOps(); + EXPECT_EQ(ops, nullptr); +} From 0c75c074984612b27a004d5e9c63d0686d0e698d Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Thu, 28 Nov 2024 11:44:52 +0100 Subject: [PATCH 334/352] Rename utils_level_zero.h to examples_level_zero.h Signed-off-by: Lukasz Dorau --- benchmark/ubench.c | 2 +- examples/common/{utils_level_zero.h => examples_level_zero.h} | 0 examples/ipc_level_zero/ipc_level_zero.c | 2 +- examples/level_zero_shared_memory/level_zero_shared_memory.c | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename examples/common/{utils_level_zero.h => examples_level_zero.h} (100%) diff --git a/benchmark/ubench.c b/benchmark/ubench.c index 1deabde0c..6e23d47c8 100644 --- a/benchmark/ubench.c +++ b/benchmark/ubench.c @@ -32,7 +32,7 @@ #if (defined UMF_BUILD_LIBUMF_POOL_DISJOINT && \ defined UMF_BUILD_LEVEL_ZERO_PROVIDER && defined UMF_BUILD_GPU_TESTS) -#include "utils_level_zero.h" +#include "examples_level_zero.h" #endif // NOTE: with strict compilation flags, ubench compilation throws some diff --git a/examples/common/utils_level_zero.h b/examples/common/examples_level_zero.h similarity index 100% rename from examples/common/utils_level_zero.h rename to examples/common/examples_level_zero.h diff --git a/examples/ipc_level_zero/ipc_level_zero.c b/examples/ipc_level_zero/ipc_level_zero.c index fc93eb930..c7b74171f 100644 --- a/examples/ipc_level_zero/ipc_level_zero.c +++ b/examples/ipc_level_zero/ipc_level_zero.c @@ -14,7 +14,7 @@ #include "umf/pools/pool_disjoint.h" #include "umf/providers/provider_level_zero.h" -#include "utils_level_zero.h" +#include "examples_level_zero.h" int create_level_zero_pool(ze_context_handle_t context, ze_device_handle_t device, diff --git a/examples/level_zero_shared_memory/level_zero_shared_memory.c b/examples/level_zero_shared_memory/level_zero_shared_memory.c index d7f68168d..725941f6e 100644 --- a/examples/level_zero_shared_memory/level_zero_shared_memory.c +++ b/examples/level_zero_shared_memory/level_zero_shared_memory.c @@ -11,7 +11,7 @@ #include #include -#include "utils_level_zero.h" +#include "examples_level_zero.h" int main(void) { // A result object for storing UMF API result status From 87b1348a9e4a014014cd5f71a0a231b77c4b8590 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Thu, 28 Nov 2024 11:48:46 +0100 Subject: [PATCH 335/352] Rename utils_examples.h to examples_utils.h Signed-off-by: Lukasz Dorau --- examples/common/{utils_examples.h => examples_utils.h} | 0 examples/memspace_hmat/memspace_hmat.c | 2 +- examples/memspace_numa/memspace_numa.c | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename examples/common/{utils_examples.h => examples_utils.h} (100%) diff --git a/examples/common/utils_examples.h b/examples/common/examples_utils.h similarity index 100% rename from examples/common/utils_examples.h rename to examples/common/examples_utils.h diff --git a/examples/memspace_hmat/memspace_hmat.c b/examples/memspace_hmat/memspace_hmat.c index 1a4cf154e..9f3f8d17e 100644 --- a/examples/memspace_hmat/memspace_hmat.c +++ b/examples/memspace_hmat/memspace_hmat.c @@ -15,7 +15,7 @@ #include #include -#include "utils_examples.h" +#include "examples_utils.h" // Function to create a memory provider which allocates memory from the specified NUMA node int createMemoryProvider(umf_memory_provider_handle_t *hProvider, diff --git a/examples/memspace_numa/memspace_numa.c b/examples/memspace_numa/memspace_numa.c index e2c460f70..4f225cd69 100644 --- a/examples/memspace_numa/memspace_numa.c +++ b/examples/memspace_numa/memspace_numa.c @@ -15,7 +15,7 @@ #include #include -#include "utils_examples.h" +#include "examples_utils.h" // Function to create a memory provider which allocates memory from the specified NUMA node // by using umfMemspaceCreateFromNumaArray From 5108356a3c61606aa57397facd17cdb951c028f2 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Thu, 28 Nov 2024 09:24:43 +0100 Subject: [PATCH 336/352] Fix level_zero_helpers.cpp Fix level_zero_helpers.cpp: - make local functions static - initialize level_zero_init_flag with UTIL_ONCE_FLAG_INIT Signed-off-by: Lukasz Dorau --- test/providers/level_zero_helpers.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/providers/level_zero_helpers.cpp b/test/providers/level_zero_helpers.cpp index cd387ab91..088e1b814 100644 --- a/test/providers/level_zero_helpers.cpp +++ b/test/providers/level_zero_helpers.cpp @@ -306,9 +306,10 @@ static int init_level_zero_lib(void) { return 0; } -UTIL_ONCE_FLAG level_zero_init_flag; -int InitResult; -void init_level_zero_once() { +static UTIL_ONCE_FLAG level_zero_init_flag = UTIL_ONCE_FLAG_INIT; +static int InitResult; + +static void init_level_zero_once(void) { InitResult = InitLevelZeroOps(); if (InitResult != 0) { return; @@ -316,7 +317,7 @@ void init_level_zero_once() { InitResult = init_level_zero_lib(); } -int init_level_zero() { +static int init_level_zero(void) { utils_init_once(&level_zero_init_flag, init_level_zero_once); return InitResult; From 7b22b80e71789a5feb5610b74d239cd29a5aa9e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Thu, 28 Nov 2024 12:42:06 +0100 Subject: [PATCH 337/352] [CI] Fix QEMU build on Ubuntu 22.04 ssh may return non-zero code on shutting down the connection. If the VM won't close properly it will fail in next stop of the workflow. --- .github/workflows/reusable_qemu.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/reusable_qemu.yml b/.github/workflows/reusable_qemu.yml index 36c125ea9..257e90f62 100644 --- a/.github/workflows/reusable_qemu.yml +++ b/.github/workflows/reusable_qemu.yml @@ -124,7 +124,8 @@ jobs: ssh testuser@127.0.0.1 -p 2222 -t "sudo chown -R testuser:users /home/testuser" ssh testuser@127.0.0.1 -p 2222 -t "bash /home/testuser/scripts/qemu/run-build.sh COVERAGE" - ssh testuser@127.0.0.1 -p 2222 -t "sudo shutdown -h now" + # ssh may return non-zero error code on closing the connection in Ubuntu 22.04 + ssh testuser@127.0.0.1 -p 2222 -t "sudo shutdown -h now" || true - name: Run tests in QEMU run: | @@ -143,7 +144,8 @@ jobs: ssh testuser@127.0.0.1 -p 2222 -t "export SHORT_RUN=${SHORT_RUN} OS_FULL_NAME=${{matrix.os}} && /home/testuser/scripts/qemu/run-tests.sh COVERAGE ${config_name}" scp -r -P 2222 testuser@127.0.0.1:/home/testuser/coverage ./ - ssh testuser@127.0.0.1 -p 2222 -t "sudo shutdown -h now" + # ssh may return non-zero error code on closing the connection in Ubuntu 22.04 + ssh testuser@127.0.0.1 -p 2222 -t "sudo shutdown -h now" || true done ls -al ./coverage From e569de82dbcf7b4f924b9476ad1e89ee54e1ee33 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Fri, 22 Nov 2024 15:41:50 +0100 Subject: [PATCH 338/352] Update DevDax provider config API --- .../umf/providers/provider_devdax_memory.h | 58 +++--- src/libumf.def | 4 + src/libumf.map | 4 + src/provider/provider_devdax_memory.c | 135 ++++++++++++++ test/ipc_devdax_prov_consumer.c | 21 ++- test/ipc_devdax_prov_producer.c | 21 ++- test/poolFixtures.hpp | 21 --- test/pools/jemalloc_coarse_devdax.cpp | 41 ++++- test/pools/scalable_coarse_devdax.cpp | 41 ++++- test/provider_devdax_memory.cpp | 167 ++++++++++++++---- test/provider_devdax_memory_ipc.cpp | 46 +++-- 11 files changed, 438 insertions(+), 121 deletions(-) diff --git a/include/umf/providers/provider_devdax_memory.h b/include/umf/providers/provider_devdax_memory.h index 113d38372..0fb5218bc 100644 --- a/include/umf/providers/provider_devdax_memory.h +++ b/include/umf/providers/provider_devdax_memory.h @@ -18,15 +18,43 @@ extern "C" { #define UMF_DEVDAX_RESULTS_START_FROM 2000 /// @endcond -/// @brief Memory provider settings struct -typedef struct umf_devdax_memory_provider_params_t { - /// path of the device DAX - char *path; - /// size of the device DAX in bytes - size_t size; - /// combination of 'umf_mem_protection_flags_t' flags - unsigned protection; -} umf_devdax_memory_provider_params_t; +struct umf_devdax_memory_provider_params_t; + +typedef struct umf_devdax_memory_provider_params_t + *umf_devdax_memory_provider_params_handle_t; + +/// @brief Create a struct to store parameters of the Devdax Memory Provider. +/// @param hParams [out] handle to the newly created parameters struct. +/// @param path [in] path of the device DAX. +/// @param size [in] size of the device DAX in bytes. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfDevDaxMemoryProviderParamsCreate( + umf_devdax_memory_provider_params_handle_t *hParams, const char *path, + size_t size); + +/// @brief Destroy parameters struct. +/// @param hParams [in] handle to the parameters of the Devdax Memory Provider. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfDevDaxMemoryProviderParamsDestroy( + umf_devdax_memory_provider_params_handle_t hParams); + +/// @brief Set a device DAX in the parameters struct. Overwrites the previous value. +/// It provides an ability to use the same instance of params to create multiple +/// instances of the provider for different DAX devices. +/// @param hParams [in] handle to the parameters of the Devdax Memory Provider. +/// @param path [in] path of the device DAX. +/// @param size [in] size of the device DAX in bytes. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfDevDaxMemoryProviderParamsSetDeviceDax( + umf_devdax_memory_provider_params_handle_t hParams, const char *path, + size_t size); + +/// @brief Set the protection flags in the parameters struct. +/// @param hParams [in] handle to the parameters of the Devdax Memory Provider. +/// @param protection [in] combination of 'umf_mem_protection_flags_t' flags. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfDevDaxMemoryProviderParamsSetProtection( + umf_devdax_memory_provider_params_handle_t hParams, unsigned protection); /// @brief Devdax Memory Provider operation results typedef enum umf_devdax_memory_provider_native_error { @@ -39,18 +67,6 @@ typedef enum umf_devdax_memory_provider_native_error { umf_memory_provider_ops_t *umfDevDaxMemoryProviderOps(void); -/// @brief Create default params for the devdax memory provider -static inline umf_devdax_memory_provider_params_t -umfDevDaxMemoryProviderParamsDefault(char *path, size_t size) { - umf_devdax_memory_provider_params_t params = { - path, /* path of the device DAX */ - size, /* size of the device DAX in bytes */ - UMF_PROTECTION_READ | UMF_PROTECTION_WRITE, /* protection */ - }; - - return params; -} - #ifdef __cplusplus } #endif diff --git a/src/libumf.def b/src/libumf.def index ae1ba6809..0b4588bb8 100644 --- a/src/libumf.def +++ b/src/libumf.def @@ -23,6 +23,10 @@ EXPORTS umfCUDAMemoryProviderParamsSetDevice umfCUDAMemoryProviderParamsSetMemoryType umfDevDaxMemoryProviderOps + umfDevDaxMemoryProviderParamsCreate + umfDevDaxMemoryProviderParamsDestroy + umfDevDaxMemoryProviderParamsSetDeviceDax + umfDevDaxMemoryProviderParamsSetProtection umfFree umfFileMemoryProviderOps umfFileMemoryProviderParamsCreate diff --git a/src/libumf.map b/src/libumf.map index 923112384..41467bad5 100644 --- a/src/libumf.map +++ b/src/libumf.map @@ -17,6 +17,10 @@ UMF_1.0 { umfCUDAMemoryProviderParamsSetDevice; umfCUDAMemoryProviderParamsSetMemoryType; umfDevDaxMemoryProviderOps; + umfDevDaxMemoryProviderParamsCreate; + umfDevDaxMemoryProviderParamsDestroy; + umfDevDaxMemoryProviderParamsSetDeviceDax; + umfDevDaxMemoryProviderParamsSetProtection; umfFree; umfFileMemoryProviderOps; umfFileMemoryProviderParamsCreate; diff --git a/src/provider/provider_devdax_memory.c b/src/provider/provider_devdax_memory.c index 1179ed115..f7c9e09ba 100644 --- a/src/provider/provider_devdax_memory.c +++ b/src/provider/provider_devdax_memory.c @@ -24,9 +24,41 @@ umf_memory_provider_ops_t *umfDevDaxMemoryProviderOps(void) { return NULL; } +umf_result_t umfDevDaxMemoryProviderParamsCreate( + umf_devdax_memory_provider_params_handle_t *hParams, const char *path, + size_t size) { + (void)hParams; + (void)path; + (void)size; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + +umf_result_t umfDevDaxMemoryProviderParamsDestroy( + umf_devdax_memory_provider_params_handle_t hParams) { + (void)hParams; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + +umf_result_t umfDevDaxMemoryProviderParamsSetDeviceDax( + umf_devdax_memory_provider_params_handle_t hParams, const char *path, + size_t size) { + (void)hParams; + (void)path; + (void)size; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + +umf_result_t umfDevDaxMemoryProviderParamsSetProtection( + umf_devdax_memory_provider_params_handle_t hParams, unsigned protection) { + (void)hParams; + (void)protection; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + #else // !defined(_WIN32) && !defined(UMF_NO_HWLOC) #include "base_alloc_global.h" +#include "libumf.h" #include "utils_common.h" #include "utils_concurrency.h" #include "utils_log.h" @@ -44,6 +76,13 @@ typedef struct devdax_memory_provider_t { unsigned protection; // combination of OS-specific protection flags } devdax_memory_provider_t; +// DevDax Memory provider settings struct +typedef struct umf_devdax_memory_provider_params_t { + char *path; + size_t size; + unsigned protection; +} umf_devdax_memory_provider_params_t; + typedef struct devdax_last_native_error_t { int32_t native_error; int errno_value; @@ -511,4 +550,100 @@ umf_memory_provider_ops_t *umfDevDaxMemoryProviderOps(void) { return &UMF_DEVDAX_MEMORY_PROVIDER_OPS; } +umf_result_t umfDevDaxMemoryProviderParamsCreate( + umf_devdax_memory_provider_params_handle_t *hParams, const char *path, + size_t size) { + libumfInit(); + if (hParams == NULL) { + LOG_ERR("DevDax Memory Provider params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + if (path == NULL) { + LOG_ERR("DevDax path is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + umf_devdax_memory_provider_params_handle_t params = + umf_ba_global_alloc(sizeof(*params)); + if (params == NULL) { + LOG_ERR( + "Allocating memory for the DevDax Memory Provider params failed"); + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + params->path = NULL; + params->size = 0; + params->protection = UMF_PROTECTION_READ | UMF_PROTECTION_WRITE; + + umf_result_t res = + umfDevDaxMemoryProviderParamsSetDeviceDax(params, path, size); + if (res != UMF_RESULT_SUCCESS) { + umf_ba_global_free(params); + return res; + } + + *hParams = params; + + return UMF_RESULT_SUCCESS; +} + +umf_result_t umfDevDaxMemoryProviderParamsDestroy( + umf_devdax_memory_provider_params_handle_t hParams) { + if (hParams != NULL) { + umf_ba_global_free(hParams->path); + umf_ba_global_free(hParams); + } + + return UMF_RESULT_SUCCESS; +} + +umf_result_t umfDevDaxMemoryProviderParamsSetDeviceDax( + umf_devdax_memory_provider_params_handle_t hParams, const char *path, + size_t size) { + if (hParams == NULL) { + LOG_ERR("DevDax Memory Provider params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + if (path == NULL) { + LOG_ERR("DevDax path is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + size_t path_len = strlen(path); + if (path_len == 0) { + LOG_ERR("DevDax path is empty"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + path_len += 1; // for the null terminator + char *new_path = umf_ba_global_alloc(path_len); + if (new_path == NULL) { + LOG_ERR("Allocating memory for the DevDax path failed"); + return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; + } + + strncpy(new_path, path, path_len); + + umf_ba_global_free(hParams->path); + + hParams->path = new_path; + hParams->size = size; + + return UMF_RESULT_SUCCESS; +} + +umf_result_t umfDevDaxMemoryProviderParamsSetProtection( + umf_devdax_memory_provider_params_handle_t hParams, unsigned protection) { + if (hParams == NULL) { + LOG_ERR("DevDax Memory Provider params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + hParams->protection = protection; + + return UMF_RESULT_SUCCESS; +} + #endif // !defined(_WIN32) && !defined(UMF_NO_HWLOC) diff --git a/test/ipc_devdax_prov_consumer.c b/test/ipc_devdax_prov_consumer.c index a8fd8211d..286b6de78 100644 --- a/test/ipc_devdax_prov_consumer.c +++ b/test/ipc_devdax_prov_consumer.c @@ -19,6 +19,7 @@ int main(int argc, char *argv[]) { return -1; } + int ret = 0; int port = atoi(argv[1]); char *path = getenv("UMF_TESTS_DEVDAX_PATH"); @@ -33,12 +34,22 @@ int main(int argc, char *argv[]) { return 0; } - umf_devdax_memory_provider_params_t devdax_params = - umfDevDaxMemoryProviderParamsDefault(path, atol(size)); + umf_devdax_memory_provider_params_handle_t devdax_params = NULL; + umf_result_t umf_result = + umfDevDaxMemoryProviderParamsCreate(&devdax_params, path, atol(size)); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "[consumer] ERROR: creating DevDax Memory Provider " + "params failed\n"); + return -1; + } void *pool_params = NULL; - return run_consumer(port, umfScalablePoolOps(), pool_params, - umfDevDaxMemoryProviderOps(), &devdax_params, memcopy, - NULL); + ret = run_consumer(port, umfScalablePoolOps(), pool_params, + umfDevDaxMemoryProviderOps(), devdax_params, memcopy, + NULL); + + umfDevDaxMemoryProviderParamsDestroy(devdax_params); + + return ret; } diff --git a/test/ipc_devdax_prov_producer.c b/test/ipc_devdax_prov_producer.c index 90afe64dd..479c1f945 100644 --- a/test/ipc_devdax_prov_producer.c +++ b/test/ipc_devdax_prov_producer.c @@ -19,6 +19,7 @@ int main(int argc, char *argv[]) { return -1; } + int ret = 0; int port = atoi(argv[1]); char *path = getenv("UMF_TESTS_DEVDAX_PATH"); @@ -33,12 +34,22 @@ int main(int argc, char *argv[]) { return 0; } - umf_devdax_memory_provider_params_t devdax_params = - umfDevDaxMemoryProviderParamsDefault(path, atol(size)); + umf_devdax_memory_provider_params_handle_t devdax_params = NULL; + umf_result_t umf_result = + umfDevDaxMemoryProviderParamsCreate(&devdax_params, path, atol(size)); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "[producer] ERROR: creating DevDax Memory Provider " + "params failed\n"); + return -1; + } void *pool_params = NULL; - return run_producer(port, umfScalablePoolOps(), pool_params, - umfDevDaxMemoryProviderOps(), &devdax_params, memcopy, - NULL); + ret = run_producer(port, umfScalablePoolOps(), pool_params, + umfDevDaxMemoryProviderOps(), devdax_params, memcopy, + NULL); + + umfDevDaxMemoryProviderParamsDestroy(devdax_params); + + return ret; } diff --git a/test/poolFixtures.hpp b/test/poolFixtures.hpp index 995db981b..e5ec85012 100644 --- a/test/poolFixtures.hpp +++ b/test/poolFixtures.hpp @@ -69,27 +69,6 @@ struct umfPoolTest : umf_test::test, void SetUp() override { test::SetUp(); - auto [pool_ops, pool_params, provider_ops, provider_params, - coarse_params] = this->GetParam(); - (void)pool_ops; - (void)pool_params; - (void)provider_params; - (void)coarse_params; - - if (provider_ops == umfDevDaxMemoryProviderOps()) { - char *path = getenv("UMF_TESTS_DEVDAX_PATH"); - if (path == nullptr || path[0] == 0) { - GTEST_SKIP() - << "Test skipped, UMF_TESTS_DEVDAX_PATH is not set"; - } - - char *size = getenv("UMF_TESTS_DEVDAX_SIZE"); - if (size == nullptr || size[0] == 0) { - GTEST_SKIP() - << "Test skipped, UMF_TESTS_DEVDAX_SIZE is not set"; - } - } - pool = poolCreateExtUnique(this->GetParam()); } diff --git a/test/pools/jemalloc_coarse_devdax.cpp b/test/pools/jemalloc_coarse_devdax.cpp index ae98ecf4b..350e053ab 100644 --- a/test/pools/jemalloc_coarse_devdax.cpp +++ b/test/pools/jemalloc_coarse_devdax.cpp @@ -7,14 +7,39 @@ #include "pool_coarse.hpp" +using devdax_params_unique_handle_t = + std::unique_ptr; + +devdax_params_unique_handle_t create_devdax_params() { + char *path = getenv("UMF_TESTS_DEVDAX_PATH"); + char *size = getenv("UMF_TESTS_DEVDAX_SIZE"); + if (path == nullptr || path[0] == 0 || size == nullptr || size[0] == 0) { + return devdax_params_unique_handle_t( + nullptr, &umfDevDaxMemoryProviderParamsDestroy); + } + + umf_devdax_memory_provider_params_handle_t params = NULL; + umf_result_t res = + umfDevDaxMemoryProviderParamsCreate(¶ms, path, atol(size)); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error( + "Failed to create DevDax Memory Provider params"); + } + + return devdax_params_unique_handle_t(params, + &umfDevDaxMemoryProviderParamsDestroy); +} + auto coarseParams = umfCoarseMemoryProviderParamsDefault(); -auto devdaxParams = umfDevDaxMemoryProviderParamsDefault( - getenv("UMF_TESTS_DEVDAX_PATH"), getenv("UMF_TESTS_DEVDAX_SIZE") - ? atol(getenv("UMF_TESTS_DEVDAX_SIZE")) - : 0); +auto devdaxParams = create_devdax_params(); + +static std::vector poolParamsList = + devdaxParams.get() + ? std::vector{poolCreateExtParams{ + umfJemallocPoolOps(), nullptr, umfDevDaxMemoryProviderOps(), + devdaxParams.get(), &coarseParams}} + : std::vector{}; INSTANTIATE_TEST_SUITE_P(jemallocCoarseDevDaxTest, umfPoolTest, - ::testing::Values(poolCreateExtParams{ - umfJemallocPoolOps(), nullptr, - umfDevDaxMemoryProviderOps(), &devdaxParams, - &coarseParams})); + ::testing::ValuesIn(poolParamsList)); diff --git a/test/pools/scalable_coarse_devdax.cpp b/test/pools/scalable_coarse_devdax.cpp index b5da7d242..1bf77c61c 100644 --- a/test/pools/scalable_coarse_devdax.cpp +++ b/test/pools/scalable_coarse_devdax.cpp @@ -7,14 +7,39 @@ #include "pool_coarse.hpp" +using devdax_params_unique_handle_t = + std::unique_ptr; + +devdax_params_unique_handle_t create_devdax_params() { + char *path = getenv("UMF_TESTS_DEVDAX_PATH"); + char *size = getenv("UMF_TESTS_DEVDAX_SIZE"); + if (path == nullptr || path[0] == 0 || size == nullptr || size[0] == 0) { + return devdax_params_unique_handle_t( + nullptr, &umfDevDaxMemoryProviderParamsDestroy); + } + + umf_devdax_memory_provider_params_handle_t params = NULL; + umf_result_t res = + umfDevDaxMemoryProviderParamsCreate(¶ms, path, atol(size)); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error( + "Failed to create DevDax Memory Provider params"); + } + + return devdax_params_unique_handle_t(params, + &umfDevDaxMemoryProviderParamsDestroy); +} + auto coarseParams = umfCoarseMemoryProviderParamsDefault(); -auto devdaxParams = umfDevDaxMemoryProviderParamsDefault( - getenv("UMF_TESTS_DEVDAX_PATH"), getenv("UMF_TESTS_DEVDAX_SIZE") - ? atol(getenv("UMF_TESTS_DEVDAX_SIZE")) - : 0); +auto devdaxParams = create_devdax_params(); + +static std::vector poolParamsList = + devdaxParams.get() + ? std::vector{poolCreateExtParams{ + umfScalablePoolOps(), nullptr, umfDevDaxMemoryProviderOps(), + devdaxParams.get(), &coarseParams}} + : std::vector{}; INSTANTIATE_TEST_SUITE_P(scalableCoarseDevDaxTest, umfPoolTest, - ::testing::Values(poolCreateExtParams{ - umfScalablePoolOps(), nullptr, - umfDevDaxMemoryProviderOps(), &devdaxParams, - &coarseParams})); + ::testing::ValuesIn(poolParamsList)); diff --git a/test/provider_devdax_memory.cpp b/test/provider_devdax_memory.cpp index c41fb8769..342d2e363 100644 --- a/test/provider_devdax_memory.cpp +++ b/test/provider_devdax_memory.cpp @@ -63,16 +63,6 @@ struct umfProviderTest : umf_test::test, ::testing::WithParamInterface { void SetUp() override { - char *path = getenv("UMF_TESTS_DEVDAX_PATH"); - if (path == nullptr || path[0] == 0) { - GTEST_SKIP() << "Test skipped, UMF_TESTS_DEVDAX_PATH is not set"; - } - - char *size = getenv("UMF_TESTS_DEVDAX_SIZE"); - if (size == nullptr || size[0] == 0) { - GTEST_SKIP() << "Test skipped, UMF_TESTS_DEVDAX_SIZE is not set"; - } - test::SetUp(); providerCreateExt(this->GetParam(), &provider); umf_result_t umf_result = umfMemoryProviderGetMinPageSize( @@ -154,9 +144,12 @@ TEST_F(test, test_if_mapped_with_MAP_SYNC) { } size_t size = atol(size_str); - auto params = umfDevDaxMemoryProviderParamsDefault(path, size); + umf_devdax_memory_provider_params_handle_t params = NULL; + umf_result = umfDevDaxMemoryProviderParamsCreate(¶ms, path, size); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(params, nullptr); - umf_result = umfMemoryProviderCreate(umfDevDaxMemoryProviderOps(), ¶ms, + umf_result = umfMemoryProviderCreate(umfDevDaxMemoryProviderOps(), params, &hProvider); ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); ASSERT_NE(hProvider, nullptr); @@ -179,15 +172,42 @@ TEST_F(test, test_if_mapped_with_MAP_SYNC) { // positive tests using test_alloc_free_success -auto defaultDevDaxParams = umfDevDaxMemoryProviderParamsDefault( - getenv("UMF_TESTS_DEVDAX_PATH"), - atol(getenv("UMF_TESTS_DEVDAX_SIZE") ? getenv("UMF_TESTS_DEVDAX_SIZE") - : "0")); +using devdax_params_unique_handle_t = + std::unique_ptr; + +devdax_params_unique_handle_t create_devdax_params() { + char *path = getenv("UMF_TESTS_DEVDAX_PATH"); + char *size = getenv("UMF_TESTS_DEVDAX_SIZE"); + if (path == nullptr || path[0] == 0 || size == nullptr || size[0] == 0) { + return devdax_params_unique_handle_t( + nullptr, &umfDevDaxMemoryProviderParamsDestroy); + } + + umf_devdax_memory_provider_params_handle_t params = NULL; + umf_result_t res = + umfDevDaxMemoryProviderParamsCreate(¶ms, path, atol(size)); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error( + "Failed to create DevDax Memory Provider params"); + } + + return devdax_params_unique_handle_t(params, + &umfDevDaxMemoryProviderParamsDestroy); +} + +auto defaultDevDaxParams = create_devdax_params(); + +static std::vector devdaxProviderTestParamsList = + defaultDevDaxParams.get() + ? std::vector{providerCreateExtParams{ + umfDevDaxMemoryProviderOps(), defaultDevDaxParams.get()}} + : std::vector{}; + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(umfProviderTest); INSTANTIATE_TEST_SUITE_P(devdaxProviderTest, umfProviderTest, - ::testing::Values(providerCreateExtParams{ - umfDevDaxMemoryProviderOps(), - &defaultDevDaxParams})); + ::testing::ValuesIn(devdaxProviderTestParamsList)); TEST_P(umfProviderTest, create_destroy) {} @@ -308,45 +328,118 @@ TEST_P(umfProviderTest, purge_force_INVALID_POINTER) { // negative tests +TEST_F(test, params_null_handle) { + auto ret = + umfDevDaxMemoryProviderParamsCreate(nullptr, "/dev/dax0.0", 4096); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + ret = umfDevDaxMemoryProviderParamsDestroy(nullptr); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + ret = + umfDevDaxMemoryProviderParamsSetDeviceDax(nullptr, "/dev/dax0.0", 4096); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + ret = umfDevDaxMemoryProviderParamsSetProtection(nullptr, 1); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} + TEST_F(test, create_empty_path) { - umf_memory_provider_handle_t hProvider = nullptr; const char *path = ""; - auto wrong_params = - umfDevDaxMemoryProviderParamsDefault((char *)path, 4096); - auto ret = umfMemoryProviderCreate(umfDevDaxMemoryProviderOps(), - &wrong_params, &hProvider); - EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); - EXPECT_EQ(hProvider, nullptr); + umf_devdax_memory_provider_params_handle_t wrong_params = NULL; + auto ret = umfDevDaxMemoryProviderParamsCreate(&wrong_params, path, 4096); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + ASSERT_EQ(wrong_params, nullptr); +} + +TEST_F(test, create_null_path) { + const char *path = nullptr; + umf_devdax_memory_provider_params_handle_t wrong_params = NULL; + auto ret = umfDevDaxMemoryProviderParamsCreate(&wrong_params, path, 4096); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + ASSERT_EQ(wrong_params, nullptr); +} + +TEST_F(test, set_empty_path) { + const char *path = "tmp"; + const char *empty_path = ""; + umf_devdax_memory_provider_params_handle_t params = NULL; + auto ret = umfDevDaxMemoryProviderParamsCreate(¶ms, path, 4096); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(params, nullptr); + + ret = umfDevDaxMemoryProviderParamsSetDeviceDax(params, empty_path, 4096); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + ret = umfDevDaxMemoryProviderParamsDestroy(params); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); +} + +TEST_F(test, set_null_path) { + const char *path = "tmp"; + const char *null_path = nullptr; + umf_devdax_memory_provider_params_handle_t params = NULL; + auto ret = umfDevDaxMemoryProviderParamsCreate(¶ms, path, 4096); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(params, nullptr); + + ret = umfDevDaxMemoryProviderParamsSetDeviceDax(params, null_path, 4096); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + ret = umfDevDaxMemoryProviderParamsDestroy(params); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); } TEST_F(test, create_wrong_path) { umf_memory_provider_handle_t hProvider = nullptr; const char *path = "/tmp/dev/dax0.0"; - auto wrong_params = - umfDevDaxMemoryProviderParamsDefault((char *)path, 4096); - auto ret = umfMemoryProviderCreate(umfDevDaxMemoryProviderOps(), - &wrong_params, &hProvider); + umf_devdax_memory_provider_params_handle_t wrong_params = nullptr; + + auto ret = umfDevDaxMemoryProviderParamsCreate(&wrong_params, path, 4096); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(wrong_params, nullptr); + + ret = umfMemoryProviderCreate(umfDevDaxMemoryProviderOps(), wrong_params, + &hProvider); EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); EXPECT_EQ(hProvider, nullptr); + + ret = umfDevDaxMemoryProviderParamsDestroy(wrong_params); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); } TEST_F(test, create_wrong_path_not_exist) { umf_memory_provider_handle_t hProvider = nullptr; const char *path = "/dev/dax1.1"; - auto wrong_params = - umfDevDaxMemoryProviderParamsDefault((char *)path, 4096); - auto ret = umfMemoryProviderCreate(umfDevDaxMemoryProviderOps(), - &wrong_params, &hProvider); + umf_devdax_memory_provider_params_handle_t wrong_params = nullptr; + + auto ret = umfDevDaxMemoryProviderParamsCreate(&wrong_params, path, 4096); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(wrong_params, nullptr); + + ret = umfMemoryProviderCreate(umfDevDaxMemoryProviderOps(), wrong_params, + &hProvider); EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); EXPECT_EQ(hProvider, nullptr); + + ret = umfDevDaxMemoryProviderParamsDestroy(wrong_params); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); } TEST_F(test, create_wrong_size_0) { umf_memory_provider_handle_t hProvider = nullptr; const char *path = "/dev/dax0.0"; - auto wrong_params = umfDevDaxMemoryProviderParamsDefault((char *)path, 0); - auto ret = umfMemoryProviderCreate(umfDevDaxMemoryProviderOps(), - &wrong_params, &hProvider); + umf_devdax_memory_provider_params_handle_t wrong_params = nullptr; + + auto ret = umfDevDaxMemoryProviderParamsCreate(&wrong_params, path, 0); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(wrong_params, nullptr); + + ret = umfMemoryProviderCreate(umfDevDaxMemoryProviderOps(), wrong_params, + &hProvider); EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); EXPECT_EQ(hProvider, nullptr); + + ret = umfDevDaxMemoryProviderParamsDestroy(wrong_params); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); } diff --git a/test/provider_devdax_memory_ipc.cpp b/test/provider_devdax_memory_ipc.cpp index 071196c94..3941f66e9 100644 --- a/test/provider_devdax_memory_ipc.cpp +++ b/test/provider_devdax_memory_ipc.cpp @@ -15,38 +15,52 @@ using umf_test::test; -auto defaultDevDaxParams = umfDevDaxMemoryProviderParamsDefault( - getenv("UMF_TESTS_DEVDAX_PATH"), - atol(getenv("UMF_TESTS_DEVDAX_SIZE") ? getenv("UMF_TESTS_DEVDAX_SIZE") - : "0")); +using devdax_params_unique_handle_t = + std::unique_ptr; + +devdax_params_unique_handle_t create_devdax_params() { + char *path = getenv("UMF_TESTS_DEVDAX_PATH"); + char *size = getenv("UMF_TESTS_DEVDAX_SIZE"); + if (path == nullptr || path[0] == 0 || size == nullptr || size[0] == 0) { + return devdax_params_unique_handle_t( + nullptr, &umfDevDaxMemoryProviderParamsDestroy); + } + + umf_devdax_memory_provider_params_handle_t params = NULL; + umf_result_t res = + umfDevDaxMemoryProviderParamsCreate(¶ms, path, atol(size)); + if (res != UMF_RESULT_SUCCESS) { + throw std::runtime_error( + "Failed to create DevDax Memory Provider params"); + } + + return devdax_params_unique_handle_t(params, + &umfDevDaxMemoryProviderParamsDestroy); +} + +auto defaultDevDaxParams = create_devdax_params(); HostMemoryAccessor hostAccessor; static std::vector getIpcProxyPoolTestParamsList(void) { std::vector ipcProxyPoolTestParamsList = {}; - char *path = getenv("UMF_TESTS_DEVDAX_PATH"); - if (path == nullptr || path[0] == 0) { - // skipping the test, UMF_TESTS_DEVDAX_PATH is not set - return ipcProxyPoolTestParamsList; - } - - char *size = getenv("UMF_TESTS_DEVDAX_SIZE"); - if (size == nullptr || size[0] == 0) { - // skipping the test, UMF_TESTS_DEVDAX_SIZE is not set + if (!defaultDevDaxParams.get()) { + // return empty list to skip the test return ipcProxyPoolTestParamsList; } ipcProxyPoolTestParamsList = { {umfProxyPoolOps(), nullptr, umfDevDaxMemoryProviderOps(), - &defaultDevDaxParams, &hostAccessor, true}, + defaultDevDaxParams.get(), &hostAccessor, true}, #ifdef UMF_POOL_JEMALLOC_ENABLED {umfJemallocPoolOps(), nullptr, umfDevDaxMemoryProviderOps(), - &defaultDevDaxParams, &hostAccessor, false}, + defaultDevDaxParams.get(), &hostAccessor, false}, #endif #ifdef UMF_POOL_SCALABLE_ENABLED {umfScalablePoolOps(), nullptr, umfDevDaxMemoryProviderOps(), - &defaultDevDaxParams, &hostAccessor, false}, + defaultDevDaxParams.get(), &hostAccessor, false}, #endif }; From 9f7fe4b26b2bf3efa178beb605ba2ad30df7bbb2 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Tue, 26 Nov 2024 13:52:47 +0100 Subject: [PATCH 339/352] Add test for not implemented devdax provider --- test/CMakeLists.txt | 4 ++++ test/provider_devdax_memory_not_impl.cpp | 30 ++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 test/provider_devdax_memory_not_impl.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6ce94654a..bf9884dc9 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -343,6 +343,10 @@ else() NAME provider_file_memory_not_impl SRCS provider_file_memory_not_impl.cpp LIBS ${UMF_UTILS_FOR_TEST}) + add_umf_test( + NAME provider_devdax_memory_not_impl + SRCS provider_devdax_memory_not_impl.cpp + LIBS ${UMF_UTILS_FOR_TEST}) endif() if(UMF_DISABLE_HWLOC) diff --git a/test/provider_devdax_memory_not_impl.cpp b/test/provider_devdax_memory_not_impl.cpp new file mode 100644 index 000000000..3b97443a0 --- /dev/null +++ b/test/provider_devdax_memory_not_impl.cpp @@ -0,0 +1,30 @@ +// Copyright (C) 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 "base.hpp" + +#include + +using umf_test::test; + +TEST_F(test, devdax_provider_not_implemented) { + umf_devdax_memory_provider_params_handle_t params = nullptr; + umf_result_t umf_result = + umfDevDaxMemoryProviderParamsCreate(¶ms, "path", 4096); + EXPECT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); + EXPECT_EQ(params, nullptr); + + umf_result = umfDevDaxMemoryProviderParamsDestroy(nullptr); + EXPECT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); + + umf_result = + umfDevDaxMemoryProviderParamsSetDeviceDax(nullptr, "path", 4096); + EXPECT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); + + umf_result = umfDevDaxMemoryProviderParamsSetProtection(nullptr, 0); + EXPECT_EQ(umf_result, UMF_RESULT_ERROR_NOT_SUPPORTED); + + umf_memory_provider_ops_t *ops = umfDevDaxMemoryProviderOps(); + EXPECT_EQ(ops, nullptr); +} From ae5b74347fce02b60f2bd5e7b117a36b52453c37 Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Thu, 28 Nov 2024 00:17:40 +0100 Subject: [PATCH 340/352] Validate protection flag in DEVDAX provider params --- src/provider/provider_devdax_memory.c | 10 +++++++ test/provider_devdax_memory.cpp | 42 ++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/provider/provider_devdax_memory.c b/src/provider/provider_devdax_memory.c index f7c9e09ba..32407acbb 100644 --- a/src/provider/provider_devdax_memory.c +++ b/src/provider/provider_devdax_memory.c @@ -641,6 +641,16 @@ umf_result_t umfDevDaxMemoryProviderParamsSetProtection( return UMF_RESULT_ERROR_INVALID_ARGUMENT; } + // verify that protection contains only valid bits set + // (UMF_PROTECTION_MAX-1) - highest possible bit + // (UMF_PROTECTION_MAX-1) << 1 - next after highest possible bit + // ((UMF_PROTECTION_MAX-1) << 1) - 1 - all valid bits set + const unsigned VALID_FLAGS_ALL = ((UMF_PROTECTION_MAX - 1) << 1) - 1; + if (protection & ~VALID_FLAGS_ALL || protection == 0) { + LOG_ERR("Incorrect memory protection flags: %u", protection); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + hParams->protection = protection; return UMF_RESULT_SUCCESS; diff --git a/test/provider_devdax_memory.cpp b/test/provider_devdax_memory.cpp index 342d2e363..0fd0705da 100644 --- a/test/provider_devdax_memory.cpp +++ b/test/provider_devdax_memory.cpp @@ -326,7 +326,47 @@ TEST_P(umfProviderTest, purge_force_INVALID_POINTER) { UMF_DEVDAX_RESULT_ERROR_PURGE_FORCE_FAILED); } -// negative tests +// params tests + +TEST_F(test, params_protection_flag) { + umf_devdax_memory_provider_params_handle_t params = nullptr; + umf_result_t ret = + umfDevDaxMemoryProviderParamsCreate(¶ms, "/dev/dax0.0", 4096); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(params, nullptr); + + //test all valid combinations + for (unsigned protection = UMF_PROTECTION_NONE; + protection < (UMF_PROTECTION_MAX - 1) << 1; ++protection) { + ret = umfDevDaxMemoryProviderParamsSetProtection(params, protection); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + } + + umfDevDaxMemoryProviderParamsDestroy(params); +} + +// negative params tests + +TEST_F(test, params_invalid_protection_flag) { + umf_devdax_memory_provider_params_handle_t params = nullptr; + umf_result_t ret = + umfDevDaxMemoryProviderParamsCreate(¶ms, "/dev/dax0.0", 4096); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(params, nullptr); + + ret = umfDevDaxMemoryProviderParamsSetProtection(params, 0); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + for (unsigned protection = UMF_PROTECTION_NONE; + protection < (UMF_PROTECTION_MAX - 1) << 1; ++protection) { + unsigned invalid_protection = protection | (UMF_PROTECTION_MAX << 1); + ret = umfDevDaxMemoryProviderParamsSetProtection(params, + invalid_protection); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + } + + umfDevDaxMemoryProviderParamsDestroy(params); +} TEST_F(test, params_null_handle) { auto ret = From 09daa84f74e4076e380e4702d53b0597e6963de1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Thu, 28 Nov 2024 12:56:43 +0100 Subject: [PATCH 341/352] [CI] Enable latest Ubuntu in QEMU nightly build This way we could verify the latest packages (e.g. compilers). --- .github/workflows/nightly.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 2c11fcc4b..281ae0061 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -191,4 +191,6 @@ jobs: uses: ./.github/workflows/reusable_qemu.yml with: short_run: false - os: "['ubuntu-22.04', 'ubuntu-24.04']" + # Beside the 2 LTS Ubuntu, we also test this on the latest Ubuntu - to be updated + # every 6 months, so we verify the latest version of packages (compilers, etc.). + os: "['ubuntu-22.04', 'ubuntu-24.04', 'ubuntu-24.10']" From 841cd4bb47c2c70a41ed066b71d55e9b90acb5e8 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Fri, 29 Nov 2024 10:55:42 +0100 Subject: [PATCH 342/352] Move level_zero_helpers to utils and use it in benchmarks 1) Add utils_ze_ prefix to all L0 helper functions. 2) Move level_zero_helpers to utils and rename it to utils_level_zero. 3) Use new utils_level_zero in benchmarks. Signed-off-by: Lukasz Dorau --- benchmark/CMakeLists.txt | 13 +++-- benchmark/ubench.c | 14 ++--- .../utils/utils_level_zero.cpp | 57 ++++++++++--------- src/utils/utils_level_zero.h | 52 +++++++++++++++++ test/CMakeLists.txt | 27 +++++---- test/providers/ipc_level_zero_prov_common.c | 6 +- test/providers/ipc_level_zero_prov_consumer.c | 16 +++--- test/providers/ipc_level_zero_prov_producer.c | 16 +++--- test/providers/level_zero_helpers.h | 45 --------------- test/providers/provider_level_zero.cpp | 25 ++++---- 10 files changed, 144 insertions(+), 127 deletions(-) rename test/providers/level_zero_helpers.cpp => src/utils/utils_level_zero.cpp (92%) create mode 100644 src/utils/utils_level_zero.h delete mode 100644 test/providers/level_zero_helpers.h diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt index cbb6468ab..aaf50c1c0 100644 --- a/benchmark/CMakeLists.txt +++ b/benchmark/CMakeLists.txt @@ -42,11 +42,8 @@ function(add_umf_benchmark) LIBS ${BENCH_LIBS}) target_include_directories( - ${BENCH_NAME} - PRIVATE ${UMF_CMAKE_SOURCE_DIR}/include - ${UMF_CMAKE_SOURCE_DIR}/src/utils - ${UMF_CMAKE_SOURCE_DIR}/test/common - ${UMF_CMAKE_SOURCE_DIR}/examples/common) + ${BENCH_NAME} PRIVATE ${UMF_CMAKE_SOURCE_DIR}/include + ${UMF_CMAKE_SOURCE_DIR}/src/utils) target_link_directories(${BENCH_NAME} PRIVATE ${ARG_LIBDIRS}) @@ -84,6 +81,9 @@ function(add_umf_benchmark) if(UMF_BUILD_LEVEL_ZERO_PROVIDER) target_compile_definitions(${BENCH_NAME} PRIVATE UMF_BUILD_LEVEL_ZERO_PROVIDER=1) + target_include_directories( + ${BENCH_NAME} PRIVATE ${UMF_CMAKE_SOURCE_DIR}/test/common + ${LEVEL_ZERO_INCLUDE_DIRS}) endif() if(UMF_BUILD_CUDA_PROVIDER) target_compile_definitions(${BENCH_NAME} @@ -108,6 +108,7 @@ if(LINUX) set(LIBS_OPTIONAL ${LIBS_OPTIONAL} m) endif() if(UMF_BUILD_GPU_TESTS AND UMF_BUILD_LEVEL_ZERO_PROVIDER) + set(SRCS_OPTIONAL ${SRCS_OPTIONAL} ../src/utils/utils_level_zero.cpp) set(LIBS_OPTIONAL ${LIBS_OPTIONAL} ze_loader) # TODO add CUDA endif() @@ -116,7 +117,7 @@ endif() add_umf_benchmark( NAME ubench - SRCS ubench.c + SRCS ubench.c ${SRCS_OPTIONAL} LIBS ${LIBS_OPTIONAL} LIBDIRS ${LIB_DIRS}) diff --git a/benchmark/ubench.c b/benchmark/ubench.c index 6e23d47c8..142112e83 100644 --- a/benchmark/ubench.c +++ b/benchmark/ubench.c @@ -32,7 +32,7 @@ #if (defined UMF_BUILD_LIBUMF_POOL_DISJOINT && \ defined UMF_BUILD_LEVEL_ZERO_PROVIDER && defined UMF_BUILD_GPU_TESTS) -#include "examples_level_zero.h" +#include "utils_level_zero.h" #endif // NOTE: with strict compilation flags, ubench compilation throws some @@ -450,28 +450,28 @@ int create_level_zero_params(ze_context_handle_t *context, uint32_t driver_idx = 0; ze_driver_handle_t driver = NULL; - int ret = init_level_zero(); + int ret = utils_ze_init_level_zero(); if (ret != 0) { fprintf(stderr, "Failed to init Level 0!\n"); return ret; } - ret = find_driver_with_gpu(&driver_idx, &driver); + ret = utils_ze_find_driver_with_gpu(&driver_idx, &driver); if (ret || driver == NULL) { fprintf(stderr, "Cannot find L0 driver with GPU device!\n"); return ret; } - ret = create_context(driver, context); + ret = utils_ze_create_context(driver, context); if (ret != 0) { fprintf(stderr, "Failed to create L0 context!\n"); return ret; } - ret = find_gpu_device(driver, device); + ret = utils_ze_find_gpu_device(driver, device); if (ret) { fprintf(stderr, "Cannot find GPU device!\n"); - destroy_context(*context); + utils_ze_destroy_context(*context); return ret; } @@ -628,7 +628,7 @@ UBENCH_EX(ipc, disjoint_pool_with_level_zero_provider) { umfLevelZeroMemoryProviderParamsDestroy(level_zero_params); err_destroy_context: - destroy_context(context); + utils_ze_destroy_context(context); } #endif /* (defined UMF_BUILD_LIBUMF_POOL_DISJOINT && defined UMF_BUILD_LEVEL_ZERO_PROVIDER && defined UMF_BUILD_GPU_TESTS) */ diff --git a/test/providers/level_zero_helpers.cpp b/src/utils/utils_level_zero.cpp similarity index 92% rename from test/providers/level_zero_helpers.cpp rename to src/utils/utils_level_zero.cpp index 088e1b814..833047dd7 100644 --- a/test/providers/level_zero_helpers.cpp +++ b/src/utils/utils_level_zero.cpp @@ -5,7 +5,7 @@ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ -#include "level_zero_helpers.h" +#include "utils_level_zero.h" #include #include @@ -297,7 +297,7 @@ int InitLevelZeroOps() { } #endif // USE_DLOPEN -static int init_level_zero_lib(void) { +static int utils_ze_init_level_zero_lib(void) { ze_init_flag_t flags = ZE_INIT_FLAG_GPU_ONLY; ze_result_t result = libze_ops.zeInit(flags); if (result != ZE_RESULT_SUCCESS) { @@ -309,29 +309,30 @@ static int init_level_zero_lib(void) { static UTIL_ONCE_FLAG level_zero_init_flag = UTIL_ONCE_FLAG_INIT; static int InitResult; -static void init_level_zero_once(void) { +static void utils_ze_init_level_zero_once(void) { InitResult = InitLevelZeroOps(); if (InitResult != 0) { return; } - InitResult = init_level_zero_lib(); + InitResult = utils_ze_init_level_zero_lib(); } -static int init_level_zero(void) { - utils_init_once(&level_zero_init_flag, init_level_zero_once); +int utils_ze_init_level_zero(void) { + utils_init_once(&level_zero_init_flag, utils_ze_init_level_zero_once); return InitResult; } -int get_drivers(uint32_t *drivers_num_, ze_driver_handle_t **drivers_) { +int utils_ze_get_drivers(uint32_t *drivers_num_, + ze_driver_handle_t **drivers_) { int ret = 0; ze_result_t ze_result; ze_driver_handle_t *drivers = NULL; uint32_t drivers_num = 0; - ret = init_level_zero(); + ret = utils_ze_init_level_zero(); if (ret != 0) { - fprintf(stderr, "init_level_zero() failed!\n"); + fprintf(stderr, "utils_ze_init_level_zero() failed!\n"); goto init_fail; } @@ -375,16 +376,16 @@ int get_drivers(uint32_t *drivers_num_, ze_driver_handle_t **drivers_) { return ret; } -int get_devices(ze_driver_handle_t driver, uint32_t *devices_num_, - ze_device_handle_t **devices_) { +int utils_ze_get_devices(ze_driver_handle_t driver, uint32_t *devices_num_, + ze_device_handle_t **devices_) { ze_result_t ze_result; int ret = 0; uint32_t devices_num = 0; ze_device_handle_t *devices = NULL; - ret = init_level_zero(); + ret = utils_ze_init_level_zero(); if (ret != 0) { - fprintf(stderr, "init_level_zero() failed!\n"); + fprintf(stderr, "utils_ze_init_level_zero() failed!\n"); goto init_fail; } @@ -427,7 +428,8 @@ int get_devices(ze_driver_handle_t driver, uint32_t *devices_num_, return ret; } -int find_driver_with_gpu(uint32_t *driver_idx, ze_driver_handle_t *driver_) { +int utils_ze_find_driver_with_gpu(uint32_t *driver_idx, + ze_driver_handle_t *driver_) { int ret = 0; ze_result_t ze_result; uint32_t drivers_num = 0; @@ -435,7 +437,7 @@ int find_driver_with_gpu(uint32_t *driver_idx, ze_driver_handle_t *driver_) { ze_driver_handle_t *drivers = NULL; ze_driver_handle_t driver_with_gpus = NULL; - ret = get_drivers(&drivers_num, &drivers); + ret = utils_ze_get_drivers(&drivers_num, &drivers); if (ret) { goto fn_fail; } @@ -445,7 +447,7 @@ int find_driver_with_gpu(uint32_t *driver_idx, ze_driver_handle_t *driver_) { uint32_t devices_num = 0; ze_driver_handle_t driver = drivers[i]; - ret = get_devices(driver, &devices_num, &devices); + ret = utils_ze_get_devices(driver, &devices_num, &devices); if (ret) { goto fn_fail; } @@ -494,13 +496,14 @@ int find_driver_with_gpu(uint32_t *driver_idx, ze_driver_handle_t *driver_) { return ret; } -int find_gpu_device(ze_driver_handle_t driver, ze_device_handle_t *device_) { +int utils_ze_find_gpu_device(ze_driver_handle_t driver, + ze_device_handle_t *device_) { int ret = -1; uint32_t devices_num = 0; ze_device_handle_t *devices = NULL; ze_device_handle_t device; - ret = get_devices(driver, &devices_num, &devices); + ret = utils_ze_get_devices(driver, &devices_num, &devices); if (ret) { return ret; } @@ -532,9 +535,9 @@ int find_gpu_device(ze_driver_handle_t driver, ze_device_handle_t *device_) { return ret; } -int level_zero_fill(ze_context_handle_t context, ze_device_handle_t device, - void *ptr, size_t size, const void *pattern, - size_t pattern_size) { +int utils_ze_level_zero_fill(ze_context_handle_t context, + ze_device_handle_t device, void *ptr, size_t size, + const void *pattern, size_t pattern_size) { int ret = 0; ze_command_queue_desc_t commandQueueDesc = { @@ -618,8 +621,9 @@ int level_zero_fill(ze_context_handle_t context, ze_device_handle_t device, return ret; } -int level_zero_copy(ze_context_handle_t context, ze_device_handle_t device, - void *dst_ptr, const void *src_ptr, size_t size) { +int utils_ze_level_zero_copy(ze_context_handle_t context, + ze_device_handle_t device, void *dst_ptr, + const void *src_ptr, size_t size) { int ret = 0; ze_command_queue_desc_t commandQueueDesc = { ZE_STRUCTURE_TYPE_COMMAND_QUEUE_DESC, @@ -701,7 +705,8 @@ int level_zero_copy(ze_context_handle_t context, ze_device_handle_t device, return ret; } -int create_context(ze_driver_handle_t driver, ze_context_handle_t *context) { +int utils_ze_create_context(ze_driver_handle_t driver, + ze_context_handle_t *context) { ze_result_t ze_result; ze_context_desc_t ctxtDesc; ctxtDesc.stype = ZE_STRUCTURE_TYPE_CONTEXT_DESC; @@ -717,7 +722,7 @@ int create_context(ze_driver_handle_t driver, ze_context_handle_t *context) { return 0; } -int destroy_context(ze_context_handle_t context) { +int utils_ze_destroy_context(ze_context_handle_t context) { ze_result_t ze_result; ze_result = libze_ops.zeContextDestroy(context); if (ze_result != ZE_RESULT_SUCCESS) { @@ -728,7 +733,7 @@ int destroy_context(ze_context_handle_t context) { return 0; } -ze_memory_type_t get_mem_type(ze_context_handle_t context, void *ptr) { +ze_memory_type_t utils_ze_get_mem_type(ze_context_handle_t context, void *ptr) { ze_device_handle_t device = NULL; ze_memory_allocation_properties_t alloc_props; alloc_props.stype = ZE_STRUCTURE_TYPE_MEMORY_ALLOCATION_PROPERTIES; diff --git a/src/utils/utils_level_zero.h b/src/utils/utils_level_zero.h new file mode 100644 index 000000000..b29a4dc43 --- /dev/null +++ b/src/utils/utils_level_zero.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 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_UTILS_LEVEL_ZERO_H +#define UMF_UTILS_LEVEL_ZERO_H + +#include + +#include "ze_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int utils_ze_init_level_zero(void); +int utils_ze_init_level_zero(void); + +int utils_ze_get_drivers(uint32_t *drivers_num_, ze_driver_handle_t **drivers_); + +int utils_ze_get_devices(ze_driver_handle_t driver, uint32_t *devices_num_, + ze_device_handle_t **devices_); + +int utils_ze_find_driver_with_gpu(uint32_t *driver_idx, + ze_driver_handle_t *driver_); + +int utils_ze_find_gpu_device(ze_driver_handle_t driver, + ze_device_handle_t *device_); + +int utils_ze_level_zero_fill(ze_context_handle_t context, + ze_device_handle_t device, void *ptr, size_t size, + const void *pattern, size_t pattern_size); + +int utils_ze_level_zero_copy(ze_context_handle_t context, + ze_device_handle_t device, void *dst_ptr, + const void *src_ptr, size_t size); + +int utils_ze_create_context(ze_driver_handle_t driver, + ze_context_handle_t *context); + +int utils_ze_destroy_context(ze_context_handle_t context); + +ze_memory_type_t utils_ze_get_mem_type(ze_context_handle_t context, void *ptr); + +#ifdef __cplusplus +} +#endif + +#endif // UMF_UTILS_LEVEL_ZERO_H diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6ce94654a..c3a191b1d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -22,6 +22,7 @@ FetchContent_MakeAvailable(googletest) enable_testing() set(UMF_TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +set(UMF_UTILS_DIR ${UMF_CMAKE_SOURCE_DIR}/src/utils) function(build_umf_test) # Parameters: * NAME - a name of the test * SRCS - source files * LIBS - @@ -136,20 +137,22 @@ if(UMF_BUILD_SHARED_LIBRARY) set(UMF_UTILS_FOR_TEST umf_utils) if(LINUX OR MACOSX) set(UMF_UTILS_SOURCES - ../src/utils/utils_common.c ../src/utils/utils_posix_common.c - ../src/utils/utils_posix_concurrency.c) + ${UMF_UTILS_DIR}/utils_common.c + ${UMF_UTILS_DIR}/utils_posix_common.c + ${UMF_UTILS_DIR}/utils_posix_concurrency.c) if(LINUX) set(UMF_UTILS_SOURCES ${UMF_UTILS_SOURCES} - ../src/utils/utils_linux_common.c) + ${UMF_UTILS_DIR}/utils_linux_common.c) set(UMF_LOGGER_LIBS rt) # librt for shm_open() elseif(MACOSX) set(UMF_UTILS_SOURCES ${UMF_UTILS_SOURCES} - ../src/utils/utils_macosx_common.c) + ${UMF_UTILS_DIR}/utils_macosx_common.c) endif() elseif(WINDOWS) set(UMF_UTILS_SOURCES - ../src/utils/utils_common.c ../src/utils/utils_windows_common.c - ../src/utils/utils_windows_concurrency.c) + ${UMF_UTILS_DIR}/utils_common.c + ${UMF_UTILS_DIR}/utils_windows_common.c + ${UMF_UTILS_DIR}/utils_windows_concurrency.c) endif() endif() @@ -358,16 +361,16 @@ if(UMF_BUILD_GPU_TESTS AND UMF_BUILD_LEVEL_ZERO_PROVIDER) # dlopen) add_umf_test( NAME provider_level_zero - SRCS providers/provider_level_zero.cpp providers/level_zero_helpers.cpp - ${BA_SOURCES_FOR_TEST} + SRCS providers/provider_level_zero.cpp + ${UMF_UTILS_DIR}/utils_level_zero.cpp ${BA_SOURCES_FOR_TEST} LIBS ${UMF_UTILS_FOR_TEST} ze_loader) target_include_directories(umf_test-provider_level_zero PRIVATE ${LEVEL_ZERO_INCLUDE_DIRS}) add_umf_test( NAME provider_level_zero_dlopen - SRCS providers/provider_level_zero.cpp providers/level_zero_helpers.cpp - ${BA_SOURCES_FOR_TEST} + SRCS providers/provider_level_zero.cpp + ${UMF_UTILS_DIR}/utils_level_zero.cpp ${BA_SOURCES_FOR_TEST} LIBS ${UMF_UTILS_FOR_TEST}) target_compile_definitions(umf_test-provider_level_zero_dlopen PUBLIC USE_DLOPEN=1) @@ -580,7 +583,7 @@ if(LINUX) providers/ipc_level_zero_prov_consumer.c common/ipc_common.c providers/ipc_level_zero_prov_common.c - providers/level_zero_helpers.cpp + ${UMF_UTILS_DIR}/utils_level_zero.cpp LIBS ze_loader disjoint_pool @@ -592,7 +595,7 @@ if(LINUX) providers/ipc_level_zero_prov_producer.c common/ipc_common.c providers/ipc_level_zero_prov_common.c - providers/level_zero_helpers.cpp + ${UMF_UTILS_DIR}/utils_level_zero.cpp LIBS ze_loader disjoint_pool diff --git a/test/providers/ipc_level_zero_prov_common.c b/test/providers/ipc_level_zero_prov_common.c index 8b951cfc8..485cb41b5 100644 --- a/test/providers/ipc_level_zero_prov_common.c +++ b/test/providers/ipc_level_zero_prov_common.c @@ -6,7 +6,7 @@ */ #include "ipc_level_zero_prov_common.h" -#include "level_zero_helpers.h" +#include "utils_level_zero.h" #include @@ -14,8 +14,8 @@ void memcopy(void *dst, const void *src, size_t size, void *context) { level_zero_copy_ctx_t *l0_params = (level_zero_copy_ctx_t *)context; - int ret = - level_zero_copy(l0_params->context, l0_params->device, dst, src, size); + int ret = utils_ze_level_zero_copy(l0_params->context, l0_params->device, + dst, src, size); if (ret != 0) { fprintf(stderr, "level_zero_copy failed with error %d\n", ret); } diff --git a/test/providers/ipc_level_zero_prov_consumer.c b/test/providers/ipc_level_zero_prov_consumer.c index 7fcb031cb..8ec0648e4 100644 --- a/test/providers/ipc_level_zero_prov_consumer.c +++ b/test/providers/ipc_level_zero_prov_consumer.c @@ -13,7 +13,7 @@ #include "ipc_common.h" #include "ipc_level_zero_prov_common.h" -#include "level_zero_helpers.h" +#include "utils_level_zero.h" int main(int argc, char *argv[]) { if (argc < 2) { @@ -27,21 +27,21 @@ int main(int argc, char *argv[]) { ze_device_handle_t hDevice = NULL; ze_context_handle_t hContext = NULL; - int ret = find_driver_with_gpu(&driver_idx, &hDriver); + int ret = utils_ze_find_driver_with_gpu(&driver_idx, &hDriver); if (ret != 0 || hDriver == NULL) { - fprintf(stderr, "find_driver_with_gpu() failed!\n"); + fprintf(stderr, "utils_ze_find_driver_with_gpu() failed!\n"); return -1; } - ret = find_gpu_device(hDriver, &hDevice); + ret = utils_ze_find_gpu_device(hDriver, &hDevice); if (ret != 0 || hDevice == NULL) { - fprintf(stderr, "find_gpu_device() failed!\n"); + fprintf(stderr, "utils_ze_find_gpu_device() failed!\n"); return -1; } - ret = create_context(hDriver, &hContext); + ret = utils_ze_create_context(hDriver, &hContext); if (ret != 0) { - fprintf(stderr, "create_context() failed!\n"); + fprintf(stderr, "utils_ze_create_context() failed!\n"); return -1; } @@ -103,7 +103,7 @@ int main(int argc, char *argv[]) { umfLevelZeroMemoryProviderParamsDestroy(l0_params); destroy_context: - destroy_context(hContext); + utils_ze_destroy_context(hContext); return ret; } diff --git a/test/providers/ipc_level_zero_prov_producer.c b/test/providers/ipc_level_zero_prov_producer.c index d9c672dee..2a8fedc37 100644 --- a/test/providers/ipc_level_zero_prov_producer.c +++ b/test/providers/ipc_level_zero_prov_producer.c @@ -13,7 +13,7 @@ #include "ipc_common.h" #include "ipc_level_zero_prov_common.h" -#include "level_zero_helpers.h" +#include "utils_level_zero.h" int main(int argc, char *argv[]) { if (argc < 2) { @@ -27,21 +27,21 @@ int main(int argc, char *argv[]) { ze_device_handle_t hDevice = NULL; ze_context_handle_t hContext = NULL; - int ret = find_driver_with_gpu(&driver_idx, &hDriver); + int ret = utils_ze_find_driver_with_gpu(&driver_idx, &hDriver); if (ret != 0 || hDriver == NULL) { - fprintf(stderr, "find_driver_with_gpu() failed!\n"); + fprintf(stderr, "utils_ze_find_driver_with_gpu() failed!\n"); return -1; } - ret = find_gpu_device(hDriver, &hDevice); + ret = utils_ze_find_gpu_device(hDriver, &hDevice); if (ret != 0 || hDevice == NULL) { - fprintf(stderr, "find_gpu_device() failed!\n"); + fprintf(stderr, "utils_ze_find_gpu_device() failed!\n"); return -1; } - ret = create_context(hDriver, &hContext); + ret = utils_ze_create_context(hDriver, &hContext); if (ret != 0) { - fprintf(stderr, "create_context() failed!\n"); + fprintf(stderr, "utils_ze_create_context() failed!\n"); return -1; } @@ -103,7 +103,7 @@ int main(int argc, char *argv[]) { umfLevelZeroMemoryProviderParamsDestroy(l0_params); destroy_context: - destroy_context(hContext); + utils_ze_destroy_context(hContext); return ret; } diff --git a/test/providers/level_zero_helpers.h b/test/providers/level_zero_helpers.h deleted file mode 100644 index aa76f8f55..000000000 --- a/test/providers/level_zero_helpers.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 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_TEST_LEVEL_ZERO_HELPERS_H -#define UMF_TEST_LEVEL_ZERO_HELPERS_H - -#include - -#include "ze_api.h" - -#ifdef __cplusplus -extern "C" { -#endif - -int get_drivers(uint32_t *drivers_num_, ze_driver_handle_t **drivers_); - -int get_devices(ze_driver_handle_t driver, uint32_t *devices_num_, - ze_device_handle_t **devices_); - -int find_driver_with_gpu(uint32_t *driver_idx, ze_driver_handle_t *driver_); - -int find_gpu_device(ze_driver_handle_t driver, ze_device_handle_t *device_); - -int level_zero_fill(ze_context_handle_t context, ze_device_handle_t device, - void *ptr, size_t size, const void *pattern, - size_t pattern_size); - -int level_zero_copy(ze_context_handle_t context, ze_device_handle_t device, - void *dst_ptr, const void *src_ptr, size_t size); - -int create_context(ze_driver_handle_t driver, ze_context_handle_t *context); - -int destroy_context(ze_context_handle_t context); - -ze_memory_type_t get_mem_type(ze_context_handle_t context, void *ptr); - -#ifdef __cplusplus -} -#endif - -#endif // UMF_TEST_LEVEL_ZERO_HELPERS_H diff --git a/test/providers/provider_level_zero.cpp b/test/providers/provider_level_zero.cpp index 06742d102..d0584777b 100644 --- a/test/providers/provider_level_zero.cpp +++ b/test/providers/provider_level_zero.cpp @@ -12,8 +12,8 @@ #include #include "ipcFixtures.hpp" -#include "level_zero_helpers.h" #include "pool.hpp" +#include "utils_level_zero.h" #include "utils_load_library.h" using umf_test::test; @@ -25,7 +25,7 @@ class LevelZeroTestHelper { ~LevelZeroTestHelper() { if (hContext_) { - destroy_context(hContext_); + utils_ze_destroy_context(hContext_); } } @@ -42,21 +42,21 @@ class LevelZeroTestHelper { LevelZeroTestHelper::LevelZeroTestHelper() { uint32_t driver_idx = 0; - int ret = find_driver_with_gpu(&driver_idx, &hDriver_); + int ret = utils_ze_find_driver_with_gpu(&driver_idx, &hDriver_); if (ret != 0 || hDriver_ == NULL) { - fprintf(stderr, "find_driver_with_gpu() failed!\n"); + fprintf(stderr, "utils_ze_find_driver_with_gpu() failed!\n"); return; } - ret = find_gpu_device(hDriver_, &hDevice_); + ret = utils_ze_find_gpu_device(hDriver_, &hDevice_); if (ret != 0 || hDevice_ == NULL) { - fprintf(stderr, "find_gpu_device() failed!\n"); + fprintf(stderr, "utils_ze_find_gpu_device() failed!\n"); return; } - ret = create_context(hDriver_, &hContext_); + ret = utils_ze_create_context(hDriver_, &hContext_); if (ret != 0) { - fprintf(stderr, "create_context() failed!\n"); + fprintf(stderr, "utils_ze_create_context() failed!\n"); return; } } @@ -218,8 +218,8 @@ class LevelZeroMemoryAccessor : public MemoryAccessor { size_t pattern_size) { ASSERT_NE(ptr, nullptr); - int ret = level_zero_fill(hContext_, hDevice_, ptr, size, pattern, - pattern_size); + int ret = utils_ze_level_zero_fill(hContext_, hDevice_, ptr, size, + pattern, pattern_size); ASSERT_EQ(ret, 0); } @@ -227,7 +227,8 @@ class LevelZeroMemoryAccessor : public MemoryAccessor { ASSERT_NE(dst_ptr, nullptr); ASSERT_NE(src_ptr, nullptr); - int ret = level_zero_copy(hContext_, hDevice_, dst_ptr, src_ptr, size); + int ret = utils_ze_level_zero_copy(hContext_, hDevice_, dst_ptr, + src_ptr, size); ASSERT_EQ(ret, 0); } @@ -301,7 +302,7 @@ TEST_P(umfLevelZeroProviderTest, basic) { // use the allocated memory - fill it with a 0xAB pattern memAccessor->fill(ptr, size, &pattern, sizeof(pattern)); - ze_memory_type_t zeMemoryTypeActual = get_mem_type(hContext, ptr); + ze_memory_type_t zeMemoryTypeActual = utils_ze_get_mem_type(hContext, ptr); ASSERT_EQ(zeMemoryTypeActual, zeMemoryTypeExpected); // check if the pattern was successfully applied From 4e013582026c9e66b2bfedd0220e509963e9a0dc Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Fri, 29 Nov 2024 11:48:07 +0100 Subject: [PATCH 343/352] Move implementation from examples_level_zero.h to examples_level_zero.c Signed-off-by: Lukasz Dorau --- examples/CMakeLists.txt | 3 +- examples/common/examples_level_zero.c | 406 ++++++++++++++++++ examples/common/examples_level_zero.h | 401 +---------------- examples/ipc_level_zero/CMakeLists.txt | 3 +- examples/ipc_level_zero/ipc_level_zero.c | 1 + .../level_zero_shared_memory/CMakeLists.txt | 3 +- .../level_zero_shared_memory.c | 2 + 7 files changed, 425 insertions(+), 394 deletions(-) create mode 100644 examples/common/examples_level_zero.c diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 201231676..8be80977e 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -49,6 +49,7 @@ if(UMF_BUILD_GPU_EXAMPLES add_umf_executable( NAME ${EXAMPLE_NAME} SRCS level_zero_shared_memory/level_zero_shared_memory.c + common/examples_level_zero.c LIBS disjoint_pool ze_loader umf) target_include_directories( @@ -126,7 +127,7 @@ if(UMF_BUILD_GPU_EXAMPLES add_umf_executable( NAME ${EXAMPLE_NAME} - SRCS ipc_level_zero/ipc_level_zero.c + SRCS ipc_level_zero/ipc_level_zero.c common/examples_level_zero.c LIBS disjoint_pool ze_loader umf) target_include_directories( diff --git a/examples/common/examples_level_zero.c b/examples/common/examples_level_zero.c new file mode 100644 index 000000000..87bc4ab94 --- /dev/null +++ b/examples/common/examples_level_zero.c @@ -0,0 +1,406 @@ +/* + * + * Copyright (C) 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 "examples_level_zero.h" + +int init_level_zero(void) { + ze_init_flag_t flags = ZE_INIT_FLAG_GPU_ONLY; + ze_result_t result = zeInit(flags); + if (result != ZE_RESULT_SUCCESS) { + return -1; + } + return 0; +} + +static inline int get_drivers(uint32_t *drivers_num_, + ze_driver_handle_t **drivers_) { + int ret = 0; + ze_result_t ze_result; + ze_driver_handle_t *drivers = NULL; + uint32_t drivers_num = 0; + + ze_result = zeDriverGet(&drivers_num, NULL); + if (ze_result != ZE_RESULT_SUCCESS) { + fprintf(stderr, "zeDriverGet() failed!\n"); + ret = -1; + goto fn_fail; + } + if (drivers_num == 0) { + goto fn_exit; + } + + drivers = malloc(drivers_num * sizeof(ze_driver_handle_t)); + if (!drivers) { + ret = -1; + goto fn_fail; + } + + ze_result = zeDriverGet(&drivers_num, drivers); + if (ze_result != ZE_RESULT_SUCCESS) { + fprintf(stderr, "zeDriverGet() failed!\n"); + ret = -1; + goto fn_fail; + } + +fn_exit: + *drivers_num_ = drivers_num; + *drivers_ = drivers; + return ret; + +fn_fail: + *drivers_num_ = 0; + if (drivers) { + free(drivers); + *drivers_ = NULL; + } + return ret; +} + +static inline int get_devices(ze_driver_handle_t driver, uint32_t *devices_num_, + ze_device_handle_t **devices_) { + ze_result_t ze_result; + int ret = 0; + uint32_t devices_num = 0; + ze_device_handle_t *devices = NULL; + + ze_result = zeDeviceGet(driver, &devices_num, NULL); + if (ze_result != ZE_RESULT_SUCCESS) { + fprintf(stderr, "zeDeviceGet() failed!\n"); + ret = -1; + goto fn_fail; + } + if (devices_num == 0) { + goto fn_exit; + } + + devices = malloc(devices_num * sizeof(ze_device_handle_t)); + if (!devices) { + ret = -1; + goto fn_fail; + } + + ze_result = zeDeviceGet(driver, &devices_num, devices); + if (ze_result != ZE_RESULT_SUCCESS) { + fprintf(stderr, "zeDeviceGet() failed!\n"); + ret = -1; + goto fn_fail; + } + +fn_exit: + *devices_num_ = devices_num; + *devices_ = devices; + return ret; + +fn_fail: + devices_num = 0; + if (devices) { + free(devices); + devices = NULL; + } + return ret; +} + +int find_driver_with_gpu(uint32_t *driver_idx, ze_driver_handle_t *driver_) { + int ret = 0; + ze_result_t ze_result; + uint32_t drivers_num = 0; + ze_device_handle_t *devices = NULL; + ze_driver_handle_t *drivers = NULL; + ze_driver_handle_t driver_with_gpus = NULL; + + ret = get_drivers(&drivers_num, &drivers); + if (ret) { + goto fn_fail; + } + + /* Find a driver with GPU */ + for (uint32_t i = 0; i < drivers_num; ++i) { + uint32_t devices_num = 0; + ze_driver_handle_t driver = drivers[i]; + + ret = get_devices(driver, &devices_num, &devices); + if (ret) { + goto fn_fail; + } + + for (uint32_t d = 0; d < devices_num; ++d) { + ze_device_handle_t device = devices[d]; + ze_device_properties_t device_properties = { + .stype = ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES, .pNext = NULL}; + + ze_result = zeDeviceGetProperties(device, &device_properties); + if (ze_result != ZE_RESULT_SUCCESS) { + fprintf(stderr, "zeDeviceGetProperties() failed!\n"); + ret = -1; + goto fn_fail; + } + + if (device_properties.type == ZE_DEVICE_TYPE_GPU) { + driver_with_gpus = driver; + *driver_idx = i; + break; + } + } + + if (devices) { + free(devices); + devices = NULL; + } + + if (driver_with_gpus != NULL) { + goto fn_exit; + } + } + +fn_fail: + if (devices) { + free(devices); + } + +fn_exit: + *driver_ = driver_with_gpus; + if (drivers) { + free(drivers); + } + return ret; +} + +int find_gpu_device(ze_driver_handle_t driver, ze_device_handle_t *device_) { + int ret = -1; + uint32_t devices_num = 0; + ze_device_handle_t *devices = NULL; + ze_device_handle_t device; + + ret = get_devices(driver, &devices_num, &devices); + if (ret) { + return ret; + } + + for (uint32_t d = 0; d < devices_num; ++d) { + device = devices[d]; + ze_device_properties_t device_properties = { + .stype = ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES, .pNext = NULL}; + + ze_result_t ze_result = + zeDeviceGetProperties(device, &device_properties); + if (ze_result != ZE_RESULT_SUCCESS) { + fprintf(stderr, "zeDeviceGetProperties() failed!\n"); + ret = -1; + break; + } + + if (device_properties.type == ZE_DEVICE_TYPE_GPU) { + *device_ = device; + ret = 0; + break; + } + } + + if (devices) { + free(devices); + } + return ret; +} + +int level_zero_fill(ze_context_handle_t context, ze_device_handle_t device, + void *ptr, size_t size, const void *pattern, + size_t pattern_size) { + int ret = 0; + + ze_command_queue_desc_t commandQueueDesc = { + ZE_STRUCTURE_TYPE_COMMAND_QUEUE_DESC, + NULL, + 0, + 0, + 0, + ZE_COMMAND_QUEUE_MODE_DEFAULT, + ZE_COMMAND_QUEUE_PRIORITY_NORMAL}; + + ze_command_list_desc_t commandListDesc = { + ZE_STRUCTURE_TYPE_COMMAND_LIST_DESC, 0, 0, + ZE_COMMAND_LIST_FLAG_RELAXED_ORDERING}; + + ze_command_queue_handle_t hCommandQueue; + ze_result_t ze_result = zeCommandQueueCreate( + context, device, &commandQueueDesc, &hCommandQueue); + if (ze_result != ZE_RESULT_SUCCESS) { + fprintf(stderr, "zeCommandQueueCreate() failed!\n"); + return -1; + } + + ze_command_list_handle_t hCommandList; + ze_result = + zeCommandListCreate(context, device, &commandListDesc, &hCommandList); + if (ze_result != ZE_RESULT_SUCCESS) { + fprintf(stderr, "zeCommandListCreate() failed!\n"); + ret = -1; + goto err_queue_destroy; + } + + // fill memory with a pattern + ze_result = zeCommandListAppendMemoryFill( + hCommandList, ptr, pattern, pattern_size, size, NULL, 0, NULL); + if (ze_result != ZE_RESULT_SUCCESS) { + fprintf(stderr, "zeCommandListAppendMemoryFill() failed!\n"); + ret = -1; + goto err_list_destroy; + } + + // close and execute the command list + ze_result = zeCommandListClose(hCommandList); + if (ze_result != ZE_RESULT_SUCCESS) { + fprintf(stderr, "zeCommandListClose() failed!\n"); + ret = -1; + goto err_list_destroy; + } + + ze_result = zeCommandQueueExecuteCommandLists(hCommandQueue, 1, + &hCommandList, NULL); + if (ze_result != ZE_RESULT_SUCCESS) { + fprintf(stderr, "zeCommandQueueExecuteCommandLists() failed!\n"); + ret = -1; + goto err_list_destroy; + } + + // sync + ze_result = zeCommandQueueSynchronize(hCommandQueue, UINT64_MAX); + if (ze_result != ZE_RESULT_SUCCESS) { + fprintf(stderr, "zeCommandQueueSynchronize() failed!\n"); + ret = -1; + goto err_list_destroy; + } + + // cleanup +err_list_destroy: + ze_result = zeCommandListDestroy(hCommandList); + if (ze_result != ZE_RESULT_SUCCESS) { + fprintf(stderr, "zeCommandListDestroy() failed!\n"); + ret = -1; + } + +err_queue_destroy: + ze_result = zeCommandQueueDestroy(hCommandQueue); + if (ze_result != ZE_RESULT_SUCCESS) { + fprintf(stderr, "zeCommandQueueDestroy() failed!\n"); + ret = -1; + } + + return ret; +} + +int level_zero_copy(ze_context_handle_t context, ze_device_handle_t device, + void *dst_ptr, void *src_ptr, size_t size) { + int ret = 0; + ze_command_queue_desc_t commandQueueDesc = { + ZE_STRUCTURE_TYPE_COMMAND_QUEUE_DESC, + NULL, + 0, + 0, + 0, + ZE_COMMAND_QUEUE_MODE_DEFAULT, + ZE_COMMAND_QUEUE_PRIORITY_NORMAL}; + + ze_command_list_desc_t commandListDesc = { + ZE_STRUCTURE_TYPE_COMMAND_LIST_DESC, 0, 0, + ZE_COMMAND_LIST_FLAG_RELAXED_ORDERING}; + + ze_command_queue_handle_t hCommandQueue; + ze_result_t ze_result = zeCommandQueueCreate( + context, device, &commandQueueDesc, &hCommandQueue); + if (ze_result != ZE_RESULT_SUCCESS) { + fprintf(stderr, "zeCommandQueueCreate() failed!\n"); + return -1; + } + + ze_command_list_handle_t hCommandList; + ze_result = + zeCommandListCreate(context, device, &commandListDesc, &hCommandList); + if (ze_result != ZE_RESULT_SUCCESS) { + fprintf(stderr, "zeCommandListCreate() failed!\n"); + ret = -1; + goto err_queue_destroy; + } + + // copy from device memory to host memory + ze_result = zeCommandListAppendMemoryCopy(hCommandList, dst_ptr, src_ptr, + size, NULL, 0, NULL); + if (ze_result != ZE_RESULT_SUCCESS) { + fprintf(stderr, "zeCommandListAppendMemoryCopy() failed!\n"); + ret = -1; + goto err_list_destroy; + } + + // close and execute the command list + ze_result = zeCommandListClose(hCommandList); + if (ze_result != ZE_RESULT_SUCCESS) { + fprintf(stderr, "zeCommandListClose() failed!\n"); + ret = -1; + goto err_list_destroy; + } + + ze_result = zeCommandQueueExecuteCommandLists(hCommandQueue, 1, + &hCommandList, NULL); + if (ze_result != ZE_RESULT_SUCCESS) { + fprintf(stderr, "zeCommandQueueExecuteCommandLists() failed!\n"); + ret = -1; + goto err_list_destroy; + } + + ze_result = zeCommandQueueSynchronize(hCommandQueue, UINT64_MAX); + if (ze_result != ZE_RESULT_SUCCESS) { + fprintf(stderr, "zeCommandQueueSynchronize() failed!\n"); + ret = -1; + goto err_list_destroy; + } + + // cleanup +err_list_destroy: + ze_result = zeCommandListDestroy(hCommandList); + if (ze_result != ZE_RESULT_SUCCESS) { + fprintf(stderr, "zeCommandListDestroy() failed!\n"); + ret = -1; + } + +err_queue_destroy: + ze_result = zeCommandQueueDestroy(hCommandQueue); + if (ze_result != ZE_RESULT_SUCCESS) { + fprintf(stderr, "zeCommandQueueDestroy() failed!\n"); + ret = -1; + } + + return ret; +} + +int create_context(ze_driver_handle_t driver, ze_context_handle_t *context) { + ze_result_t ze_result; + ze_context_desc_t ctxtDesc = { + .stype = ZE_STRUCTURE_TYPE_CONTEXT_DESC, .pNext = NULL, .flags = 0}; + + ze_result = zeContextCreate(driver, &ctxtDesc, context); + if (ze_result != ZE_RESULT_SUCCESS) { + fprintf(stderr, "zeContextCreate() failed!\n"); + return -1; + } + + return 0; +} + +int destroy_context(ze_context_handle_t context) { + ze_result_t ze_result; + ze_result = zeContextDestroy(context); + if (ze_result != ZE_RESULT_SUCCESS) { + fprintf(stderr, "zeContextDestroy() failed!\n"); + return -1; + } + + return 0; +} diff --git a/examples/common/examples_level_zero.h b/examples/common/examples_level_zero.h index 46f892278..2d8e92ff2 100644 --- a/examples/common/examples_level_zero.h +++ b/examples/common/examples_level_zero.h @@ -7,11 +7,8 @@ * */ -#ifndef UMF_EXAMPLE_UTILS_LEVEL_ZERO_H -#define UMF_EXAMPLE_UTILS_LEVEL_ZERO_H - -#include -#include +#ifndef UMF_EXAMPLES_LEVEL_ZERO_H +#define UMF_EXAMPLES_LEVEL_ZERO_H // To use the Level Zero API, the Level Zero SDK has to be installed // on the system @@ -21,399 +18,21 @@ #include #endif -static int init_level_zero(void) { - ze_init_flag_t flags = ZE_INIT_FLAG_GPU_ONLY; - ze_result_t result = zeInit(flags); - if (result != ZE_RESULT_SUCCESS) { - return -1; - } - return 0; -} - -static inline int get_drivers(uint32_t *drivers_num_, - ze_driver_handle_t **drivers_) { - int ret = 0; - ze_result_t ze_result; - ze_driver_handle_t *drivers = NULL; - uint32_t drivers_num = 0; - - ze_result = zeDriverGet(&drivers_num, NULL); - if (ze_result != ZE_RESULT_SUCCESS) { - fprintf(stderr, "zeDriverGet() failed!\n"); - ret = -1; - goto fn_fail; - } - if (drivers_num == 0) { - goto fn_exit; - } - - drivers = malloc(drivers_num * sizeof(ze_driver_handle_t)); - if (!drivers) { - ret = -1; - goto fn_fail; - } - - ze_result = zeDriverGet(&drivers_num, drivers); - if (ze_result != ZE_RESULT_SUCCESS) { - fprintf(stderr, "zeDriverGet() failed!\n"); - ret = -1; - goto fn_fail; - } - -fn_exit: - *drivers_num_ = drivers_num; - *drivers_ = drivers; - return ret; - -fn_fail: - *drivers_num_ = 0; - if (drivers) { - free(drivers); - *drivers_ = NULL; - } - return ret; -} - -static inline int get_devices(ze_driver_handle_t driver, uint32_t *devices_num_, - ze_device_handle_t **devices_) { - ze_result_t ze_result; - int ret = 0; - uint32_t devices_num = 0; - ze_device_handle_t *devices = NULL; - - ze_result = zeDeviceGet(driver, &devices_num, NULL); - if (ze_result != ZE_RESULT_SUCCESS) { - fprintf(stderr, "zeDeviceGet() failed!\n"); - ret = -1; - goto fn_fail; - } - if (devices_num == 0) { - goto fn_exit; - } - - devices = malloc(devices_num * sizeof(ze_device_handle_t)); - if (!devices) { - ret = -1; - goto fn_fail; - } - - ze_result = zeDeviceGet(driver, &devices_num, devices); - if (ze_result != ZE_RESULT_SUCCESS) { - fprintf(stderr, "zeDeviceGet() failed!\n"); - ret = -1; - goto fn_fail; - } - -fn_exit: - *devices_num_ = devices_num; - *devices_ = devices; - return ret; - -fn_fail: - devices_num = 0; - if (devices) { - free(devices); - devices = NULL; - } - return ret; -} - -static inline int find_driver_with_gpu(uint32_t *driver_idx, - ze_driver_handle_t *driver_) { - int ret = 0; - ze_result_t ze_result; - uint32_t drivers_num = 0; - ze_device_handle_t *devices = NULL; - ze_driver_handle_t *drivers = NULL; - ze_driver_handle_t driver_with_gpus = NULL; - - ret = get_drivers(&drivers_num, &drivers); - if (ret) { - goto fn_fail; - } - - /* Find a driver with GPU */ - for (uint32_t i = 0; i < drivers_num; ++i) { - uint32_t devices_num = 0; - ze_driver_handle_t driver = drivers[i]; - - ret = get_devices(driver, &devices_num, &devices); - if (ret) { - goto fn_fail; - } - - for (uint32_t d = 0; d < devices_num; ++d) { - ze_device_handle_t device = devices[d]; - ze_device_properties_t device_properties = { - .stype = ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES, .pNext = NULL}; - - ze_result = zeDeviceGetProperties(device, &device_properties); - if (ze_result != ZE_RESULT_SUCCESS) { - fprintf(stderr, "zeDeviceGetProperties() failed!\n"); - ret = -1; - goto fn_fail; - } - - if (device_properties.type == ZE_DEVICE_TYPE_GPU) { - driver_with_gpus = driver; - *driver_idx = i; - break; - } - } - - if (devices) { - free(devices); - devices = NULL; - } - - if (driver_with_gpus != NULL) { - goto fn_exit; - } - } - -fn_fail: - if (devices) { - free(devices); - } - -fn_exit: - *driver_ = driver_with_gpus; - if (drivers) { - free(drivers); - } - return ret; -} - -static inline int find_gpu_device(ze_driver_handle_t driver, - ze_device_handle_t *device_) { - int ret = -1; - uint32_t devices_num = 0; - ze_device_handle_t *devices = NULL; - ze_device_handle_t device; - - ret = get_devices(driver, &devices_num, &devices); - if (ret) { - return ret; - } +int init_level_zero(void); - for (uint32_t d = 0; d < devices_num; ++d) { - device = devices[d]; - ze_device_properties_t device_properties = { - .stype = ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES, .pNext = NULL}; +int create_context(ze_driver_handle_t driver, ze_context_handle_t *context); - ze_result_t ze_result = - zeDeviceGetProperties(device, &device_properties); - if (ze_result != ZE_RESULT_SUCCESS) { - fprintf(stderr, "zeDeviceGetProperties() failed!\n"); - ret = -1; - break; - } +int destroy_context(ze_context_handle_t context); - if (device_properties.type == ZE_DEVICE_TYPE_GPU) { - *device_ = device; - ret = 0; - break; - } - } +int find_driver_with_gpu(uint32_t *driver_idx, ze_driver_handle_t *driver_); - if (devices) { - free(devices); - } - return ret; -} +int find_gpu_device(ze_driver_handle_t driver, ze_device_handle_t *device_); int level_zero_fill(ze_context_handle_t context, ze_device_handle_t device, void *ptr, size_t size, const void *pattern, - size_t pattern_size) { - int ret = 0; - - ze_command_queue_desc_t commandQueueDesc = { - ZE_STRUCTURE_TYPE_COMMAND_QUEUE_DESC, - NULL, - 0, - 0, - 0, - ZE_COMMAND_QUEUE_MODE_DEFAULT, - ZE_COMMAND_QUEUE_PRIORITY_NORMAL}; - - ze_command_list_desc_t commandListDesc = { - ZE_STRUCTURE_TYPE_COMMAND_LIST_DESC, 0, 0, - ZE_COMMAND_LIST_FLAG_RELAXED_ORDERING}; - - ze_command_queue_handle_t hCommandQueue; - ze_result_t ze_result = zeCommandQueueCreate( - context, device, &commandQueueDesc, &hCommandQueue); - if (ze_result != ZE_RESULT_SUCCESS) { - fprintf(stderr, "zeCommandQueueCreate() failed!\n"); - return -1; - } - - ze_command_list_handle_t hCommandList; - ze_result = - zeCommandListCreate(context, device, &commandListDesc, &hCommandList); - if (ze_result != ZE_RESULT_SUCCESS) { - fprintf(stderr, "zeCommandListCreate() failed!\n"); - ret = -1; - goto err_queue_destroy; - } - - // fill memory with a pattern - ze_result = zeCommandListAppendMemoryFill( - hCommandList, ptr, pattern, pattern_size, size, NULL, 0, NULL); - if (ze_result != ZE_RESULT_SUCCESS) { - fprintf(stderr, "zeCommandListAppendMemoryFill() failed!\n"); - ret = -1; - goto err_list_destroy; - } - - // close and execute the command list - ze_result = zeCommandListClose(hCommandList); - if (ze_result != ZE_RESULT_SUCCESS) { - fprintf(stderr, "zeCommandListClose() failed!\n"); - ret = -1; - goto err_list_destroy; - } - - ze_result = zeCommandQueueExecuteCommandLists(hCommandQueue, 1, - &hCommandList, NULL); - if (ze_result != ZE_RESULT_SUCCESS) { - fprintf(stderr, "zeCommandQueueExecuteCommandLists() failed!\n"); - ret = -1; - goto err_list_destroy; - } - - // sync - ze_result = zeCommandQueueSynchronize(hCommandQueue, UINT64_MAX); - if (ze_result != ZE_RESULT_SUCCESS) { - fprintf(stderr, "zeCommandQueueSynchronize() failed!\n"); - ret = -1; - goto err_list_destroy; - } - - // cleanup -err_list_destroy: - ze_result = zeCommandListDestroy(hCommandList); - if (ze_result != ZE_RESULT_SUCCESS) { - fprintf(stderr, "zeCommandListDestroy() failed!\n"); - ret = -1; - } - -err_queue_destroy: - ze_result = zeCommandQueueDestroy(hCommandQueue); - if (ze_result != ZE_RESULT_SUCCESS) { - fprintf(stderr, "zeCommandQueueDestroy() failed!\n"); - ret = -1; - } - - return ret; -} + size_t pattern_size); int level_zero_copy(ze_context_handle_t context, ze_device_handle_t device, - void *dst_ptr, void *src_ptr, size_t size) { - int ret = 0; - ze_command_queue_desc_t commandQueueDesc = { - ZE_STRUCTURE_TYPE_COMMAND_QUEUE_DESC, - NULL, - 0, - 0, - 0, - ZE_COMMAND_QUEUE_MODE_DEFAULT, - ZE_COMMAND_QUEUE_PRIORITY_NORMAL}; - - ze_command_list_desc_t commandListDesc = { - ZE_STRUCTURE_TYPE_COMMAND_LIST_DESC, 0, 0, - ZE_COMMAND_LIST_FLAG_RELAXED_ORDERING}; - - ze_command_queue_handle_t hCommandQueue; - ze_result_t ze_result = zeCommandQueueCreate( - context, device, &commandQueueDesc, &hCommandQueue); - if (ze_result != ZE_RESULT_SUCCESS) { - fprintf(stderr, "zeCommandQueueCreate() failed!\n"); - return -1; - } - - ze_command_list_handle_t hCommandList; - ze_result = - zeCommandListCreate(context, device, &commandListDesc, &hCommandList); - if (ze_result != ZE_RESULT_SUCCESS) { - fprintf(stderr, "zeCommandListCreate() failed!\n"); - ret = -1; - goto err_queue_destroy; - } - - // copy from device memory to host memory - ze_result = zeCommandListAppendMemoryCopy(hCommandList, dst_ptr, src_ptr, - size, NULL, 0, NULL); - if (ze_result != ZE_RESULT_SUCCESS) { - fprintf(stderr, "zeCommandListAppendMemoryCopy() failed!\n"); - ret = -1; - goto err_list_destroy; - } - - // close and execute the command list - ze_result = zeCommandListClose(hCommandList); - if (ze_result != ZE_RESULT_SUCCESS) { - fprintf(stderr, "zeCommandListClose() failed!\n"); - ret = -1; - goto err_list_destroy; - } - - ze_result = zeCommandQueueExecuteCommandLists(hCommandQueue, 1, - &hCommandList, NULL); - if (ze_result != ZE_RESULT_SUCCESS) { - fprintf(stderr, "zeCommandQueueExecuteCommandLists() failed!\n"); - ret = -1; - goto err_list_destroy; - } - - ze_result = zeCommandQueueSynchronize(hCommandQueue, UINT64_MAX); - if (ze_result != ZE_RESULT_SUCCESS) { - fprintf(stderr, "zeCommandQueueSynchronize() failed!\n"); - ret = -1; - goto err_list_destroy; - } - - // cleanup -err_list_destroy: - ze_result = zeCommandListDestroy(hCommandList); - if (ze_result != ZE_RESULT_SUCCESS) { - fprintf(stderr, "zeCommandListDestroy() failed!\n"); - ret = -1; - } - -err_queue_destroy: - ze_result = zeCommandQueueDestroy(hCommandQueue); - if (ze_result != ZE_RESULT_SUCCESS) { - fprintf(stderr, "zeCommandQueueDestroy() failed!\n"); - ret = -1; - } - - return ret; -} - -int create_context(ze_driver_handle_t driver, ze_context_handle_t *context) { - ze_result_t ze_result; - ze_context_desc_t ctxtDesc = { - .stype = ZE_STRUCTURE_TYPE_CONTEXT_DESC, .pNext = NULL, .flags = 0}; - - ze_result = zeContextCreate(driver, &ctxtDesc, context); - if (ze_result != ZE_RESULT_SUCCESS) { - fprintf(stderr, "zeContextCreate() failed!\n"); - return -1; - } - - return 0; -} - -int destroy_context(ze_context_handle_t context) { - ze_result_t ze_result; - ze_result = zeContextDestroy(context); - if (ze_result != ZE_RESULT_SUCCESS) { - fprintf(stderr, "zeContextDestroy() failed!\n"); - return -1; - } - - return 0; -} + void *dst_ptr, void *src_ptr, size_t size); -#endif // UMF_EXAMPLE_UTILS_LEVEL_ZERO_H +#endif /* UMF_EXAMPLES_LEVEL_ZERO_H */ diff --git a/examples/ipc_level_zero/CMakeLists.txt b/examples/ipc_level_zero/CMakeLists.txt index 78d0e667a..10483c91e 100644 --- a/examples/ipc_level_zero/CMakeLists.txt +++ b/examples/ipc_level_zero/CMakeLists.txt @@ -45,7 +45,8 @@ message(STATUS "Level Zero include directory: ${LEVEL_ZERO_INCLUDE_DIRS}") # build the example set(EXAMPLE_NAME umf_example_ipc_level_zero) -add_executable(${EXAMPLE_NAME} ipc_level_zero.c) +add_executable(${EXAMPLE_NAME} ipc_level_zero.c + ${UMF_EXAMPLE_DIR}/common/examples_level_zero.c) target_include_directories(${EXAMPLE_NAME} PRIVATE ${LIBUMF_INCLUDE_DIRS} ${UMF_EXAMPLE_DIR}/common) target_link_directories(${EXAMPLE_NAME} PRIVATE ${LIBUMF_LIBRARY_DIRS} diff --git a/examples/ipc_level_zero/ipc_level_zero.c b/examples/ipc_level_zero/ipc_level_zero.c index c7b74171f..f8fd2f361 100644 --- a/examples/ipc_level_zero/ipc_level_zero.c +++ b/examples/ipc_level_zero/ipc_level_zero.c @@ -8,6 +8,7 @@ */ #include +#include #include "umf/ipc.h" #include "umf/memory_pool.h" diff --git a/examples/level_zero_shared_memory/CMakeLists.txt b/examples/level_zero_shared_memory/CMakeLists.txt index 21edf9a84..06a0c36bd 100644 --- a/examples/level_zero_shared_memory/CMakeLists.txt +++ b/examples/level_zero_shared_memory/CMakeLists.txt @@ -45,7 +45,8 @@ message(STATUS "Level Zero include directory: ${LEVEL_ZERO_INCLUDE_DIRS}") # build the example set(EXAMPLE_NAME umf_example_level_zero_shared_memory) -add_executable(${EXAMPLE_NAME} level_zero_shared_memory.c) +add_executable(${EXAMPLE_NAME} level_zero_shared_memory.c + ${UMF_EXAMPLE_DIR}/common/examples_level_zero.c) target_include_directories(${EXAMPLE_NAME} PRIVATE ${LIBUMF_INCLUDE_DIRS} ${UMF_EXAMPLE_DIR}/common) target_link_directories(${EXAMPLE_NAME} PRIVATE ${LIBUMF_LIBRARY_DIRS} diff --git a/examples/level_zero_shared_memory/level_zero_shared_memory.c b/examples/level_zero_shared_memory/level_zero_shared_memory.c index 725941f6e..607da6d4c 100644 --- a/examples/level_zero_shared_memory/level_zero_shared_memory.c +++ b/examples/level_zero_shared_memory/level_zero_shared_memory.c @@ -7,6 +7,8 @@ * */ +#include + #include #include #include From 971113d016ccf8ece32824bc43c56acf4b7557b0 Mon Sep 17 00:00:00 2001 From: Krzysztof Filipek Date: Fri, 29 Nov 2024 11:46:24 +0100 Subject: [PATCH 344/352] [CMake] Remove redundant compilation flags This change removes all unnecessary flags that are enabled by other flags like -Wall, -Wextra, -Wpedantic Signed-off-by: Krzysztof Filipek --- cmake/helpers.cmake | 4 ---- 1 file changed, 4 deletions(-) diff --git a/cmake/helpers.cmake b/cmake/helpers.cmake index 2a16de742..2544a1518 100644 --- a/cmake/helpers.cmake +++ b/cmake/helpers.cmake @@ -233,12 +233,8 @@ function(add_umf_target_compile_options name) -Wall -Wextra -Wpedantic - -Wempty-body - -Wunused-parameter - -Wformat -Wformat-security -Wcast-qual - -Wunused-result $<$:-fdiagnostics-color=auto>) if(CMAKE_BUILD_TYPE STREQUAL "Release") target_compile_definitions(${name} PRIVATE -D_FORTIFY_SOURCE=2) From 022ec6b260fe090d73344fa7418b4603e1e3b568 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Fri, 29 Nov 2024 13:30:32 +0100 Subject: [PATCH 345/352] Rename examples_level_zero.* to examples_level_zero_helpers.* --- examples/CMakeLists.txt | 5 +++-- .../{examples_level_zero.c => examples_level_zero_helpers.c} | 2 +- .../{examples_level_zero.h => examples_level_zero_helpers.h} | 0 examples/ipc_level_zero/CMakeLists.txt | 5 +++-- examples/ipc_level_zero/ipc_level_zero.c | 2 +- examples/level_zero_shared_memory/CMakeLists.txt | 5 +++-- examples/level_zero_shared_memory/level_zero_shared_memory.c | 2 +- 7 files changed, 12 insertions(+), 9 deletions(-) rename examples/common/{examples_level_zero.c => examples_level_zero_helpers.c} (99%) rename examples/common/{examples_level_zero.h => examples_level_zero_helpers.h} (100%) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 8be80977e..942579a30 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -49,7 +49,7 @@ if(UMF_BUILD_GPU_EXAMPLES add_umf_executable( NAME ${EXAMPLE_NAME} SRCS level_zero_shared_memory/level_zero_shared_memory.c - common/examples_level_zero.c + common/examples_level_zero_helpers.c LIBS disjoint_pool ze_loader umf) target_include_directories( @@ -127,7 +127,8 @@ if(UMF_BUILD_GPU_EXAMPLES add_umf_executable( NAME ${EXAMPLE_NAME} - SRCS ipc_level_zero/ipc_level_zero.c common/examples_level_zero.c + SRCS ipc_level_zero/ipc_level_zero.c + common/examples_level_zero_helpers.c LIBS disjoint_pool ze_loader umf) target_include_directories( diff --git a/examples/common/examples_level_zero.c b/examples/common/examples_level_zero_helpers.c similarity index 99% rename from examples/common/examples_level_zero.c rename to examples/common/examples_level_zero_helpers.c index 87bc4ab94..5e00838c2 100644 --- a/examples/common/examples_level_zero.c +++ b/examples/common/examples_level_zero_helpers.c @@ -10,7 +10,7 @@ #include #include -#include "examples_level_zero.h" +#include "examples_level_zero_helpers.h" int init_level_zero(void) { ze_init_flag_t flags = ZE_INIT_FLAG_GPU_ONLY; diff --git a/examples/common/examples_level_zero.h b/examples/common/examples_level_zero_helpers.h similarity index 100% rename from examples/common/examples_level_zero.h rename to examples/common/examples_level_zero_helpers.h diff --git a/examples/ipc_level_zero/CMakeLists.txt b/examples/ipc_level_zero/CMakeLists.txt index 10483c91e..5c17d4c9c 100644 --- a/examples/ipc_level_zero/CMakeLists.txt +++ b/examples/ipc_level_zero/CMakeLists.txt @@ -45,8 +45,9 @@ message(STATUS "Level Zero include directory: ${LEVEL_ZERO_INCLUDE_DIRS}") # build the example set(EXAMPLE_NAME umf_example_ipc_level_zero) -add_executable(${EXAMPLE_NAME} ipc_level_zero.c - ${UMF_EXAMPLE_DIR}/common/examples_level_zero.c) +add_executable( + ${EXAMPLE_NAME} ipc_level_zero.c + ${UMF_EXAMPLE_DIR}/common/examples_level_zero_helpers.c) target_include_directories(${EXAMPLE_NAME} PRIVATE ${LIBUMF_INCLUDE_DIRS} ${UMF_EXAMPLE_DIR}/common) target_link_directories(${EXAMPLE_NAME} PRIVATE ${LIBUMF_LIBRARY_DIRS} diff --git a/examples/ipc_level_zero/ipc_level_zero.c b/examples/ipc_level_zero/ipc_level_zero.c index f8fd2f361..e81940717 100644 --- a/examples/ipc_level_zero/ipc_level_zero.c +++ b/examples/ipc_level_zero/ipc_level_zero.c @@ -15,7 +15,7 @@ #include "umf/pools/pool_disjoint.h" #include "umf/providers/provider_level_zero.h" -#include "examples_level_zero.h" +#include "examples_level_zero_helpers.h" int create_level_zero_pool(ze_context_handle_t context, ze_device_handle_t device, diff --git a/examples/level_zero_shared_memory/CMakeLists.txt b/examples/level_zero_shared_memory/CMakeLists.txt index 06a0c36bd..3711b4094 100644 --- a/examples/level_zero_shared_memory/CMakeLists.txt +++ b/examples/level_zero_shared_memory/CMakeLists.txt @@ -45,8 +45,9 @@ message(STATUS "Level Zero include directory: ${LEVEL_ZERO_INCLUDE_DIRS}") # build the example set(EXAMPLE_NAME umf_example_level_zero_shared_memory) -add_executable(${EXAMPLE_NAME} level_zero_shared_memory.c - ${UMF_EXAMPLE_DIR}/common/examples_level_zero.c) +add_executable( + ${EXAMPLE_NAME} level_zero_shared_memory.c + ${UMF_EXAMPLE_DIR}/common/examples_level_zero_helpers.c) target_include_directories(${EXAMPLE_NAME} PRIVATE ${LIBUMF_INCLUDE_DIRS} ${UMF_EXAMPLE_DIR}/common) target_link_directories(${EXAMPLE_NAME} PRIVATE ${LIBUMF_LIBRARY_DIRS} diff --git a/examples/level_zero_shared_memory/level_zero_shared_memory.c b/examples/level_zero_shared_memory/level_zero_shared_memory.c index 607da6d4c..b0f646861 100644 --- a/examples/level_zero_shared_memory/level_zero_shared_memory.c +++ b/examples/level_zero_shared_memory/level_zero_shared_memory.c @@ -13,7 +13,7 @@ #include #include -#include "examples_level_zero.h" +#include "examples_level_zero_helpers.h" int main(void) { // A result object for storing UMF API result status From f38671aba3b1d24d030aac831fcf5fbb025f3451 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Plewa?= Date: Tue, 22 Oct 2024 15:37:11 +0200 Subject: [PATCH 346/352] Add new benchmarks --- .github/workflows/reusable_gpu.yml | 1 + CMakeLists.txt | 2 +- benchmark/CMakeLists.txt | 53 +++- benchmark/benchmark.cpp | 362 +++++++++++++++++++++++++++ benchmark/benchmark.hpp | 382 +++++++++++++++++++++++++++++ benchmark/benchmark_interfaces.hpp | 129 ++++++++++ benchmark/multithread.cpp | 4 +- benchmark/ubench.c | 16 +- 8 files changed, 925 insertions(+), 24 deletions(-) create mode 100644 benchmark/benchmark.cpp create mode 100644 benchmark/benchmark.hpp create mode 100644 benchmark/benchmark_interfaces.hpp diff --git a/.github/workflows/reusable_gpu.yml b/.github/workflows/reusable_gpu.yml index a09f43e6d..739aab9e1 100644 --- a/.github/workflows/reusable_gpu.yml +++ b/.github/workflows/reusable_gpu.yml @@ -112,6 +112,7 @@ jobs: run: ctest --output-on-failure --test-dir examples -C ${{matrix.build_type}} - name: Run benchmarks + if: matrix.build_type == 'Release' working-directory: ${{env.BUILD_DIR}} run: ctest --output-on-failure --test-dir benchmark -C ${{matrix.build_type}} --exclude-regex umf-bench-multithreaded diff --git a/CMakeLists.txt b/CMakeLists.txt index cc3a24e5f..4dcc293d2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -320,7 +320,7 @@ endif() # compiler is required. Moreover, if these options are not set, CMake will set # up a strict C build, without C++ support. set(OPTIONS_REQUIRING_CXX "UMF_BUILD_TESTS" "UMF_BUILD_LIBUMF_POOL_DISJOINT" - "UMF_BUILD_BENCHMARKS_MT") + "UMF_BUILD_BENCHMARKS_MT" "UMF_BUILD_BENCHMARKS") foreach(option_name ${OPTIONS_REQUIRING_CXX}) if(${option_name}) enable_language(CXX) diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt index aaf50c1c0..5605519ee 100644 --- a/benchmark/CMakeLists.txt +++ b/benchmark/CMakeLists.txt @@ -1,7 +1,24 @@ -# Copyright (C) 2023 Intel Corporation +# 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(FetchContent) +FetchContent_Declare( + googlebenchmark + GIT_REPOSITORY https://github.com/google/benchmark.git + GIT_TAG v1.9.0) + +set(BENCHMARK_ENABLE_GTEST_TESTS + OFF + CACHE BOOL "" FORCE) +set(BENCHMARK_ENABLE_TESTING + OFF + CACHE BOOL "" FORCE) +set(BENCHMARK_ENABLE_INSTALL + OFF + CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(googlebenchmark) + # In MSVC builds, there is no way to determine the actual build type during the # CMake configuration step. Therefore, this message is printed in all MSVC # builds. @@ -32,7 +49,7 @@ function(add_umf_benchmark) "${multiValueArgs}" ${ARGN}) - set(BENCH_NAME umf-bench-${ARG_NAME}) + set(BENCH_NAME umf-${ARG_NAME}) set(BENCH_LIBS ${ARG_LIBS} umf) @@ -52,13 +69,17 @@ function(add_umf_benchmark) COMMAND ${BENCH_NAME} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) - # Benchmark passes if it prints "PASSED" in the output, because ubench of - # scalable pool fails if the confidence interval exceeds maximum permitted - # 2.5%. - set_tests_properties( - ${BENCH_NAME} PROPERTIES - LABELS "benchmark" - PASS_REGULAR_EXPRESSION "PASSED") + if("${BENCH_NAME}" STREQUAL "umf-ubench") + # Benchmark passes if it prints "PASSED" in the output, because ubench + # of scalable pool fails if the confidence interval exceeds maximum + # permitted 2.5%. + set_tests_properties( + ${BENCH_NAME} PROPERTIES + LABELS "benchmark" + PASS_REGULAR_EXPRESSION "PASSED") + else() + set_tests_properties(${BENCH_NAME} PROPERTIES LABELS "benchmark") + endif() if(WINDOWS) # append PATH to DLLs @@ -68,11 +89,11 @@ function(add_umf_benchmark) if(UMF_BUILD_LIBUMF_POOL_DISJOINT) target_compile_definitions(${BENCH_NAME} - PRIVATE UMF_BUILD_LIBUMF_POOL_DISJOINT=1) + PRIVATE UMF_POOL_DISJOINT_ENABLED=1) endif() - if(UMF_BUILD_LIBUMF_POOL_JEMALLOC) + if(UMF_POOL_JEMALLOC_ENABLED) target_compile_definitions(${BENCH_NAME} - PRIVATE UMF_BUILD_LIBUMF_POOL_JEMALLOC=1) + PRIVATE UMF_POOL_JEMALLOC_ENABLED=1) endif() if(UMF_POOL_SCALABLE_ENABLED) target_compile_definitions(${BENCH_NAME} @@ -80,7 +101,7 @@ function(add_umf_benchmark) endif() if(UMF_BUILD_LEVEL_ZERO_PROVIDER) target_compile_definitions(${BENCH_NAME} - PRIVATE UMF_BUILD_LEVEL_ZERO_PROVIDER=1) + PRIVATE UMF_PROVIDER_LEVEL_ZERO_ENABLED=1) target_include_directories( ${BENCH_NAME} PRIVATE ${UMF_CMAKE_SOURCE_DIR}/test/common ${LEVEL_ZERO_INCLUDE_DIRS}) @@ -121,6 +142,12 @@ add_umf_benchmark( LIBS ${LIBS_OPTIONAL} LIBDIRS ${LIB_DIRS}) +add_umf_benchmark( + NAME benchmark + SRCS benchmark.cpp + LIBS ${LIBS_OPTIONAL} benchmark::benchmark + LIBDIRS ${LIB_DIRS}) + if(UMF_BUILD_BENCHMARKS_MT) add_umf_benchmark( NAME multithreaded diff --git a/benchmark/benchmark.cpp b/benchmark/benchmark.cpp new file mode 100644 index 000000000..c10bbda87 --- /dev/null +++ b/benchmark/benchmark.cpp @@ -0,0 +1,362 @@ +/* + * Copyright (C) 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 +#ifdef UMF_POOL_SCALABLE_ENABLED +#include +#endif +#include + +#ifdef UMF_POOL_DISJOINT_ENABLED +#include +#endif + +#ifdef UMF_POOL_JEMALLOC_ENABLED +#include +#endif + +#include "benchmark.hpp" + +struct glibc_malloc : public allocator_interface { + unsigned SetUp([[maybe_unused]] ::benchmark::State &state, + unsigned argPos) override { + return argPos; + } + void TearDown([[maybe_unused]] ::benchmark::State &state) override{}; + void *benchAlloc(size_t size) override { return malloc(size); } + void benchFree(void *ptr, [[maybe_unused]] size_t size) override { + free(ptr); + } + static std::string name() { return "glibc"; } +}; + +struct os_provider : public provider_interface { + umf_os_memory_provider_params_handle_t params = NULL; + os_provider() { + umfOsMemoryProviderParamsCreate(¶ms); + return; + } + + ~os_provider() { + if (params != NULL) { + umfOsMemoryProviderParamsDestroy(params); + } + } + + void *getParams() override { return params; } + umf_memory_provider_ops_t *getOps() override { + return umfOsMemoryProviderOps(); + } + static std::string name() { return "os_provider"; } +}; + +template +struct proxy_pool : public pool_interface { + umf_memory_pool_ops_t * + getOps([[maybe_unused]] ::benchmark::State &state) override { + return umfProxyPoolOps(); + } + void *getParams([[maybe_unused]] ::benchmark::State &state) override { + return nullptr; + } + static std::string name() { return "proxy_pool<" + Provider::name() + ">"; } +}; + +#ifdef UMF_POOL_DISJOINT_ENABLED +template +struct disjoint_pool : public pool_interface { + umf_disjoint_pool_params_handle_t disjoint_memory_pool_params; + + disjoint_pool() { + disjoint_memory_pool_params = NULL; + auto ret = umfDisjointPoolParamsCreate(&disjoint_memory_pool_params); + if (ret != UMF_RESULT_SUCCESS) { + return; + } + + // those function should never fail, so error handling is minimal. + ret = umfDisjointPoolParamsSetSlabMinSize(disjoint_memory_pool_params, + 4096); + if (ret != UMF_RESULT_SUCCESS) { + goto err; + } + + ret = umfDisjointPoolParamsSetCapacity(disjoint_memory_pool_params, 4); + if (ret != UMF_RESULT_SUCCESS) { + goto err; + } + + ret = umfDisjointPoolParamsSetMinBucketSize(disjoint_memory_pool_params, + 4096); + if (ret != UMF_RESULT_SUCCESS) { + goto err; + } + + ret = umfDisjointPoolParamsSetMaxPoolableSize( + disjoint_memory_pool_params, 4096 * 16); + + if (ret != UMF_RESULT_SUCCESS) { + goto err; + } + return; + err: + + umfDisjointPoolParamsDestroy(disjoint_memory_pool_params); + disjoint_memory_pool_params = NULL; + } + + ~disjoint_pool() { + if (disjoint_memory_pool_params != NULL) { + umfDisjointPoolParamsDestroy(disjoint_memory_pool_params); + } + } + + umf_memory_pool_ops_t * + getOps([[maybe_unused]] ::benchmark::State &state) override { + return umfDisjointPoolOps(); + } + void *getParams([[maybe_unused]] ::benchmark::State &state) override { + + if (disjoint_memory_pool_params == NULL) { + state.SkipWithError("Failed to create disjoint pool params"); + } + + return disjoint_memory_pool_params; + } + static std::string name() { + return "disjoint_pool<" + Provider::name() + ">"; + } +}; +#endif + +#ifdef UMF_POOL_JEMALLOC_ENABLED +template +struct jemalloc_pool : public pool_interface { + umf_memory_pool_ops_t * + getOps([[maybe_unused]] ::benchmark::State &state) override { + return umfJemallocPoolOps(); + } + void *getParams([[maybe_unused]] ::benchmark::State &state) override { + return NULL; + } + static std::string name() { + return "jemalloc_pool<" + Provider::name() + ">"; + } +}; +#endif + +#ifdef UMF_POOL_SCALABLE_ENABLED +template +struct scalable_pool : public pool_interface { + virtual umf_memory_pool_ops_t * + getOps([[maybe_unused]] ::benchmark::State &state) override { + return umfScalablePoolOps(); + } + virtual void * + getParams([[maybe_unused]] ::benchmark::State &state) override { + return NULL; + } + static std::string name() { + return "scalable_pool<" + Provider::name() + ">"; + } +}; +#endif +// Benchmarks scenarios: + +UMF_BENCHMARK_TEMPLATE_DEFINE(alloc_benchmark, glibc_fix, fixed_alloc_size, + glibc_malloc); + +// The benchmark arguments specified in Args() are, in order: +// benchmark arguments, allocator arguments, size generator arguments. +// The exact meaning of each argument depends on the benchmark, allocator, and size components used. +// Refer to the 'argsName()' function in each component to find detailed descriptions of these arguments. +UMF_BENCHMARK_REGISTER_F(alloc_benchmark, glibc_fix) + ->Args({10000, 0, 4096}) + ->Args({10000, 100000, 4096}) + ->Threads(4) + ->Threads(1); + +UMF_BENCHMARK_TEMPLATE_DEFINE(alloc_benchmark, glibc_uniform, + uniform_alloc_size, glibc_malloc); +UMF_BENCHMARK_REGISTER_F(alloc_benchmark, glibc_uniform) + ->Args({10000, 0, 8, 64 * 1024, 8}) + ->Threads(4) + ->Threads(1); + +UMF_BENCHMARK_TEMPLATE_DEFINE(alloc_benchmark, os_provider, fixed_alloc_size, + provider_allocator); +UMF_BENCHMARK_REGISTER_F(alloc_benchmark, os_provider) + ->Args({10000, 0, 4096}) + ->Args({10000, 100000, 4096}) + ->Threads(4) + ->Threads(1); + +UMF_BENCHMARK_TEMPLATE_DEFINE(alloc_benchmark, proxy_pool, fixed_alloc_size, + pool_allocator>); + +UMF_BENCHMARK_REGISTER_F(alloc_benchmark, proxy_pool) + ->Args({1000, 0, 4096}) + ->Args({1000, 100000, 4096}) + ->Threads(4) + ->Threads(1); + +#ifdef UMF_POOL_DISJOINT_ENABLED +UMF_BENCHMARK_TEMPLATE_DEFINE(alloc_benchmark, disjoint_pool_fix, + fixed_alloc_size, + pool_allocator>); +UMF_BENCHMARK_REGISTER_F(alloc_benchmark, disjoint_pool_fix) + ->Args({10000, 0, 4096}) + ->Args({10000, 100000, 4096}) + ->Threads(4) + ->Threads(1); + +// TODO: debug why this crashes +/*UMF_BENCHMARK_TEMPLATE_DEFINE(alloc_benchmark, disjoint_pool_uniform, + uniform_alloc_size, + pool_allocator>); +UMF_BENCHMARK_REGISTER_F(alloc_benchmark, disjoint_pool_uniform) + ->Args({10000, 0, 8, 64 * 1024, 8}) + // ->Threads(4) + ->Threads(1); +*/ +#endif + +#ifdef UMF_POOL_JEMALLOC_ENABLED +UMF_BENCHMARK_TEMPLATE_DEFINE(alloc_benchmark, jemalloc_pool_fix, + fixed_alloc_size, + pool_allocator>); +UMF_BENCHMARK_REGISTER_F(alloc_benchmark, jemalloc_pool_fix) + ->Args({10000, 0, 4096}) + ->Args({10000, 100000, 4096}) + ->Threads(4) + ->Threads(1); + +UMF_BENCHMARK_TEMPLATE_DEFINE(alloc_benchmark, jemalloc_pool_uniform, + uniform_alloc_size, + pool_allocator>); +UMF_BENCHMARK_REGISTER_F(alloc_benchmark, jemalloc_pool_uniform) + ->Args({10000, 0, 8, 64 * 1024, 8}) + ->Threads(4) + ->Threads(1); + +#endif +#ifdef UMF_POOL_SCALABLE_ENABLED +UMF_BENCHMARK_TEMPLATE_DEFINE(alloc_benchmark, scalable_pool_fix, + fixed_alloc_size, + pool_allocator>); + +UMF_BENCHMARK_REGISTER_F(alloc_benchmark, scalable_pool_fix) + ->Args({10000, 0, 4096}) + ->Args({10000, 100000, 4096}) + ->Threads(4) + ->Threads(1); + +UMF_BENCHMARK_TEMPLATE_DEFINE(alloc_benchmark, scalable_pool_uniform, + uniform_alloc_size, + pool_allocator>); + +UMF_BENCHMARK_REGISTER_F(alloc_benchmark, scalable_pool_uniform) + ->Args({10000, 0, 8, 64 * 1024, 8}) + ->Threads(4) + ->Threads(1); +#endif +// Multiple allocs/free + +UMF_BENCHMARK_TEMPLATE_DEFINE(multiple_malloc_free_benchmark, glibc_fix, + fixed_alloc_size, glibc_malloc); + +UMF_BENCHMARK_REGISTER_F(multiple_malloc_free_benchmark, glibc_fix) + ->Args({10000, 4096}) + ->Threads(4) + ->Threads(1); + +UMF_BENCHMARK_TEMPLATE_DEFINE(multiple_malloc_free_benchmark, glibc_uniform, + uniform_alloc_size, glibc_malloc); +UMF_BENCHMARK_REGISTER_F(multiple_malloc_free_benchmark, glibc_uniform) + ->Args({10000, 8, 64 * 1024, 8}) + ->Threads(4) + ->Threads(1); + +UMF_BENCHMARK_TEMPLATE_DEFINE(multiple_malloc_free_benchmark, proxy_pool, + fixed_alloc_size, + pool_allocator>); + +UMF_BENCHMARK_REGISTER_F(multiple_malloc_free_benchmark, proxy_pool) + ->Args({10000, 4096}) + ->Threads(4) + ->Threads(1); + +UMF_BENCHMARK_TEMPLATE_DEFINE(multiple_malloc_free_benchmark, os_provider, + fixed_alloc_size, + provider_allocator); +UMF_BENCHMARK_REGISTER_F(multiple_malloc_free_benchmark, os_provider) + ->Args({10000, 4096}) + ->Threads(4) + ->Threads(1); + +#ifdef UMF_POOL_DISJOINT_ENABLED +UMF_BENCHMARK_TEMPLATE_DEFINE(multiple_malloc_free_benchmark, disjoint_pool_fix, + fixed_alloc_size, + pool_allocator>); +UMF_BENCHMARK_REGISTER_F(multiple_malloc_free_benchmark, disjoint_pool_fix) + ->Args({10000, 4096}) + ->Threads(4) + ->Threads(1); + +// TODO: debug why this crashes +/*UMF_BENCHMARK_TEMPLATE_DEFINE(multiple_malloc_free_benchmark, + disjoint_pool_uniform, uniform_alloc_size, + pool_allocator>); +UMF_BENCHMARK_REGISTER_F(multiple_malloc_free_benchmark, disjoint_pool_uniform) + ->Args({10000, 0, 8, 64 * 1024, 8}) + ->Threads(4) + ->Threads(1); +*/ +#endif + +#ifdef UMF_POOL_JEMALLOC_ENABLED +UMF_BENCHMARK_TEMPLATE_DEFINE(multiple_malloc_free_benchmark, jemalloc_pool_fix, + fixed_alloc_size, + pool_allocator>); +UMF_BENCHMARK_REGISTER_F(multiple_malloc_free_benchmark, jemalloc_pool_fix) + ->Args({10000, 4096}) + ->Threads(4) + ->Threads(1); + +UMF_BENCHMARK_TEMPLATE_DEFINE(multiple_malloc_free_benchmark, + jemalloc_pool_uniform, uniform_alloc_size, + pool_allocator>); +UMF_BENCHMARK_REGISTER_F(multiple_malloc_free_benchmark, jemalloc_pool_uniform) + ->Args({1000, 8, 64 * 1024, 8}) + ->Threads(4) + ->Threads(1); + +#endif + +#ifdef UMF_POOL_SCALABLE_ENABLED +UMF_BENCHMARK_TEMPLATE_DEFINE(multiple_malloc_free_benchmark, scalable_pool_fix, + fixed_alloc_size, + pool_allocator>); + +UMF_BENCHMARK_REGISTER_F(multiple_malloc_free_benchmark, scalable_pool_fix) + ->Args({10000, 4096}) + ->Threads(4) + ->Threads(1); + +UMF_BENCHMARK_TEMPLATE_DEFINE(multiple_malloc_free_benchmark, + scalable_pool_uniform, uniform_alloc_size, + pool_allocator>); + +UMF_BENCHMARK_REGISTER_F(multiple_malloc_free_benchmark, scalable_pool_uniform) + ->Args({10000, 8, 64 * 1024, 8}) + ->Threads(4) + ->Threads(1); + +#endif +BENCHMARK_MAIN(); diff --git a/benchmark/benchmark.hpp b/benchmark/benchmark.hpp new file mode 100644 index 000000000..ead6b39e7 --- /dev/null +++ b/benchmark/benchmark.hpp @@ -0,0 +1,382 @@ +/* + * Copyright (C) 2024 Intel Corporation + * + * Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + * + */ + +/* + * This file defines a benchmarking framework for evaluating memory allocation + * and deallocation performance using the Unified Memory Framework (UMF). The + * design is modular and extensible, allowing for flexible benchmarking of different + * allocation strategies, size distributions, and memory providers. + * + * **Key Design Features:** + * - **Modular Components**: The framework is built using interfaces and templates, + * which allows for easy extension and customization of allocation strategies, + * size distributions, and memory providers. + * - **Flexible Allocation Size Generators**: Includes classes like `fixed_alloc_size` + * and `uniform_alloc_size` that generate allocation sizes based on different + * strategies. These classes implement the `alloc_size_interface`. + * - **Abstract Allocator Interface**: The `allocator_interface` defines the basic + * methods for memory allocation and deallocation. Concrete allocators like + * `provider_allocator` and `pool_allocator` implement this interface to work + * with different memory providers and pools. + * - **Benchmarking Classes**: Classes like `alloc_benchmark` and `multiple_malloc_free_benchmark` + * templates the allocation size generator and allocator to perform benchmarks. + * It manages the setup, execution, and teardown of the benchmark. + * - **Threaded Execution Support**: The benchmarks support multi-threaded execution + * by maintaining thread-specific allocation data and synchronization. + * + * **Component Interactions:** + * - **Size Generators and Allocators**: The `alloc_benchmark` class uses a size + * generator (e.g., `fixed_alloc_size` or `uniform_alloc_size`) to determine the + * sizes of memory allocations, and an allocator (e.g., `provider_allocator` or + * `pool_allocator`) to perform the actual memory operations. + * - **Benchmark Execution**: During the benchmark, `alloc_benchmark` repeatedly + * calls the `bench` method, which performs allocations and deallocations using + * the allocator and size generator. + * - **Allocator Adapters**: The `provider_allocator` and `pool_allocator` adapt + * specific memory providers and pools to the `allocator_interface`, allowing + * them to be used interchangeably in the benchmark classes. This abstraction + * enables benchmarking different memory management strategies without changing + * the core benchmarking logic. + * - **Pre-allocations and Iterations**: The `alloc_benchmark` can perform a set + * number of pre-allocations before the benchmark starts, and manages allocation + * and deallocation cycles to simulate memory pressure and fragmentation. + * - **Derived Benchmarks**: `multiple_malloc_free_benchmark` extends + * `alloc_benchmark` to perform multiple random deallocations and reallocations + * in each iteration, using a uniform distribution to select which allocations + * to free and reallocate. This models workloads with frequent memory churn. + * + * **Execution Flow:** + * 1. **Setup Phase**: + * - The benchmark class initializes the size generator and allocator. + * - Pre-allocations are performed if specified. + * - Thread-specific data structures for allocations are prepared. + * 2. **Benchmark Loop**: + * - For each iteration, the `bench` method is called. + * - The size generator provides the next allocation size. + * - The allocator performs the allocation. + * - Allocations are tracked per thread. + * 3. **Teardown Phase**: + * - All remaining allocations are freed. + * - Allocator and size generator are cleaned up. + * + * **Customization and Extension:** + * - New size generators can be created by implementing the `alloc_size_interface`. + * - New allocators can be adapted by implementing the `allocator_interface`. + * - Additional benchmarking scenarios can be created by extending `benchmark_interface`. + */ + +#include +#include +#include +#include + +#include "benchmark_interfaces.hpp" + +struct alloc_data { + void *ptr; + size_t size; +}; + +#define UMF_BENCHMARK_TEMPLATE_DEFINE(BaseClass, Method, ...) \ + BENCHMARK_TEMPLATE_DEFINE_F(BaseClass, Method, __VA_ARGS__) \ + (benchmark::State & state) { \ + for (auto _ : state) { \ + bench(state); \ + } \ + } + +#define UMF_BENCHMARK_REGISTER_F(BaseClass, Method) \ + BENCHMARK_REGISTER_F(BaseClass, Method) \ + ->ArgNames( \ + BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method)::argsName()) \ + ->Name(BENCHMARK_PRIVATE_CONCAT_NAME(BaseClass, Method)::name()) \ + ->MinWarmUpTime(1) + +class fixed_alloc_size : public alloc_size_interface { + public: + unsigned SetUp(::benchmark::State &state, unsigned argPos) override { + size = state.range(argPos); + return argPos + 1; + } + void TearDown([[maybe_unused]] ::benchmark::State &state) override {} + size_t nextSize() override { return size; }; + static std::vector argsName() { return {"size"}; } + + private: + size_t size; +}; + +class uniform_alloc_size : public alloc_size_interface { + using distribution = std::uniform_int_distribution; + + public: + unsigned SetUp(::benchmark::State &state, unsigned argPos) override { + auto min = state.range(argPos++); + auto max = state.range(argPos++); + auto gran = state.range(argPos++); + if (min % gran != 0 && max % gran != 0) { + state.SkipWithError("min and max must be divisible by granularity"); + return argPos; + } + + dist.param(distribution::param_type(min / gran, max / gran)); + multiplier = gran; + return argPos; + } + void TearDown([[maybe_unused]] ::benchmark::State &state) override {} + size_t nextSize() override { return dist(generator) * multiplier; } + static std::vector argsName() { + return {"min size", "max size", "granularity"}; + } + + private: + std::default_random_engine generator; + distribution dist; + size_t multiplier; +}; + +// This class benchmarks speed of alloc() operations. +template < + typename Size, typename Alloc, + typename = + std::enable_if_t::value>, + typename = + std::enable_if_t::value>> +class alloc_benchmark : public benchmark_interface { + public: + size_t max_allocs = 1000; + size_t pre_allocs = 0; + void SetUp(::benchmark::State &state) override { + if (state.thread_index() != 0) { + return; + } + + // unpack arguments + int argPos = 0; + max_allocs = state.range(argPos++); + pre_allocs = state.range(argPos++); + // pass rest of the arguments to "alloc_size" and "allocator" + argPos = base::alloc_size.SetUp(state, argPos); + base::allocator.SetUp(state, argPos); + + // initialize allocations tracking vectors (one per thread) + // and iterators for these vectors. + allocations.resize(state.threads()); + iters.resize(state.threads()); + + for (auto &i : iters) { + i = pre_allocs; + } + + // do "pre_alloc" allocations before actual benchmark. + for (auto &i : allocations) { + i.resize(max_allocs + pre_allocs); + + for (size_t j = 0; j < pre_allocs; j++) { + i[j].ptr = + base::allocator.benchAlloc(base::alloc_size.nextSize()); + if (i[j].ptr == NULL) { + state.SkipWithError("preallocation failed"); + return; + } + i[j].size = base::alloc_size.nextSize(); + } + } + } + + void TearDown(::benchmark::State &state) override { + if (state.thread_index() != 0) { + return; + } + for (auto &i : allocations) { + for (auto &j : i) { + if (j.ptr != NULL) { + base::allocator.benchFree(j.ptr, j.size); + j.ptr = NULL; + j.size = 0; + } + } + } + + base::TearDown(state); + } + + void bench(benchmark::State &state) override { + auto tid = state.thread_index(); + auto s = base::alloc_size.nextSize(); + auto &i = iters[tid]; + allocations[tid][i].ptr = base::allocator.benchAlloc(s); + if (allocations[tid][i].ptr == NULL) { + state.SkipWithError("allocation failed"); + return; + } + allocations[tid][i].size = s; + i++; + if (i >= max_allocs + pre_allocs) { + // This benchmark tests only allocations - + // if allocation tracker is full we pause benchmark to dealloc all allocations - + // excluding pre-allocated ones. + state.PauseTiming(); + while (i > pre_allocs) { + auto &allocation = allocations[tid][--i]; + base::allocator.benchFree(allocation.ptr, allocation.size); + allocation.ptr = NULL; + allocation.size = 0; + } + state.ResumeTiming(); + } + } + static std::vector argsName() { + auto n = benchmark_interface::argsName(); + std::vector res = {"max_allocs", "pre_allocs"}; + res.insert(res.end(), n.begin(), n.end()); + return res; + } + static std::string name() { return base::name() + "/alloc"; } + + protected: + using base = benchmark_interface; + std::vector> allocations; + std::vector iters; +}; + +// This class benchmarks performance of random deallocations and (re)allocations +template < + typename Size, typename Alloc, + typename = + std::enable_if_t::value>, + typename = + std::enable_if_t::value>> +class multiple_malloc_free_benchmark : public alloc_benchmark { + using distribution = std::uniform_int_distribution; + using base = alloc_benchmark; + + public: + int reallocs = 100; + void SetUp(::benchmark::State &state) override { + if (state.thread_index() != 0) { + return; + } + // unpack arguments + int argPos = 0; + base::max_allocs = state.range(argPos++); + + // pass rest of the arguments to "alloc_size" and "allocator" + argPos = base::alloc_size.SetUp(state, argPos); + base::allocator.SetUp(state, argPos); + + // perform initial allocations which will be later freed and reallocated + base::allocations.resize(state.threads()); + for (auto &i : base::allocations) { + i.resize(base::max_allocs); + + for (size_t j = 0; j < base::max_allocs; j++) { + i[j].ptr = + base::allocator.benchAlloc(base::alloc_size.nextSize()); + if (i[j].ptr == NULL) { + state.SkipWithError("preallocation failed"); + return; + } + i[j].size = base::alloc_size.nextSize(); + } + } + dist.param(distribution::param_type(0, base::max_allocs - 1)); + } + + void bench(benchmark::State &state) override { + auto tid = state.thread_index(); + auto &allocation = base::allocations[tid]; + std::vector to_alloc; + for (int j = 0; j < reallocs; j++) { + auto idx = dist(generator); + if (allocation[idx].ptr == NULL) { + continue; + } + to_alloc.push_back(idx); + + base::allocator.benchFree(allocation[idx].ptr, + allocation[idx].size); + allocation[idx].ptr = NULL; + allocation[idx].size = 0; + } + + for (auto idx : to_alloc) { + auto s = base::alloc_size.nextSize(); + allocation[idx].ptr = base::allocator.benchAlloc(s); + if (allocation[idx].ptr == NULL) { + state.SkipWithError("allocation failed"); + } + allocation[idx].size = s; + } + } + + static std::string name() { + return base::base::name() + "/multiple_malloc_free"; + } + static std::vector argsName() { + auto n = benchmark_interface::argsName(); + std::vector res = {"max_allocs"}; + res.insert(res.end(), n.begin(), n.end()); + return res; + } + std::default_random_engine generator; + distribution dist; +}; + +template ::value>> +class provider_allocator : public allocator_interface { + public: + unsigned SetUp(::benchmark::State &state, unsigned r) override { + provider.SetUp(state); + return r; + } + + void TearDown(::benchmark::State &state) override { + provider.TearDown(state); + } + + void *benchAlloc(size_t size) override { + void *ptr; + if (umfMemoryProviderAlloc(provider.provider, size, 0, &ptr) != + UMF_RESULT_SUCCESS) { + return NULL; + } + return ptr; + } + void benchFree(void *ptr, size_t size) override { + umfMemoryProviderFree(provider.provider, ptr, size); + } + static std::string name() { return Provider::name(); } + + private: + Provider provider; +}; + +// TODO: assert Pool to be a pool_interface. +template class pool_allocator : public allocator_interface { + public: + unsigned SetUp(::benchmark::State &state, unsigned r) override { + pool.SetUp(state); + return r; + } + + void TearDown(::benchmark::State &state) override { pool.TearDown(state); } + + virtual void *benchAlloc(size_t size) override { + return umfPoolMalloc(pool.pool, size); + } + virtual void benchFree(void *ptr, [[maybe_unused]] size_t size) override { + umfPoolFree(pool.pool, ptr); + } + + static std::string name() { return Pool::name(); } + + private: + Pool pool; +}; diff --git a/benchmark/benchmark_interfaces.hpp b/benchmark/benchmark_interfaces.hpp new file mode 100644 index 000000000..868116062 --- /dev/null +++ b/benchmark/benchmark_interfaces.hpp @@ -0,0 +1,129 @@ +/* + * Copyright (C) 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 + +class alloc_size_interface { + public: + virtual unsigned SetUp([[maybe_unused]] ::benchmark::State &state, + [[maybe_unused]] unsigned argPos) = 0; + virtual void TearDown([[maybe_unused]] ::benchmark::State &state) = 0; + virtual size_t nextSize() = 0; + static std::vector argsName() { return {""}; }; +}; + +class allocator_interface { + public: + virtual unsigned SetUp([[maybe_unused]] ::benchmark::State &state, + [[maybe_unused]] unsigned argPos) = 0; + virtual void TearDown([[maybe_unused]] ::benchmark::State &state) = 0; + virtual void *benchAlloc(size_t size) = 0; + virtual void benchFree(void *ptr, [[maybe_unused]] size_t size) = 0; + static std::vector argsName() { return {}; } +}; + +template +struct benchmark_interface : public benchmark::Fixture { + void SetUp(::benchmark::State &state) { + int argPos = alloc_size.SetUp(state, 0); + allocator.SetUp(state, argPos); + } + void TearDown(::benchmark::State &state) { + alloc_size.TearDown(state); + allocator.TearDown(state); + } + + virtual void bench(::benchmark::State &state) = 0; + + static std::vector argsName() { + auto s = Size::argsName(); + auto a = Allocator::argsName(); + std::vector res = {}; + res.insert(res.end(), s.begin(), s.end()); + res.insert(res.end(), a.begin(), a.end()); + return res; + } + static std::string name() { return Allocator::name(); } + + Size alloc_size; + Allocator allocator; +}; + +struct provider_interface { + umf_memory_provider_handle_t provider = NULL; + virtual void SetUp(::benchmark::State &state) { + if (state.thread_index() != 0) { + return; + } + auto umf_result = + umfMemoryProviderCreate(getOps(), getParams(), &provider); + if (umf_result != UMF_RESULT_SUCCESS) { + state.SkipWithError("umfMemoryProviderCreate() failed"); + } + } + + virtual void TearDown([[maybe_unused]] ::benchmark::State &state) { + if (state.thread_index() != 0) { + return; + } + + if (provider) { + umfMemoryProviderDestroy(provider); + } + } + + virtual umf_memory_provider_ops_t *getOps() { return nullptr; } + virtual void *getParams() { return nullptr; } +}; + +template ::value>> +struct pool_interface { + virtual void SetUp(::benchmark::State &state) { + provider.SetUp(state); + if (state.thread_index() != 0) { + return; + } + auto umf_result = umfPoolCreate(getOps(state), provider.provider, + getParams(state), 0, &pool); + if (umf_result != UMF_RESULT_SUCCESS) { + state.SkipWithError("umfPoolCreate() failed"); + } + } + virtual void TearDown([[maybe_unused]] ::benchmark::State &state) { + if (state.thread_index() != 0) { + return; + } + // TODO: The scalable pool destruction process can race with other threads + // performing TLS (Thread-Local Storage) destruction. + // As a temporary workaround, we introduce a delay (sleep) + // to ensure the pool is destroyed only after all threads have completed. + // Issue: #933 + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + if (pool) { + umfPoolDestroy(pool); + } + }; + + virtual umf_memory_pool_ops_t * + getOps([[maybe_unused]] ::benchmark::State &state) { + return nullptr; + } + virtual void *getParams([[maybe_unused]] ::benchmark::State &state) { + return nullptr; + } + T provider; + umf_memory_pool_handle_t pool; +}; diff --git a/benchmark/multithread.cpp b/benchmark/multithread.cpp index efb46729c..4558942ec 100644 --- a/benchmark/multithread.cpp +++ b/benchmark/multithread.cpp @@ -113,7 +113,7 @@ int main() { std::cout << "skipping scalable_pool mt_alloc_free" << std::endl; #endif -#if defined(UMF_BUILD_LIBUMF_POOL_JEMALLOC) +#if defined(UMF_POOL_JEMALLOC_ENABLED) std::cout << "jemalloc_pool mt_alloc_free: "; mt_alloc_free(poolCreateExtParams{umfJemallocPoolOps(), nullptr, umfOsMemoryProviderOps(), osParams}); @@ -121,7 +121,7 @@ int main() { std::cout << "skipping jemalloc_pool mt_alloc_free" << std::endl; #endif -#if defined(UMF_BUILD_LIBUMF_POOL_DISJOINT) +#if defined(UMF_POOL_DISJOINT_ENABLED) umf_disjoint_pool_params_handle_t hDisjointParams = nullptr; umf_result_t ret = umfDisjointPoolParamsCreate(&hDisjointParams); if (ret != UMF_RESULT_SUCCESS) { diff --git a/benchmark/ubench.c b/benchmark/ubench.c index 142112e83..5f1bfe9e4 100644 --- a/benchmark/ubench.c +++ b/benchmark/ubench.c @@ -20,11 +20,11 @@ #include #include -#ifdef UMF_BUILD_LIBUMF_POOL_DISJOINT +#ifdef UMF_POOL_DISJOINT_ENABLED #include #endif -#ifdef UMF_BUILD_LIBUMF_POOL_JEMALLOC +#ifdef UMF_POOL_JEMALLOC_ENABLED #include #endif @@ -244,7 +244,7 @@ UBENCH_EX(simple, proxy_pool_with_os_memory_provider) { free(array); } -#if (defined UMF_BUILD_LIBUMF_POOL_DISJOINT) +#if (defined UMF_POOL_DISJOINT_ENABLED) ////////////////// DISJOINT POOL WITH OS MEMORY PROVIDER UBENCH_EX(simple, disjoint_pool_with_os_memory_provider) { @@ -327,9 +327,9 @@ UBENCH_EX(simple, disjoint_pool_with_os_memory_provider) { umfMemoryProviderDestroy(os_memory_provider); free(array); } -#endif /* (defined UMF_BUILD_LIBUMF_POOL_DISJOINT) */ +#endif /* (defined UMF_POOL_DISJOINT_ENABLED) */ -#if (defined UMF_BUILD_LIBUMF_POOL_JEMALLOC) +#if (defined UMF_POOL_JEMALLOC_ENABLED) ////////////////// JEMALLOC POOL WITH OS MEMORY PROVIDER UBENCH_EX(simple, jemalloc_pool_with_os_memory_provider) { @@ -373,7 +373,7 @@ UBENCH_EX(simple, jemalloc_pool_with_os_memory_provider) { umfMemoryProviderDestroy(os_memory_provider); free(array); } -#endif /* (defined UMF_BUILD_LIBUMF_POOL_JEMALLOC) */ +#endif /* (defined UMF_POOL_JEMALLOC_ENABLED) */ #if (defined UMF_POOL_SCALABLE_ENABLED) ////////////////// SCALABLE (TBB) POOL WITH OS MEMORY PROVIDER @@ -421,7 +421,7 @@ UBENCH_EX(simple, scalable_pool_with_os_memory_provider) { } #endif /* (defined UMF_POOL_SCALABLE_ENABLED) */ -#if (defined UMF_BUILD_LIBUMF_POOL_DISJOINT && \ +#if (defined UMF_POOL_DISJOINT_ENABLED && \ defined UMF_BUILD_LEVEL_ZERO_PROVIDER && defined UMF_BUILD_GPU_TESTS) static void do_ipc_get_put_benchmark(alloc_t *allocs, size_t num_allocs, size_t repeats, @@ -630,7 +630,7 @@ UBENCH_EX(ipc, disjoint_pool_with_level_zero_provider) { err_destroy_context: utils_ze_destroy_context(context); } -#endif /* (defined UMF_BUILD_LIBUMF_POOL_DISJOINT && defined UMF_BUILD_LEVEL_ZERO_PROVIDER && defined UMF_BUILD_GPU_TESTS) */ +#endif /* (defined UMF_POLL_DISJOINT_ENABLED && defined UMF_BUILD_LEVEL_ZERO_PROVIDER && defined UMF_BUILD_GPU_TESTS) */ // TODO add IPC benchmark for CUDA From 816d03609958331345912d8b021b85e451156844 Mon Sep 17 00:00:00 2001 From: Rafal Rudnicki Date: Wed, 4 Dec 2024 14:53:39 +0100 Subject: [PATCH 347/352] update 3rd party programs file (uthash, google bench, nvidia) --- licensing/third-party-programs.txt | 540 +++++++++++++++++++++++++++++ 1 file changed, 540 insertions(+) diff --git a/licensing/third-party-programs.txt b/licensing/third-party-programs.txt index 54520c141..8ee09e2e9 100644 --- a/licensing/third-party-programs.txt +++ b/licensing/third-party-programs.txt @@ -422,4 +422,544 @@ _______________________________________________________________________________ _______________________________________________________________________________ +8. uthash: + + Copyright (c) 2005-2018, Troy D. Hanson http://troydhanson.github.com/uthash/ + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +_______________________________________________________________________________ + +9. google benchmark + + Copyright 2015 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +_______________________________________________________________________________ + +9. NVIDIA runtime headers + + Preface + ------- + + The Software License Agreement in Chapter 1 and the Supplement + in Chapter 2 contain license terms and conditions that govern + the use of NVIDIA software. By accepting this agreement, you + agree to comply with all the terms and conditions applicable + to the product(s) included herein. + + 1. License Agreement for NVIDIA Software Development Kits + --------------------------------------------------------- + + + Release Date: July 26, 2018 + --------------------------- + + + Important NoticeRead before downloading, installing, + copying or using the licensed software: + ------------------------------------------------------- + + This license agreement, including exhibits attached + ("Agreement”) is a legal agreement between you and NVIDIA + Corporation ("NVIDIA") and governs your use of a NVIDIA + software development kit (“SDK”). + + Each SDK has its own set of software and materials, but here + is a description of the types of items that may be included in + a SDK: source code, header files, APIs, data sets and assets + (examples include images, textures, models, scenes, videos, + native API input/output files), binary software, sample code, + libraries, utility programs, programming code and + documentation. + + This Agreement can be accepted only by an adult of legal age + of majority in the country in which the SDK is used. + + If you are entering into this Agreement on behalf of a company + or other legal entity, you represent that you have the legal + authority to bind the entity to this Agreement, in which case + “you” will mean the entity you represent. + + If you don’t have the required age or authority to accept + this Agreement, or if you don’t accept all the terms and + conditions of this Agreement, do not download, install or use + the SDK. + + You agree to use the SDK only for purposes that are permitted + by (a) this Agreement, and (b) any applicable law, regulation + or generally accepted practices or guidelines in the relevant + jurisdictions. + + + 1.1. License + + + 1.1.1. License Grant + + Subject to the terms of this Agreement, NVIDIA hereby grants + you a non-exclusive, non-transferable license, without the + right to sublicense (except as expressly provided in this + Agreement) to: + + 1. Install and use the SDK, + + 2. Modify and create derivative works of sample source code + delivered in the SDK, and + + 3. Distribute those portions of the SDK that are identified + in this Agreement as distributable, as incorporated in + object code format into a software application that meets + the distribution requirements indicated in this Agreement. + + + 1.1.2. Distribution Requirements + + These are the distribution requirements for you to exercise + the distribution grant: + + 1. Your application must have material additional + functionality, beyond the included portions of the SDK. + + 2. The distributable portions of the SDK shall only be + accessed by your application. + + 3. The following notice shall be included in modifications + and derivative works of sample source code distributed: + “This software contains source code provided by NVIDIA + Corporation.” + + 4. Unless a developer tool is identified in this Agreement + as distributable, it is delivered for your internal use + only. + + 5. The terms under which you distribute your application + must be consistent with the terms of this Agreement, + including (without limitation) terms relating to the + license grant and license restrictions and protection of + NVIDIA’s intellectual property rights. Additionally, you + agree that you will protect the privacy, security and + legal rights of your application users. + + 6. You agree to notify NVIDIA in writing of any known or + suspected distribution or use of the SDK not in compliance + with the requirements of this Agreement, and to enforce + the terms of your agreements with respect to distributed + SDK. + + + 1.1.3. Authorized Users + + You may allow employees and contractors of your entity or of + your subsidiary(ies) to access and use the SDK from your + secure network to perform work on your behalf. + + If you are an academic institution you may allow users + enrolled or employed by the academic institution to access and + use the SDK from your secure network. + + You are responsible for the compliance with the terms of this + Agreement by your authorized users. If you become aware that + your authorized users didn’t follow the terms of this + Agreement, you agree to take reasonable steps to resolve the + non-compliance and prevent new occurrences. + + + 1.1.4. Pre-Release SDK + + The SDK versions identified as alpha, beta, preview or + otherwise as pre-release, may not be fully functional, may + contain errors or design flaws, and may have reduced or + different security, privacy, accessibility, availability, and + reliability standards relative to commercial versions of + NVIDIA software and materials. Use of a pre-release SDK may + result in unexpected results, loss of data, project delays or + other unpredictable damage or loss. + + You may use a pre-release SDK at your own risk, understanding + that pre-release SDKs are not intended for use in production + or business-critical systems. + + NVIDIA may choose not to make available a commercial version + of any pre-release SDK. NVIDIA may also choose to abandon + development and terminate the availability of a pre-release + SDK at any time without liability. + + + 1.1.5. Updates + + NVIDIA may, at its option, make available patches, workarounds + or other updates to this SDK. Unless the updates are provided + with their separate governing terms, they are deemed part of + the SDK licensed to you as provided in this Agreement. You + agree that the form and content of the SDK that NVIDIA + provides may change without prior notice to you. While NVIDIA + generally maintains compatibility between versions, NVIDIA may + in some cases make changes that introduce incompatibilities in + future versions of the SDK. + + + 1.1.6. Third Party Licenses + + The SDK may come bundled with, or otherwise include or be + distributed with, third party software licensed by a NVIDIA + supplier and/or open source software provided under an open + source license. Use of third party software is subject to the + third-party license terms, or in the absence of third party + terms, the terms of this Agreement. Copyright to third party + software is held by the copyright holders indicated in the + third-party software or license. + + + 1.1.7. Reservation of Rights + + NVIDIA reserves all rights, title, and interest in and to the + SDK, not expressly granted to you under this Agreement. + + + 1.2. Limitations + + The following license limitations apply to your use of the + SDK: + + 1. You may not reverse engineer, decompile or disassemble, + or remove copyright or other proprietary notices from any + portion of the SDK or copies of the SDK. + + 2. Except as expressly provided in this Agreement, you may + not copy, sell, rent, sublicense, transfer, distribute, + modify, or create derivative works of any portion of the + SDK. For clarity, you may not distribute or sublicense the + SDK as a stand-alone product. + + 3. Unless you have an agreement with NVIDIA for this + purpose, you may not indicate that an application created + with the SDK is sponsored or endorsed by NVIDIA. + + 4. You may not bypass, disable, or circumvent any + encryption, security, digital rights management or + authentication mechanism in the SDK. + + 5. You may not use the SDK in any manner that would cause it + to become subject to an open source software license. As + examples, licenses that require as a condition of use, + modification, and/or distribution that the SDK be: + + a. Disclosed or distributed in source code form; + + b. Licensed for the purpose of making derivative works; + or + + c. Redistributable at no charge. + + 6. Unless you have an agreement with NVIDIA for this + purpose, you may not use the SDK with any system or + application where the use or failure of the system or + application can reasonably be expected to threaten or + result in personal injury, death, or catastrophic loss. + Examples include use in avionics, navigation, military, + medical, life support or other life critical applications. + NVIDIA does not design, test or manufacture the SDK for + these critical uses and NVIDIA shall not be liable to you + or any third party, in whole or in part, for any claims or + damages arising from such uses. + + 7. You agree to defend, indemnify and hold harmless NVIDIA + and its affiliates, and their respective employees, + contractors, agents, officers and directors, from and + against any and all claims, damages, obligations, losses, + liabilities, costs or debt, fines, restitutions and + expenses (including but not limited to attorney’s fees + and costs incident to establishing the right of + indemnification) arising out of or related to your use of + the SDK outside of the scope of this Agreement, or not in + compliance with its terms. + + + 1.3. Ownership + + 1. NVIDIA or its licensors hold all rights, title and + interest in and to the SDK and its modifications and + derivative works, including their respective intellectual + property rights, subject to your rights described in this + section. This SDK may include software and materials from + NVIDIA’s licensors, and these licensors are intended + third party beneficiaries that may enforce this Agreement + with respect to their intellectual property rights. + + 2. You hold all rights, title and interest in and to your + applications and your derivative works of the sample + source code delivered in the SDK, including their + respective intellectual property rights, subject to + NVIDIA’s rights described in this section. + + 3. You may, but don’t have to, provide to NVIDIA + suggestions, feature requests or other feedback regarding + the SDK, including possible enhancements or modifications + to the SDK. For any feedback that you voluntarily provide, + you hereby grant NVIDIA and its affiliates a perpetual, + non-exclusive, worldwide, irrevocable license to use, + reproduce, modify, license, sublicense (through multiple + tiers of sublicensees), and distribute (through multiple + tiers of distributors) it without the payment of any + royalties or fees to you. NVIDIA will use feedback at its + choice. NVIDIA is constantly looking for ways to improve + its products, so you may send feedback to NVIDIA through + the developer portal at https://developer.nvidia.com. + + + 1.4. No Warranties + + THE SDK IS PROVIDED BY NVIDIA “AS IS” AND “WITH ALL + FAULTS.” TO THE MAXIMUM EXTENT PERMITTED BY LAW, NVIDIA AND + ITS AFFILIATES EXPRESSLY DISCLAIM ALL WARRANTIES OF ANY KIND + OR NATURE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, + BUT NOT LIMITED TO, ANY WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE, TITLE, NON-INFRINGEMENT, OR THE + ABSENCE OF ANY DEFECTS THEREIN, WHETHER LATENT OR PATENT. NO + WARRANTY IS MADE ON THE BASIS OF TRADE USAGE, COURSE OF + DEALING OR COURSE OF TRADE. + + + 1.5. Limitation of Liability + + TO THE MAXIMUM EXTENT PERMITTED BY LAW, NVIDIA AND ITS + AFFILIATES SHALL NOT BE LIABLE FOR ANY SPECIAL, INCIDENTAL, + PUNITIVE OR CONSEQUENTIAL DAMAGES, OR ANY LOST PROFITS, LOSS + OF USE, LOSS OF DATA OR LOSS OF GOODWILL, OR THE COSTS OF + PROCURING SUBSTITUTE PRODUCTS, ARISING OUT OF OR IN CONNECTION + WITH THIS AGREEMENT OR THE USE OR PERFORMANCE OF THE SDK, + WHETHER SUCH LIABILITY ARISES FROM ANY CLAIM BASED UPON BREACH + OF CONTRACT, BREACH OF WARRANTY, TORT (INCLUDING NEGLIGENCE), + PRODUCT LIABILITY OR ANY OTHER CAUSE OF ACTION OR THEORY OF + LIABILITY. IN NO EVENT WILL NVIDIA’S AND ITS AFFILIATES + TOTAL CUMULATIVE LIABILITY UNDER OR ARISING OUT OF THIS + AGREEMENT EXCEED US$10.00. THE NATURE OF THE LIABILITY OR THE + NUMBER OF CLAIMS OR SUITS SHALL NOT ENLARGE OR EXTEND THIS + LIMIT. + + These exclusions and limitations of liability shall apply + regardless if NVIDIA or its affiliates have been advised of + the possibility of such damages, and regardless of whether a + remedy fails its essential purpose. These exclusions and + limitations of liability form an essential basis of the + bargain between the parties, and, absent any of these + exclusions or limitations of liability, the provisions of this + Agreement, including, without limitation, the economic terms, + would be substantially different. + + + 1.6. Termination + + 1. This Agreement will continue to apply until terminated by + either you or NVIDIA as described below. + + 2. If you want to terminate this Agreement, you may do so by + stopping to use the SDK. + + 3. NVIDIA may, at any time, terminate this Agreement if: + + a. (i) you fail to comply with any term of this + Agreement and the non-compliance is not fixed within + thirty (30) days following notice from NVIDIA (or + immediately if you violate NVIDIA’s intellectual + property rights); + + b. (ii) you commence or participate in any legal + proceeding against NVIDIA with respect to the SDK; or + + c. (iii) NVIDIA decides to no longer provide the SDK in + a country or, in NVIDIA’s sole discretion, the + continued use of it is no longer commercially viable. + + 4. Upon any termination of this Agreement, you agree to + promptly discontinue use of the SDK and destroy all copies + in your possession or control. Your prior distributions in + accordance with this Agreement are not affected by the + termination of this Agreement. Upon written request, you + will certify in writing that you have complied with your + commitments under this section. Upon any termination of + this Agreement all provisions survive except for the + license grant provisions. + + + 1.7. General + + If you wish to assign this Agreement or your rights and + obligations, including by merger, consolidation, dissolution + or operation of law, contact NVIDIA to ask for permission. Any + attempted assignment not approved by NVIDIA in writing shall + be void and of no effect. NVIDIA may assign, delegate or + transfer this Agreement and its rights and obligations, and if + to a non-affiliate you will be notified. + + You agree to cooperate with NVIDIA and provide reasonably + requested information to verify your compliance with this + Agreement. + + This Agreement will be governed in all respects by the laws of + the United States and of the State of Delaware as those laws + are applied to contracts entered into and performed entirely + within Delaware by Delaware residents, without regard to the + conflicts of laws principles. The United Nations Convention on + Contracts for the International Sale of Goods is specifically + disclaimed. You agree to all terms of this Agreement in the + English language. + + The state or federal courts residing in Santa Clara County, + California shall have exclusive jurisdiction over any dispute + or claim arising out of this Agreement. Notwithstanding this, + you agree that NVIDIA shall still be allowed to apply for + injunctive remedies or an equivalent type of urgent legal + relief in any jurisdiction. + + If any court of competent jurisdiction determines that any + provision of this Agreement is illegal, invalid or + unenforceable, such provision will be construed as limited to + the extent necessary to be consistent with and fully + enforceable under the law and the remaining provisions will + remain in full force and effect. Unless otherwise specified, + remedies are cumulative. + + Each party acknowledges and agrees that the other is an + independent contractor in the performance of this Agreement. + + The SDK has been developed entirely at private expense and is + “commercial items” consisting of “commercial computer + software” and “commercial computer software + documentation” provided with RESTRICTED RIGHTS. Use, + duplication or disclosure by the U.S. Government or a U.S. + Government subcontractor is subject to the restrictions in + this Agreement pursuant to DFARS 227.7202-3(a) or as set forth + in subparagraphs (c)(1) and (2) of the Commercial Computer + Software - Restricted Rights clause at FAR 52.227-19, as + applicable. Contractor/manufacturer is NVIDIA, 2788 San Tomas + Expressway, Santa Clara, CA 95051. + + The SDK is subject to United States export laws and + regulations. You agree that you will not ship, transfer or + export the SDK into any country, or use the SDK in any manner, + prohibited by the United States Bureau of Industry and + Security or economic sanctions regulations administered by the + U.S. Department of Treasury’s Office of Foreign Assets + Control (OFAC), or any applicable export laws, restrictions or + regulations. These laws include restrictions on destinations, + end users and end use. By accepting this Agreement, you + confirm that you are not a resident or citizen of any country + currently embargoed by the U.S. and that you are not otherwise + prohibited from receiving the SDK. + + Any notice delivered by NVIDIA to you under this Agreement + will be delivered via mail, email or fax. You agree that any + notices that NVIDIA sends you electronically will satisfy any + legal communication requirements. Please direct your legal + notices or other correspondence to NVIDIA Corporation, 2788 + San Tomas Expressway, Santa Clara, California 95051, United + States of America, Attention: Legal Department. + + This Agreement and any exhibits incorporated into this + Agreement constitute the entire agreement of the parties with + respect to the subject matter of this Agreement and supersede + all prior negotiations or documentation exchanged between the + parties relating to this SDK license. Any additional and/or + conflicting terms on documents issued by you are null, void, + and invalid. Any amendment or waiver under this Agreement + shall be in writing and signed by representatives of both + parties. + + + 2. CUDA Toolkit Supplement to Software License Agreement for + NVIDIA Software Development Kits + ------------------------------------------------------------ + + + Release date: August 16, 2018 + ----------------------------- + + The terms in this supplement govern your use of the NVIDIA + CUDA Toolkit SDK under the terms of your license agreement + (“Agreement”) as modified by this supplement. Capitalized + terms used but not defined below have the meaning assigned to + them in the Agreement. + + This supplement is an exhibit to the Agreement and is + incorporated as an integral part of the Agreement. In the + event of conflict between the terms in this supplement and the + terms in the Agreement, the terms in this supplement govern. + + + 2.1. License Scope + + The SDK is licensed for you to develop applications only for + use in systems with NVIDIA GPUs. + + + 2.2. Distribution + + The portions of the SDK that are distributable under the + Agreement are listed in Attachment A. + + + 2.3. Operating Systems + + Those portions of the SDK designed exclusively for use on the + Linux or FreeBSD operating systems, or other operating systems + derived from the source code to these operating systems, may + be copied and redistributed for use in accordance with this + Agreement, provided that the object code files are not + modified in any way (except for unzipping of compressed + files). + + + 2.4. Audio and Video Encoders and Decoders + + You acknowledge and agree that it is your sole responsibility + to obtain any additional third-party licenses required to + make, have made, use, have used, sell, import, and offer for + sale your products or services that include or incorporate any + third-party software and content relating to audio and/or + video encoders and decoders from, including but not limited + to, Microsoft, Thomson, Fraunhofer IIS, Sisvel S.p.A., + MPEG-LA, and Coding Technologies. NVIDIA does not grant to you + under this Agreement any necessary patent or other rights with + respect to any audio and/or video encoders and decoders. + + + 2.5. Licensing + + If the distribution terms in this Agreement are not suitable + for your organization, or for any questions regarding this + Agreement, please contact NVIDIA at + nvidia-compute-license-questions@nvidia.com. + +_______________________________________________________________________________ + *Other names and brands may be claimed as the property of others. From 0a893d7bd83b4f2afd110da962f83b9fb8aaec3e Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Wed, 4 Dec 2024 00:16:25 +0100 Subject: [PATCH 348/352] Update umfOpenIPCHandle API to use IPC handler isntead of pool --- examples/ipc_ipcapi/ipc_ipcapi_consumer.c | 9 +++- examples/ipc_level_zero/ipc_level_zero.c | 11 +++- include/umf/ipc.h | 13 ++++- src/ipc.c | 37 ++++++++++++-- src/libumf.def | 1 + src/libumf.map | 1 + test/common/ipc_common.c | 9 +++- test/ipcFixtures.hpp | 62 +++++++++++++++++------ test/ipc_negative.cpp | 8 ++- 9 files changed, 124 insertions(+), 27 deletions(-) diff --git a/examples/ipc_ipcapi/ipc_ipcapi_consumer.c b/examples/ipc_ipcapi/ipc_ipcapi_consumer.c index 1739e005a..2f55c473f 100644 --- a/examples/ipc_ipcapi/ipc_ipcapi_consumer.c +++ b/examples/ipc_ipcapi/ipc_ipcapi_consumer.c @@ -142,6 +142,13 @@ int main(int argc, char *argv[]) { goto err_destroy_OS_memory_provider; } + umf_ipc_handler_handle_t ipc_handler; + umf_result = umfPoolGetIPCHandler(scalable_pool, &ipc_handler); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "[producer] ERROR: get IPC handler failed\n"); + goto err_destroy_scalable_pool; + } + // connect to the producer producer_socket = consumer_connect_to_producer(port); if (producer_socket < 0) { @@ -209,7 +216,7 @@ int main(int argc, char *argv[]) { len); void *SHM_ptr; - umf_result = umfOpenIPCHandle(scalable_pool, IPC_handle, &SHM_ptr); + umf_result = umfOpenIPCHandle(ipc_handler, IPC_handle, &SHM_ptr); if (umf_result == UMF_RESULT_ERROR_NOT_SUPPORTED) { fprintf(stderr, "[consumer] SKIP: opening the IPC handle is not supported\n"); diff --git a/examples/ipc_level_zero/ipc_level_zero.c b/examples/ipc_level_zero/ipc_level_zero.c index e81940717..9579244ab 100644 --- a/examples/ipc_level_zero/ipc_level_zero.c +++ b/examples/ipc_level_zero/ipc_level_zero.c @@ -180,14 +180,21 @@ int main(void) { fprintf(stdout, "Consumer pool created.\n"); + umf_ipc_handler_handle_t ipc_handler = 0; + umf_result = umfPoolGetIPCHandler(consumer_pool, &ipc_handler); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "ERROR: Failed to get IPC handler!\n"); + return -1; + } + void *mapped_buf = NULL; - umf_result = umfOpenIPCHandle(consumer_pool, ipc_handle, &mapped_buf); + umf_result = umfOpenIPCHandle(ipc_handler, ipc_handle, &mapped_buf); if (umf_result != UMF_RESULT_SUCCESS) { fprintf(stderr, "ERROR: Failed to open IPC handle!\n"); return -1; } - fprintf(stdout, "IPC handle opened in the consumer pool.\n"); + fprintf(stdout, "IPC handle opened.\n"); size_t *tmp_buf = malloc(BUFFER_SIZE); ret = level_zero_copy(consumer_context, device, tmp_buf, mapped_buf, diff --git a/include/umf/ipc.h b/include/umf/ipc.h index ffe38bfc8..ab47b0971 100644 --- a/include/umf/ipc.h +++ b/include/umf/ipc.h @@ -19,6 +19,8 @@ extern "C" { typedef struct umf_ipc_data_t *umf_ipc_handle_t; +typedef void *umf_ipc_handler_handle_t; + /// /// @brief Returns the size of IPC handles for the specified pool. /// @param hPool [in] Pool handle @@ -44,11 +46,11 @@ umf_result_t umfPutIPCHandle(umf_ipc_handle_t ipcHandle); /// /// @brief Open IPC handle retrieved by umfGetIPCHandle. -/// @param hPool [in] Pool handle where to open the the IPC handle. +/// @param hIPCHandler [in] IPC Handler handle used to open the IPC handle. /// @param ipcHandle [in] IPC handle. /// @param ptr [out] pointer to the memory in the current process. /// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. -umf_result_t umfOpenIPCHandle(umf_memory_pool_handle_t hPool, +umf_result_t umfOpenIPCHandle(umf_ipc_handler_handle_t hIPCHandler, umf_ipc_handle_t ipcHandle, void **ptr); /// @@ -57,6 +59,13 @@ umf_result_t umfOpenIPCHandle(umf_memory_pool_handle_t hPool, /// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. umf_result_t umfCloseIPCHandle(void *ptr); +/// @brief Get handle to the IPC handler from existing pool. +/// @param hPool [in] Pool handle +/// @param hIPCHandler [out] handle to the IPC handler +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfPoolGetIPCHandler(umf_memory_pool_handle_t hPool, + umf_ipc_handler_handle_t *hIPCHandler); + #ifdef __cplusplus } #endif diff --git a/src/ipc.c b/src/ipc.c index 5df755876..1b479fd7c 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -119,12 +119,18 @@ umf_result_t umfPutIPCHandle(umf_ipc_handle_t umfIPCHandle) { return ret; } -umf_result_t umfOpenIPCHandle(umf_memory_pool_handle_t hPool, +umf_result_t umfOpenIPCHandle(umf_ipc_handler_handle_t hIPCHandler, umf_ipc_handle_t umfIPCHandle, void **ptr) { - // We cannot use umfPoolGetMemoryProvider function because it returns - // upstream provider but we need tracking one - umf_memory_provider_handle_t hProvider = hPool->provider; + // IPC handler is an instance of tracking memory provider + if (*(uint32_t *)hIPCHandler != UMF_VERSION_CURRENT) { + // It is a temporary hack to verify that user passes correct IPC handler, + // not a pool handle, as it was required in previous version. + LOG_ERR("Invalid IPC handler."); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + umf_memory_provider_handle_t hProvider = hIPCHandler; void *base = NULL; umf_result_t ret = umfMemoryProviderOpenIPCHandle( @@ -153,3 +159,26 @@ umf_result_t umfCloseIPCHandle(void *ptr) { return umfMemoryProviderCloseIPCHandle(hProvider, allocInfo.base, allocInfo.baseSize); } + +umf_result_t umfPoolGetIPCHandler(umf_memory_pool_handle_t hPool, + umf_ipc_handler_handle_t *hIPCHandler) { + if (hPool == NULL) { + LOG_ERR("Pool handle is NULL."); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + if (hIPCHandler == NULL) { + LOG_ERR("hIPCHandler is NULL."); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + // We cannot use umfPoolGetMemoryProvider function because it returns + // upstream provider but we need tracking one + umf_memory_provider_handle_t hProvider = hPool->provider; + + // We are using tracking provider as an IPC handler because + // it is doing IPC caching. + *hIPCHandler = (umf_ipc_handler_handle_t)hProvider; + + return UMF_RESULT_SUCCESS; +} diff --git a/src/libumf.def b/src/libumf.def index 0b4588bb8..33c09f4b9 100644 --- a/src/libumf.def +++ b/src/libumf.def @@ -102,6 +102,7 @@ EXPORTS umfPoolCreateFromMemspace umfPoolDestroy umfPoolFree + umfPoolGetIPCHandler umfPoolGetIPCHandleSize umfPoolGetLastAllocationError umfPoolGetMemoryProvider diff --git a/src/libumf.map b/src/libumf.map index 41467bad5..c1e1fd62c 100644 --- a/src/libumf.map +++ b/src/libumf.map @@ -96,6 +96,7 @@ UMF_1.0 { umfPoolCreateFromMemspace; umfPoolDestroy; umfPoolFree; + umfPoolGetIPCHandler; umfPoolGetIPCHandleSize; umfPoolGetLastAllocationError; umfPoolGetMemoryProvider; diff --git a/test/common/ipc_common.c b/test/common/ipc_common.c index 9d78afc9c..140927079 100644 --- a/test/common/ipc_common.c +++ b/test/common/ipc_common.c @@ -138,6 +138,13 @@ int run_consumer(int port, umf_memory_pool_ops_t *pool_ops, void *pool_params, goto err_umfMemoryProviderDestroy; } + umf_ipc_handler_handle_t ipc_handler; + umf_result = umfPoolGetIPCHandler(pool, &ipc_handler); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "[consumer] ERROR: get IPC handler failed\n"); + goto err_umfMemoryPoolDestroy; + } + producer_socket = consumer_connect(port); if (producer_socket < 0) { goto err_umfMemoryPoolDestroy; @@ -195,7 +202,7 @@ int run_consumer(int port, umf_memory_pool_ops_t *pool_ops, void *pool_params, len); void *SHM_ptr; - umf_result = umfOpenIPCHandle(pool, IPC_handle, &SHM_ptr); + umf_result = umfOpenIPCHandle(ipc_handler, IPC_handle, &SHM_ptr); if (umf_result == UMF_RESULT_ERROR_NOT_SUPPORTED) { fprintf(stderr, "[consumer] SKIP: opening the IPC handle is not supported\n"); diff --git a/test/ipcFixtures.hpp b/test/ipcFixtures.hpp index 161a84844..8dca83f10 100644 --- a/test/ipcFixtures.hpp +++ b/test/ipcFixtures.hpp @@ -207,12 +207,17 @@ TEST_P(umfIpcTest, BasicFlow) { ASSERT_EQ(ret, UMF_RESULT_SUCCESS); ASSERT_EQ(handleFullSize, handleHalfSize); + umf_ipc_handler_handle_t ipcHandler = nullptr; + ret = umfPoolGetIPCHandler(pool.get(), &ipcHandler); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(ipcHandler, nullptr); + void *fullArray = nullptr; - ret = umfOpenIPCHandle(pool.get(), ipcHandleFull, &fullArray); + ret = umfOpenIPCHandle(ipcHandler, ipcHandleFull, &fullArray); ASSERT_EQ(ret, UMF_RESULT_SUCCESS); void *halfArray = nullptr; - ret = umfOpenIPCHandle(pool.get(), ipcHandleHalf, &halfArray); + ret = umfOpenIPCHandle(ipcHandler, ipcHandleHalf, &halfArray); ASSERT_EQ(ret, UMF_RESULT_SUCCESS); std::vector actual_data(SIZE); @@ -276,8 +281,13 @@ TEST_P(umfIpcTest, GetPoolByOpenedHandle) { for (size_t pool_id = 0; pool_id < NUM_POOLS; pool_id++) { void *ptr = nullptr; + umf_ipc_handler_handle_t ipcHandler = nullptr; ret = - umfOpenIPCHandle(pools_to_open[pool_id].get(), ipcHandle, &ptr); + umfPoolGetIPCHandler(pools_to_open[pool_id].get(), &ipcHandler); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(ipcHandler, nullptr); + + ret = umfOpenIPCHandle(ipcHandler, ipcHandle, &ptr); ASSERT_EQ(ret, UMF_RESULT_SUCCESS); openedPtrs[pool_id][i] = ptr; } @@ -311,16 +321,22 @@ TEST_P(umfIpcTest, GetPoolByOpenedHandle) { TEST_P(umfIpcTest, AllocFreeAllocTest) { constexpr size_t SIZE = 64 * 1024; umf::pool_unique_handle_t pool = makePool(); + umf_ipc_handler_handle_t ipcHandler = nullptr; + + umf_result_t ret = umfPoolGetIPCHandler(pool.get(), &ipcHandler); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(ipcHandler, nullptr); + void *ptr = umfPoolMalloc(pool.get(), SIZE); EXPECT_NE(ptr, nullptr); umf_ipc_handle_t ipcHandle = nullptr; size_t handleSize = 0; - umf_result_t ret = umfGetIPCHandle(ptr, &ipcHandle, &handleSize); + ret = umfGetIPCHandle(ptr, &ipcHandle, &handleSize); ASSERT_EQ(ret, UMF_RESULT_SUCCESS); void *opened_ptr = nullptr; - ret = umfOpenIPCHandle(pool.get(), ipcHandle, &opened_ptr); + ret = umfOpenIPCHandle(ipcHandler, ipcHandle, &opened_ptr); ASSERT_EQ(ret, UMF_RESULT_SUCCESS); ret = umfCloseIPCHandle(opened_ptr); @@ -343,7 +359,7 @@ TEST_P(umfIpcTest, AllocFreeAllocTest) { ret = umfGetIPCHandle(ptr, &ipcHandle, &handleSize); ASSERT_EQ(ret, UMF_RESULT_SUCCESS); - ret = umfOpenIPCHandle(pool.get(), ipcHandle, &opened_ptr); + ret = umfOpenIPCHandle(ipcHandler, ipcHandle, &opened_ptr); ASSERT_EQ(ret, UMF_RESULT_SUCCESS); ret = umfCloseIPCHandle(opened_ptr); @@ -362,11 +378,22 @@ TEST_P(umfIpcTest, AllocFreeAllocTest) { EXPECT_EQ(stat.openCount, stat.closeCount); } -TEST_P(umfIpcTest, openInTwoPools) { +TEST_P(umfIpcTest, openInTwoIpcHandlers) { constexpr size_t SIZE = 100; std::vector expected_data(SIZE); umf::pool_unique_handle_t pool1 = makePool(); umf::pool_unique_handle_t pool2 = makePool(); + umf_ipc_handler_handle_t ipcHandler1 = nullptr; + umf_ipc_handler_handle_t ipcHandler2 = nullptr; + + umf_result_t ret = umfPoolGetIPCHandler(pool1.get(), &ipcHandler1); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(ipcHandler1, nullptr); + + ret = umfPoolGetIPCHandler(pool2.get(), &ipcHandler2); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(ipcHandler2, nullptr); + void *ptr = umfPoolMalloc(pool1.get(), sizeof(expected_data[0]) * SIZE); EXPECT_NE(ptr, nullptr); @@ -375,15 +402,15 @@ TEST_P(umfIpcTest, openInTwoPools) { umf_ipc_handle_t ipcHandle = nullptr; size_t handleSize = 0; - umf_result_t ret = umfGetIPCHandle(ptr, &ipcHandle, &handleSize); + ret = umfGetIPCHandle(ptr, &ipcHandle, &handleSize); ASSERT_EQ(ret, UMF_RESULT_SUCCESS); void *openedPtr1 = nullptr; - ret = umfOpenIPCHandle(pool1.get(), ipcHandle, &openedPtr1); + ret = umfOpenIPCHandle(ipcHandler1, ipcHandle, &openedPtr1); ASSERT_EQ(ret, UMF_RESULT_SUCCESS); void *openedPtr2 = nullptr; - ret = umfOpenIPCHandle(pool2.get(), ipcHandle, &openedPtr2); + ret = umfOpenIPCHandle(ipcHandler2, ipcHandle, &openedPtr2); ASSERT_EQ(ret, UMF_RESULT_SUCCESS); ret = umfPutIPCHandle(ipcHandle); @@ -466,6 +493,7 @@ TEST_P(umfIpcTest, ConcurrentGetPutHandles) { } TEST_P(umfIpcTest, ConcurrentOpenCloseHandles) { + umf_result_t ret; std::vector ptrs; constexpr size_t ALLOC_SIZE = 100; constexpr size_t NUM_POINTERS = 100; @@ -481,21 +509,25 @@ TEST_P(umfIpcTest, ConcurrentOpenCloseHandles) { for (size_t i = 0; i < NUM_POINTERS; ++i) { umf_ipc_handle_t ipcHandle; size_t handleSize; - umf_result_t ret = umfGetIPCHandle(ptrs[i], &ipcHandle, &handleSize); + ret = umfGetIPCHandle(ptrs[i], &ipcHandle, &handleSize); ASSERT_EQ(ret, UMF_RESULT_SUCCESS); ipcHandles[i] = ipcHandle; } std::array, NTHREADS> openedIpcHandles; + umf_ipc_handler_handle_t ipcHandler = nullptr; + ret = umfPoolGetIPCHandler(pool.get(), &ipcHandler); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(ipcHandler, nullptr); umf_test::syncthreads_barrier syncthreads(NTHREADS); auto openHandlesFn = [&ipcHandles, &openedIpcHandles, &syncthreads, - &pool](size_t tid) { + ipcHandler](size_t tid) { syncthreads(); for (auto ipcHandle : ipcHandles) { void *ptr; - umf_result_t ret = umfOpenIPCHandle(pool.get(), ipcHandle, &ptr); + umf_result_t ret = umfOpenIPCHandle(ipcHandler, ipcHandle, &ptr); ASSERT_EQ(ret, UMF_RESULT_SUCCESS); openedIpcHandles[tid].push_back(ptr); } @@ -514,12 +546,12 @@ TEST_P(umfIpcTest, ConcurrentOpenCloseHandles) { umf_test::parallel_exec(NTHREADS, closeHandlesFn); for (auto ipcHandle : ipcHandles) { - umf_result_t ret = umfPutIPCHandle(ipcHandle); + ret = umfPutIPCHandle(ipcHandle); EXPECT_EQ(ret, UMF_RESULT_SUCCESS); } for (void *ptr : ptrs) { - umf_result_t ret = umfPoolFree(pool.get(), ptr); + ret = umfPoolFree(pool.get(), ptr); EXPECT_EQ(ret, get_umf_result_of_free(freeNotSupported, UMF_RESULT_SUCCESS)); } diff --git a/test/ipc_negative.cpp b/test/ipc_negative.cpp index 5407422ea..5c4cccf22 100644 --- a/test/ipc_negative.cpp +++ b/test/ipc_negative.cpp @@ -47,7 +47,11 @@ TEST_F(IpcNotSupported, OpenIPCHandleNotSupported) { // This data doesn't matter, as the ipc call is no-op std::array ipc_data = {}; void *ptr; - auto ret = umfOpenIPCHandle( - pool, reinterpret_cast(&ipc_data), &ptr); + umf_ipc_handler_handle_t ipc_handler; + auto ret = umfPoolGetIPCHandler(pool, &ipc_handler); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + ret = umfOpenIPCHandle(ipc_handler, + reinterpret_cast(&ipc_data), &ptr); EXPECT_EQ(ret, UMF_RESULT_ERROR_NOT_SUPPORTED); } From 55cf4abd58f42b6287d94e53ce442a7a6ccdb2dd Mon Sep 17 00:00:00 2001 From: "Vinogradov, Sergei" Date: Wed, 4 Dec 2024 12:47:26 +0100 Subject: [PATCH 349/352] Update the documentation for the Level Zero IPC example --- scripts/docs_config/examples.rst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/scripts/docs_config/examples.rst b/scripts/docs_config/examples.rst index a84dd3aa2..c58e7fc22 100644 --- a/scripts/docs_config/examples.rst +++ b/scripts/docs_config/examples.rst @@ -194,12 +194,15 @@ to another process it can be opened by the :any:`umfOpenIPCHandle` function. .. code-block:: c + umf_ipc_handler_handle_t ipc_handler = 0; + umf_result = umfPoolGetIPCHandler(consumer_pool, &ipc_handler); + void *mapped_buf = NULL; - umf_result = umfOpenIPCHandle(consumer_pool, ipc_handle, &mapped_buf); + umf_result = umfOpenIPCHandle(ipc_handler, ipc_handle, &mapped_buf); -The :any:`umfOpenIPCHandle` function requires the memory pool handle and the IPC handle as input parameters. It maps +The :any:`umfOpenIPCHandle` function requires the IPC handler and the IPC handle as input parameters. The IPC handler maps the handle to the current process address space and returns the pointer to the same memory region that was allocated -in the producer process. +in the producer process. To retrieve the IPC handler, the :any:`umfPoolGetIPCHandler` function is used. .. note:: The virtual addresses of the memory region referred to by the IPC handle may not be the same in the producer and consumer processes. From 8ad2f6a4d4bfc85f9e826ce8b9c41dee12799aa9 Mon Sep 17 00:00:00 2001 From: Patryk Kaminski Date: Mon, 9 Dec 2024 11:13:48 +0100 Subject: [PATCH 350/352] Disable rsmi in hwloc build Disable not used hwloc feature "rsmi". Silence errors during hwloc linkage to umf, like: /usr/bin/ld: _deps/hwloc_targ-build/lib/libhwloc.a(topology-rsmi.o): in function `get_device_name': topology-rsmi.c:(.text+0x208): undefined reference to `rsmi_dev_name_get' --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4dcc293d2..5614684bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -176,8 +176,8 @@ else() ./configure --prefix=${hwloc_targ_BINARY_DIR} --enable-static=yes --enable-shared=no --disable-libxml2 --disable-pci --disable-levelzero --disable-opencl - --disable-cuda --disable-nvml --disable-libudev CFLAGS=-fPIC - CXXFLAGS=-fPIC + --disable-cuda --disable-nvml --disable-libudev --disable-rsmi + CFLAGS=-fPIC CXXFLAGS=-fPIC WORKING_DIRECTORY ${hwloc_targ_SOURCE_DIR} OUTPUT ${hwloc_targ_SOURCE_DIR}/Makefile DEPENDS ${hwloc_targ_SOURCE_DIR}/configure) From 8c2c0f8464395f058bbd333d5281716ea791efd4 Mon Sep 17 00:00:00 2001 From: Lukasz Dorau Date: Mon, 9 Dec 2024 14:58:33 +0100 Subject: [PATCH 351/352] Do not check coverage in the Release build 1) Do not check coverage in the Release multi-numa build 2) Unify the name of the coverage data file in the `upload-artifact` step and the coverage artifact file in the `Check coverage` step. A name of the coverage artifact file in the `Check coverage` step must be unique. Signed-off-by: Lukasz Dorau --- .github/workflows/reusable_gpu.yml | 2 +- .github/workflows/reusable_multi_numa.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/reusable_gpu.yml b/.github/workflows/reusable_gpu.yml index 739aab9e1..913a0f0f1 100644 --- a/.github/workflows/reusable_gpu.yml +++ b/.github/workflows/reusable_gpu.yml @@ -129,5 +129,5 @@ jobs: - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 if: ${{ matrix.build_type == 'Debug' && matrix.os == 'Ubuntu' }} with: - name: ${{env.COVERAGE_NAME}}-${{matrix.os}}-${{matrix.build_type}}-shared-${{matrix.shared_library}} + name: ${{env.COVERAGE_NAME}}-shared-${{matrix.shared_library}} path: ${{env.COVERAGE_DIR}} diff --git a/.github/workflows/reusable_multi_numa.yml b/.github/workflows/reusable_multi_numa.yml index c012f3e19..8b30ed53e 100644 --- a/.github/workflows/reusable_multi_numa.yml +++ b/.github/workflows/reusable_multi_numa.yml @@ -69,7 +69,7 @@ jobs: --gtest_filter="-*checkModeLocal/*:*checkModePreferredEmptyNodeset/*:testNuma.checkModeInterleave" - name: Check coverage - if: matrix.os == 'ubuntu-22.04' + if: ${{ matrix.build_type == 'Debug' && matrix.os == 'ubuntu-22.04' }} working-directory: ${{env.BUILD_DIR}} run: | export COVERAGE_FILE_NAME=${{env.COVERAGE_NAME}}-${{matrix.os}}-shared-${{matrix.shared_library}} @@ -79,7 +79,7 @@ jobs: mv ./$COVERAGE_FILE_NAME ${{env.COVERAGE_DIR}} - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 - if: matrix.os == 'ubuntu-22.04' + if: ${{ matrix.build_type == 'Debug' && matrix.os == 'ubuntu-22.04' }} with: - name: ${{env.COVERAGE_NAME}}-${{matrix.os}}-${{matrix.build_type}}-shared-${{matrix.shared_library}} + name: ${{env.COVERAGE_NAME}}-${{matrix.os}}-shared-${{matrix.shared_library}} path: ${{env.COVERAGE_DIR}} From ee6a7115618f1660a5c17b8b537bba0ff094c648 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stolarczuk?= Date: Mon, 9 Dec 2024 16:49:00 +0100 Subject: [PATCH 352/352] 0.10.0 release --- ChangeLog | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/ChangeLog b/ChangeLog index 867e59f0f..75b69fdeb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +Mon Dec 09 2024 Łukasz Stolarczuk + + * Version 0.10.0 + + In this release we introduced updates in several areas, listed below. + We still don't yet guarantee a fully stable API, though. + With new parameters' API we broke the compatibility, as we no longer + support direct access to UMF params via (now internal) structures. + + Significant updates: + - updated Level Zero Provider + - new API to handle UMF parameters (replacing previous struct's) + - extended IPC API testing + - new Memtarget and Memspace API + + Minor updates: + - multiple fixes in the source code + - extended code coverage reporting + - improved CI and testing + - new examples + - extended logging + - yet more fixes in the building system + Thu Sep 12 2024 Łukasz Stolarczuk * Version 0.9.0 pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy