diff --git a/include/umf/providers/provider_level_zero.h b/include/umf/providers/provider_level_zero.h index 65d7e3e781..89e55c6e00 100644 --- a/include/umf/providers/provider_level_zero.h +++ b/include/umf/providers/provider_level_zero.h @@ -83,6 +83,21 @@ umf_result_t umfLevelZeroMemoryProviderParamsSetFreePolicy( umf_level_zero_memory_provider_params_handle_t hParams, umf_level_zero_memory_provider_free_policy_t policy); +typedef enum umf_level_zero_memory_provider_memory_exchange_policy_t { + UMF_LEVEL_ZERO_MEMORY_PROVIDER_MEMORY_EXCHANGE_POLICY_IPC = + 0, ///< Memory exchange policy based on IPC. Default. + UMF_LEVEL_ZERO_MEMORY_PROVIDER_MEMORY_EXCHANGE_POLICY_IMPORT_EXPORT, + ///< Memory exchange policy based on import/export APIs. Should be used if IPC exchange policy is not supported. +} umf_level_zero_memory_provider_memory_exchange_policy_t; + +/// @brief Set the memory exchange policy. +/// @param hParams handle to the parameters of the Level Zero Memory Provider. +/// @param policy memory exchange policy. +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfLevelZeroMemoryProviderParamsSetMemoryExchangePolicy( + umf_level_zero_memory_provider_params_handle_t hParams, + umf_level_zero_memory_provider_memory_exchange_policy_t policy); + /// @brief Set the device ordinal in the parameters struct. /// @param hParams handle to the parameters of the Level Zero Memory Provider. /// @param deviceOrdinal device ordinal. diff --git a/src/libumf.def b/src/libumf.def index 68163c6b5f..e5cdcea983 100644 --- a/src/libumf.def +++ b/src/libumf.def @@ -153,6 +153,7 @@ EXPORTS umfGetMemoryProperty umfGetMemoryPropertySize umfJemallocPoolParamsSetName + umfLevelZeroMemoryProviderParamsSetMemoryExchangePolicy umfLevelZeroMemoryProviderParamsSetName umfOsMemoryProviderParamsSetName umfPoolTrimMemory diff --git a/src/libumf.map b/src/libumf.map index 98b9134995..533078cdcc 100644 --- a/src/libumf.map +++ b/src/libumf.map @@ -151,6 +151,7 @@ UMF_1.1 { umfGetMemoryProperty; umfGetMemoryPropertySize; umfJemallocPoolParamsSetName; + umfLevelZeroMemoryProviderParamsSetMemoryExchangePolicy; umfLevelZeroMemoryProviderParamsSetName; umfOsMemoryProviderParamsSetName; umfPoolTrimMemory; diff --git a/src/provider/provider_level_zero.c b/src/provider/provider_level_zero.c index d5ab3e8e4f..84a535dad4 100644 --- a/src/provider/provider_level_zero.c +++ b/src/provider/provider_level_zero.c @@ -43,20 +43,26 @@ void fini_ze_global_state(void) { // 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 + // Handle to the Level Zero context + ze_context_handle_t level_zero_context_handle; - umf_usm_memory_type_t memory_type; ///< Allocation memory type + // Handle to the Level Zero device + ze_device_handle_t level_zero_device_handle; - 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 + // Allocation memory type + umf_usm_memory_type_t memory_type; - umf_level_zero_memory_provider_free_policy_t - freePolicy; ///< Memory free policy + // Array of devices for which the memory should be made resident + ze_device_handle_t *resident_device_handles; + + // Number of devices for which the memory should be made resident + uint32_t resident_device_count; + + // Memory free policy + umf_level_zero_memory_provider_free_policy_t freePolicy; + + // Memory exchange policy + umf_level_zero_memory_provider_memory_exchange_policy_t exchangePolicy; uint32_t device_ordinal; char name[64]; @@ -74,6 +80,8 @@ typedef struct ze_memory_provider_t { ze_driver_memory_free_policy_ext_flags_t freePolicyFlags; + umf_level_zero_memory_provider_memory_exchange_policy_t exchangePolicy; + size_t min_page_size; uint32_t device_ordinal; @@ -253,6 +261,8 @@ umf_result_t umfLevelZeroMemoryProviderParamsCreate( params->resident_device_handles = NULL; params->resident_device_count = 0; params->freePolicy = UMF_LEVEL_ZERO_MEMORY_PROVIDER_FREE_POLICY_DEFAULT; + params->exchangePolicy = + UMF_LEVEL_ZERO_MEMORY_PROVIDER_MEMORY_EXCHANGE_POLICY_IPC; params->device_ordinal = 0; strncpy(params->name, DEFAULT_NAME, sizeof(params->name) - 1); params->name[sizeof(params->name) - 1] = '\0'; @@ -374,6 +384,18 @@ umf_result_t umfLevelZeroMemoryProviderParamsSetFreePolicy( return UMF_RESULT_SUCCESS; } +umf_result_t umfLevelZeroMemoryProviderParamsSetMemoryExchangePolicy( + umf_level_zero_memory_provider_params_handle_t hParams, + umf_level_zero_memory_provider_memory_exchange_policy_t policy) { + if (!hParams) { + LOG_ERR("Level Zero memory provider params handle is NULL"); + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + hParams->exchangePolicy = policy; + return UMF_RESULT_SUCCESS; +} + static ze_driver_memory_free_policy_ext_flags_t umfFreePolicyToZePolicy(umf_level_zero_memory_provider_free_policy_t policy) { switch (policy) { @@ -401,6 +423,11 @@ static ze_relaxed_allocation_limits_exp_desc_t relaxed_device_allocation_desc = .pNext = NULL, .flags = ZE_RELAXED_ALLOCATION_LIMITS_EXP_FLAG_MAX_SIZE}; +static ze_external_memory_export_desc_t memory_export_desc = { + .stype = ZE_STRUCTURE_TYPE_EXTERNAL_MEMORY_EXPORT_DESC, + .pNext = NULL, + .flags = ZE_EXTERNAL_MEMORY_TYPE_FLAG_OPAQUE_WIN32}; + static umf_result_t ze_memory_provider_alloc_helper(void *provider, size_t size, size_t alignment, int update_stats, @@ -421,11 +448,30 @@ static umf_result_t ze_memory_provider_alloc_helper(void *provider, size_t size, case UMF_MEMORY_TYPE_DEVICE: { ze_device_mem_alloc_desc_t dev_desc = { .stype = ZE_STRUCTURE_TYPE_DEVICE_MEM_ALLOC_DESC, - .pNext = use_relaxed_allocation(ze_provider, size) - ? &relaxed_device_allocation_desc - : NULL, + .pNext = NULL, .flags = 0, .ordinal = ze_provider->device_ordinal}; + void *lastNext = &dev_desc.pNext; + + ze_relaxed_allocation_limits_exp_desc_t + relaxed_device_allocation_desc_copy = + relaxed_device_allocation_desc; + if (use_relaxed_allocation(ze_provider, size)) { + // add relaxed allocation desc to the pNext chain + *(uintptr_t *)lastNext = + (uintptr_t)&relaxed_device_allocation_desc_copy; + lastNext = &relaxed_device_allocation_desc_copy.pNext; + } + + ze_external_memory_export_desc_t memory_export_desc_copy = + memory_export_desc; + if (ze_provider->exchangePolicy == + UMF_LEVEL_ZERO_MEMORY_PROVIDER_MEMORY_EXCHANGE_POLICY_IMPORT_EXPORT) { + // add external memory export desc to the pNext chain + *(uintptr_t *)lastNext = (uintptr_t)&memory_export_desc_copy; + lastNext = &memory_export_desc_copy.pNext; + } + ze_result = g_ze_ops.zeMemAllocDevice(ze_provider->context, &dev_desc, size, alignment, ze_provider->device, resultPtr); @@ -599,6 +645,7 @@ static umf_result_t ze_memory_provider_initialize(const void *params, ze_provider->memory_type = umf2ze_memory_type(ze_params->memory_type); ze_provider->freePolicyFlags = umfFreePolicyToZePolicy(ze_params->freePolicy); + ze_provider->exchangePolicy = ze_params->exchangePolicy; ze_provider->min_page_size = 0; ze_provider->device_ordinal = ze_params->device_ordinal; @@ -755,6 +802,7 @@ static umf_result_t ze_memory_provider_allocation_split(void *provider, typedef struct ze_ipc_data_t { int pid; + size_t size; ze_ipc_mem_handle_t ze_handle; } ze_ipc_data_t; @@ -770,20 +818,45 @@ static umf_result_t ze_memory_provider_get_ipc_handle(void *provider, const void *ptr, size_t size, void *providerIpcData) { - (void)size; - ze_result_t ze_result; ze_ipc_data_t *ze_ipc_data = (ze_ipc_data_t *)providerIpcData; struct ze_memory_provider_t *ze_provider = (struct ze_memory_provider_t *)provider; - ze_result = g_ze_ops.zeMemGetIpcHandle(ze_provider->context, ptr, - &ze_ipc_data->ze_handle); - if (ze_result != ZE_RESULT_SUCCESS) { - LOG_ERR("zeMemGetIpcHandle() failed."); - return ze2umf_result(ze_result); + if (ze_provider->exchangePolicy == + UMF_LEVEL_ZERO_MEMORY_PROVIDER_MEMORY_EXCHANGE_POLICY_IPC) { + ze_result = g_ze_ops.zeMemGetIpcHandle(ze_provider->context, ptr, + &ze_ipc_data->ze_handle); + + if (ze_result != ZE_RESULT_SUCCESS) { + LOG_ERR("zeMemGetIpcHandle() failed."); + return ze2umf_result(ze_result); + } + } else { // UMF_LEVEL_ZERO_MEMORY_PROVIDER_MEMORY_EXCHANGE_POLICY_IMPORT_EXPORT + ze_external_memory_export_fd_t fd_desc = { + .stype = ZE_STRUCTURE_TYPE_EXTERNAL_MEMORY_EXPORT_FD, + .pNext = NULL, + .flags = ZE_EXTERNAL_MEMORY_TYPE_FLAG_OPAQUE_WIN32, + .fd = 0}; + + ze_memory_allocation_properties_t mem_alloc_props = { + .stype = ZE_STRUCTURE_TYPE_MEMORY_ALLOCATION_PROPERTIES, + .pNext = &fd_desc, + .type = 0, + .id = 0, + .pageSize = 0}; + + ze_result = g_ze_ops.zeMemGetAllocProperties(ze_provider->context, ptr, + &mem_alloc_props, NULL); + if (ze_result != ZE_RESULT_SUCCESS) { + LOG_ERR("zeMemGetAllocProperties() failed."); + return ze2umf_result(ze_result); + } + + memcpy(&ze_ipc_data->ze_handle, &fd_desc.fd, sizeof(fd_desc.fd)); } + ze_ipc_data->size = size; ze_ipc_data->pid = utils_getpid(); return UMF_RESULT_SUCCESS; @@ -834,14 +907,40 @@ static umf_result_t ze_memory_provider_open_ipc_handle(void *provider, memcpy(&ze_ipc_handle, &fd_local, sizeof(fd_local)); } - ze_result = g_ze_ops.zeMemOpenIpcHandle( - ze_provider->context, ze_provider->device, ze_ipc_handle, 0, ptr); - if (fd_local != -1) { - (void)utils_close_fd(fd_local); - } - if (ze_result != ZE_RESULT_SUCCESS) { - LOG_ERR("zeMemOpenIpcHandle() failed."); - return ze2umf_result(ze_result); + if (ze_provider->exchangePolicy == + UMF_LEVEL_ZERO_MEMORY_PROVIDER_MEMORY_EXCHANGE_POLICY_IPC) { + ze_result = g_ze_ops.zeMemOpenIpcHandle( + ze_provider->context, ze_provider->device, ze_ipc_handle, 0, ptr); + if (fd_local != -1) { + (void)utils_close_fd(fd_local); + } + if (ze_result != ZE_RESULT_SUCCESS) { + LOG_ERR("zeMemOpenIpcHandle() failed."); + return ze2umf_result(ze_result); + } + } else { // UMF_LEVEL_ZERO_MEMORY_PROVIDER_MEMORY_EXCHANGE_POLICY_IMPORT_EXPORT + ze_external_memory_import_fd_t import_fd = { + .stype = ZE_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMPORT_FD, + .pNext = NULL, + .flags = ZE_EXTERNAL_MEMORY_TYPE_FLAG_DMA_BUF, + .fd = fd_local}; + + ze_device_mem_alloc_desc_t alloc_desc = { + .stype = ZE_STRUCTURE_TYPE_DEVICE_MEM_ALLOC_DESC, + .pNext = &import_fd, + .flags = 0, + .ordinal = 0}; + ze_result = g_ze_ops.zeMemAllocDevice(ze_provider->context, &alloc_desc, + ze_ipc_data->size, 0, + ze_provider->device, ptr); + if (fd_local != -1) { + (void)utils_close_fd(fd_local); + } + + if (ze_result != ZE_RESULT_SUCCESS) { + LOG_ERR("zeMemAllocDevice() failed."); + return ze2umf_result(ze_result); + } } return UMF_RESULT_SUCCESS; @@ -1027,6 +1126,14 @@ umf_result_t umfLevelZeroMemoryProviderParamsSetFreePolicy( return UMF_RESULT_ERROR_NOT_SUPPORTED; } +umf_result_t umfLevelZeroMemoryProviderParamsSetMemoryExchangePolicy( + umf_level_zero_memory_provider_params_handle_t hParams, + umf_level_zero_memory_provider_memory_exchange_policy_t policy) { + (void)hParams; + (void)policy; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + umf_result_t umfLevelZeroMemoryProviderParamsSetDeviceOrdinal( umf_level_zero_memory_provider_params_handle_t hParams, uint32_t deviceOrdinal) { diff --git a/src/utils/utils_windows_common.c b/src/utils/utils_windows_common.c index 7aa8f7684d..4e1c63bd44 100644 --- a/src/utils/utils_windows_common.c +++ b/src/utils/utils_windows_common.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -47,10 +48,7 @@ int utils_getpid(void) { return GetCurrentProcessId(); } int utils_gettid(void) { return GetCurrentThreadId(); } -int utils_close_fd(int fd) { - (void)fd; // unused - return -1; -} +int utils_close_fd(int fd) { return CloseHandle((HANDLE)(uintptr_t)fd); } umf_result_t utils_errno_to_umf_result(int err) { (void)err; // unused @@ -58,10 +56,41 @@ umf_result_t utils_errno_to_umf_result(int err) { } umf_result_t utils_duplicate_fd(int pid, int fd_in, int *fd_out) { - (void)pid; // unused - (void)fd_in; // unused - (void)fd_out; // unused - return UMF_RESULT_ERROR_NOT_SUPPORTED; + umf_result_t ret = UMF_RESULT_SUCCESS; + HANDLE current_process_handle = GetCurrentProcess(); + if (!current_process_handle) { + LOG_ERR("GetCurrentProcess() failed."); + return UMF_RESULT_ERROR_UNKNOWN; + } + + HANDLE source_process_handle = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid); + if (!source_process_handle) { + LOG_ERR("OpenProcess() failed for pid=%d.", pid); + ret = UMF_RESULT_ERROR_UNKNOWN; + goto release_current; + } + + HANDLE handle_in = (HANDLE)(uintptr_t)fd_in; + HANDLE handle_out = NULL; + BOOL result = DuplicateHandle(source_process_handle, handle_in, + current_process_handle, &handle_out, + GENERIC_READ | GENERIC_WRITE, FALSE, 0); + if (!result) { + LOG_ERR("DuplicateHandle() failed for pid=%d fd_in=%d handle_in=%p", + pid, fd_in, handle_in); + ret = UMF_RESULT_ERROR_UNKNOWN; + goto release_source; + } + + *fd_out = (int)(uintptr_t)handle_out; + +release_source: + CloseHandle(source_process_handle); + +release_current: + CloseHandle(current_process_handle); + + return ret; } umf_result_t utils_translate_mem_protection_flags(unsigned in_protection, diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8862b7b88d..400508d9de 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -588,13 +588,31 @@ function(add_umf_ipc_test) set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}) endif() - file(COPY ${SRC_DIR}/${ARG_TEST}.sh DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) + if(WINDOWS) + set(EXT bat) + else() + set(EXT sh) + endif() + + file(COPY ${SRC_DIR}/${ARG_TEST}.${EXT} + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) add_test( NAME ${TEST_NAME} - COMMAND ${ARG_TEST}.sh + COMMAND ${ARG_TEST}.${EXT} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + if(WINDOWS) + set_tests_properties(${TEST_NAME} PROPERTIES + ENVIRONMENT "BUILD_TYPE=${CMAKE_BUILD_TYPE}") + # add PATH to DLL on Windows + set(DLL_PATH_LIST + "${DLL_PATH_LIST};PATH=path_list_append:${CMAKE_BINARY_DIR}/bin/;PATH=path_list_append:${CMAKE_BINARY_DIR}/bin/$/" + ) + set_property(TEST ${TEST_NAME} PROPERTY ENVIRONMENT_MODIFICATION + "${DLL_PATH_LIST}") + endif() + set_tests_properties(${TEST_NAME} PROPERTIES LABELS "umf") set_tests_properties(${TEST_NAME} PROPERTIES TIMEOUT 60) if(NOT UMF_TESTS_FAIL_ON_SKIP) @@ -602,6 +620,42 @@ function(add_umf_ipc_test) endif() endfunction() +if(WINDOWS) + set(UMF_IPC_LIBS ws2_32) +endif() + +if(UMF_BUILD_GPU_TESTS AND UMF_LEVEL_ZERO_ENABLED) + build_umf_test( + NAME ipc_level_zero_prov_consumer + SRCS providers/ipc_level_zero_prov_consumer.c common/ipc_common.c + providers/ipc_level_zero_prov_common.c + ${UMF_UTILS_DIR}/utils_level_zero.cpp + LIBS ze_loader ${UMF_IPC_LIBS} ${UMF_UTILS_FOR_TEST}) + build_umf_test( + NAME ipc_level_zero_prov_producer + SRCS providers/ipc_level_zero_prov_producer.c common/ipc_common.c + providers/ipc_level_zero_prov_common.c + ${UMF_UTILS_DIR}/utils_level_zero.cpp + LIBS ze_loader ${UMF_IPC_LIBS} ${UMF_UTILS_FOR_TEST}) + add_umf_ipc_test(TEST ipc_level_zero_prov SRC_DIR providers) +endif() + +if(UMF_BUILD_GPU_TESTS AND UMF_BUILD_CUDA_PROVIDER) + 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 ${UMF_IPC_LIBS} ${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 ${UMF_IPC_LIBS} ${UMF_UTILS_FOR_TEST}) + add_umf_ipc_test(TEST ipc_cuda_prov SRC_DIR providers) +endif() + +# TODO IPC tests for OS, file, devdax providers and proxy lib are supported only +# on Linux - skipping if(LINUX) if(UMF_POOL_SCALABLE_ENABLED) build_umf_test( @@ -645,39 +699,11 @@ if(LINUX) add_umf_ipc_test(TEST ipc_file_prov_fsdax) endif() - # TODO add IPC tests for CUDA - - if(UMF_BUILD_GPU_TESTS AND UMF_LEVEL_ZERO_ENABLED) - build_umf_test( - NAME ipc_level_zero_prov_consumer - SRCS providers/ipc_level_zero_prov_consumer.c common/ipc_common.c - providers/ipc_level_zero_prov_common.c - ${UMF_UTILS_DIR}/utils_level_zero.cpp - LIBS ze_loader ${UMF_UTILS_FOR_TEST}) - build_umf_test( - NAME ipc_level_zero_prov_producer - SRCS providers/ipc_level_zero_prov_producer.c common/ipc_common.c - providers/ipc_level_zero_prov_common.c - ${UMF_UTILS_DIR}/utils_level_zero.cpp - LIBS ze_loader ${UMF_UTILS_FOR_TEST}) - add_umf_ipc_test(TEST ipc_level_zero_prov SRC_DIR providers) - endif() - - if(UMF_BUILD_GPU_TESTS AND UMF_BUILD_CUDA_PROVIDER) - 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 ${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 ${UMF_UTILS_FOR_TEST}) - add_umf_ipc_test(TEST ipc_cuda_prov SRC_DIR providers) - endif() else() - message(STATUS "IPC tests are supported on Linux only - skipping") + message( + STATUS + "IPC tests for OS, file, devdax providers and proxy lib are supported only on Linux - skipping" + ) endif() if(LINUX diff --git a/test/common/ipc_common.c b/test/common/ipc_common.c index 5e9b911be8..879d392868 100644 --- a/test/common/ipc_common.c +++ b/test/common/ipc_common.c @@ -5,13 +5,21 @@ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ +#ifdef _WIN32 +#define _WINSOCK_DEPRECATED_NO_WARNINGS +#include +typedef int socklen_t; +typedef SSIZE_T ssize_t; +#else #include -#include -#include -#include #include #include #include +#endif + +#include +#include +#include #include "ipc_common.h" @@ -53,25 +61,39 @@ Generally communication between the producer and the consumer looks like: */ int consumer_connect(int port) { + +#ifdef _WIN32 + WSADATA wsaData; + SOCKET producer_socket, consumer_socket; +#else + int producer_socket = -1; + int consumer_socket = -1; +#endif + struct sockaddr_in consumer_addr; struct sockaddr_in producer_addr; int producer_addr_len; - int producer_socket = -1; - int consumer_socket = -1; - int ret = -1; + +#ifdef _WIN32 + // initialize Winsock + if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { + fprintf(stderr, "WSAStartup failed: %d\n", WSAGetLastError()); + return -1; + } +#endif // create a socket consumer_socket = socket(AF_INET, SOCK_STREAM, 0); if (consumer_socket < 0) { fprintf(stderr, "[consumer] ERROR: creating socket failed\n"); - return -1; + goto err_WSA_cleanup; } fprintf(stderr, "[consumer] Socket created\n"); // set the IP address and the port consumer_addr.sin_family = AF_INET; - consumer_addr.sin_port = htons(port); + consumer_addr.sin_port = htons((uint16_t)port); consumer_addr.sin_addr.s_addr = inet_addr(INET_ADDR); // bind to the IP address and the port @@ -101,14 +123,24 @@ int consumer_connect(int port) { } fprintf(stderr, "[consumer] Producer connected at IP %s and port %i\n", - inet_ntoa(producer_addr.sin_addr), ntohs(producer_addr.sin_port)); + inet_ntoa(producer_addr.sin_addr), + (int)ntohs(producer_addr.sin_port)); - ret = producer_socket; // success + return (int)producer_socket; // success err_close_consumer_socket: +#ifdef _WIN32 + closesocket(consumer_socket); +#else close(consumer_socket); +#endif - return ret; +err_WSA_cleanup: +#ifdef _WIN32 + WSACleanup(); +#endif + + return -1; } int run_consumer(int port, const umf_memory_pool_ops_t *pool_ops, @@ -117,7 +149,13 @@ int run_consumer(int port, const umf_memory_pool_ops_t *pool_ops, void *provider_params, memcopy_callback_t memcopy_callback, void *memcopy_ctx) { char consumer_message[MSG_SIZE]; + +#ifdef _WIN32 + SOCKET producer_socket; +#else int producer_socket = -1; +#endif + int ret = -1; umf_memory_provider_handle_t provider = NULL; umf_result_t umf_result = UMF_RESULT_ERROR_UNKNOWN; @@ -171,8 +209,8 @@ int run_consumer(int port, const umf_memory_pool_ops_t *pool_ops, IPC_handle_size); // send confirmation to the producer (IPC handle size) - recv_len = - send(producer_socket, &IPC_handle_size, sizeof(IPC_handle_size), 0); + recv_len = send(producer_socket, (const char *)&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; @@ -214,8 +252,8 @@ int run_consumer(int port, const umf_memory_pool_ops_t *pool_ops, strcpy(consumer_message, "SKIP"); // send the SKIP response to the producer - send(producer_socket, consumer_message, strlen(consumer_message) + 1, - 0); + send(producer_socket, consumer_message, + (int)strlen(consumer_message) + 1, 0); goto err_free_recv_buffer; } @@ -249,8 +287,8 @@ int run_consumer(int port, const umf_memory_pool_ops_t *pool_ops, strcpy(consumer_message, CONSUMER_MSG); // send response to the producer - if (send(producer_socket, consumer_message, strlen(consumer_message) + 1, - 0) < 0) { + if (send(producer_socket, consumer_message, + (int)strlen(consumer_message) + 1, 0) < 0) { fprintf(stderr, "[consumer] ERROR: send() failed\n"); goto err_closeIPCHandle; } @@ -273,7 +311,12 @@ int run_consumer(int port, const umf_memory_pool_ops_t *pool_ops, free(recv_buffer); err_close_producer_socket: +#ifdef _WIN32 + closesocket(producer_socket); + WSACleanup(); +#else close(producer_socket); +#endif err_umfMemoryPoolDestroy: umfPoolDestroy(pool); @@ -295,20 +338,35 @@ int run_consumer(int port, const umf_memory_pool_ops_t *pool_ops, int producer_connect(int port) { struct sockaddr_in consumer_addr; + +#ifdef _WIN32 + WSADATA wsaData; + SOCKET producer_socket; +#else int producer_socket = -1; +#endif + +#ifdef _WIN32 + // initialize Winsock + if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { + fprintf(stderr, "WSAStartup failed. Error Code: %d\n", + WSAGetLastError()); + return -1; + } +#endif // create a producer socket producer_socket = socket(AF_INET, SOCK_STREAM, 0); if (producer_socket < 0) { fprintf(stderr, "[producer] ERROR: Unable to create socket\n"); - return -1; + goto err_WSA_cleanup; } fprintf(stderr, "[producer] Socket created\n"); // set IP address and port the same as for the consumer consumer_addr.sin_family = AF_INET; - consumer_addr.sin_port = htons(port); + consumer_addr.sin_port = htons((uint16_t)port); consumer_addr.sin_addr.s_addr = inet_addr(INET_ADDR); // send connection request to the consumer @@ -321,10 +379,19 @@ int producer_connect(int port) { fprintf(stderr, "[producer] Connected to the consumer\n"); - return producer_socket; // success + return (int)producer_socket; // success err_close_producer_socket_connect: +#ifdef _WIN32 + closesocket(producer_socket); +#else close(producer_socket); +#endif + +err_WSA_cleanup: +#ifdef _WIN32 + WSACleanup(); +#endif return -1; } @@ -340,18 +407,20 @@ int run_producer(int port, const umf_memory_pool_ops_t *pool_ops, int producer_socket = -1; char consumer_message[MSG_SIZE]; +#if !defined(_WIN32) ret = prctl(PR_SET_PTRACER, getppid()); if (ret == -1) { perror("PR_SET_PTRACER may be not supported. prctl() call failed"); goto err_end; } +#endif // create OS memory provider umf_result = umfMemoryProviderCreate(provider_ops, provider_params, &provider); if (umf_result != UMF_RESULT_SUCCESS) { fprintf(stderr, "[producer] ERROR: creating memory provider failed\n"); - return -1; + goto err_end; } umf_memory_pool_handle_t pool; @@ -421,8 +490,8 @@ int run_producer(int port, const umf_memory_pool_ops_t *pool_ops, } // send the IPC_handle_size to the consumer - ssize_t len = - send(producer_socket, &IPC_handle_size, sizeof(IPC_handle_size), 0); + ssize_t len = send(producer_socket, (const char *)&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; @@ -459,7 +528,8 @@ int run_producer(int port, const umf_memory_pool_ops_t *pool_ops, } // send the IPC_handle of IPC_handle_size to the consumer - if (send(producer_socket, IPC_handle, IPC_handle_size, 0) < 0) { + if (send(producer_socket, (const char *)IPC_handle, (int)IPC_handle_size, + 0) < 0) { fprintf(stderr, "[producer] ERROR: unable to send the message\n"); goto err_close_producer_socket; } @@ -512,7 +582,12 @@ int run_producer(int port, const umf_memory_pool_ops_t *pool_ops, } err_close_producer_socket: +#ifdef _WIN32 + closesocket(producer_socket); + WSACleanup(); +#else close(producer_socket); +#endif err_PutIPCHandle: umf_result = umfPutIPCHandle(IPC_handle); diff --git a/test/providers/ipc_cuda_prov.bat b/test/providers/ipc_cuda_prov.bat new file mode 100644 index 0000000000..989d4d4828 --- /dev/null +++ b/test/providers/ipc_cuda_prov.bat @@ -0,0 +1,38 @@ +@echo off +rem +rem Copyright (C) 2025 Intel Corporation +rem +rem Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. +rem SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +rem + +rem port should be a number from the range <1024, 65535> +set PID=%PROCESS_ID% +set /a PORT=1024 + (PID %% (65535 - 1024)) + +set UMF_LOG="level:debug;flush:debug;output:stderr;pid:yes" + +echo "Starting test_ipc_cuda_prov CONSUMER on port %PORT% ..." +start "" cmd /c ".\%BUILD_TYPE%\test_ipc_cuda_prov_consumer %PORT% > consumer_log.txt 2>&1" + +echo "Waiting 5 sec ..." +ping -n 5 -w 1000 localhost > nul + +echo "Starting test_ipc_cuda_prov PRODUCER on port %PORT% ..." +start "" cmd /c ".\%BUILD_TYPE%\test_ipc_cuda_prov_producer %PORT% > producer_log.txt 2>&1" + +echo "Waiting 10 sec for the consumer and producer to finish ..." +ping -n 10 -w 1000 localhost > nul + +echo "Test finished" +echo "Consumer log:" +type consumer_log.txt + +echo "Producer log:" +type producer_log.txt + +findstr /I "ERROR FATAL" consumer_log.txt producer_log.txt >nul +if not errorlevel 1 ( + echo "Test failed: ERROR or FATAL found in logs." + exit /b 1 +) diff --git a/test/providers/ipc_level_zero_prov.bat b/test/providers/ipc_level_zero_prov.bat new file mode 100644 index 0000000000..df571bfc48 --- /dev/null +++ b/test/providers/ipc_level_zero_prov.bat @@ -0,0 +1,38 @@ +@echo off +rem +rem Copyright (C) 2025 Intel Corporation +rem +rem Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. +rem SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +rem + +rem port should be a number from the range <1024, 65535> +set PID=%PROCESS_ID% +set /a PORT=1024 + (PID %% (65535 - 1024)) + +set UMF_LOG="level:debug;flush:debug;output:stderr;pid:yes" + +echo "Starting test_ipc_level_zero_prov CONSUMER on port %PORT% ..." +start "" cmd /c ".\%BUILD_TYPE%\test_ipc_level_zero_prov_consumer %PORT% > consumer_log.txt 2>&1" + +echo "Waiting 5 sec ..." +ping -n 5 -w 1000 localhost > nul + +echo "Starting test_ipc_level_zero_prov PRODUCER on port %PORT% ..." +start "" cmd /c ".\%BUILD_TYPE%\test_ipc_level_zero_prov_producer %PORT% > producer_log.txt 2>&1" + +echo "Waiting 10 sec for the consumer and producer to finish ..." +ping -n 10 -w 1000 localhost > nul + +echo "Test finished" +echo "Consumer log:" +type consumer_log.txt + +echo "Producer log:" +type producer_log.txt + +findstr /I "ERROR FATAL" consumer_log.txt producer_log.txt >nul +if not errorlevel 1 ( + echo "Test failed: ERROR or FATAL found in logs." + exit /b 1 +) diff --git a/test/providers/ipc_level_zero_prov_consumer.c b/test/providers/ipc_level_zero_prov_consumer.c index 5fb2128815..0dd4f67e63 100644 --- a/test/providers/ipc_level_zero_prov_consumer.c +++ b/test/providers/ipc_level_zero_prov_consumer.c @@ -88,6 +88,20 @@ int main(int argc, char *argv[]) { goto destroy_provider_params; } +#ifdef _WIN32 + // on Windows, we must use the import/export memory exchange policy because IPC + // currently does not work + umf_result = umfLevelZeroMemoryProviderParamsSetMemoryExchangePolicy( + l0_params, + UMF_LEVEL_ZERO_MEMORY_PROVIDER_MEMORY_EXCHANGE_POLICY_IMPORT_EXPORT); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to set memory exchange policy in Level Zero " + "Memory Provider params!\n"); + ret = -1; + goto destroy_provider_params; + } +#endif + umf_disjoint_pool_params_handle_t pool_params = NULL; umf_result = umfDisjointPoolParamsCreate(&pool_params); diff --git a/test/providers/ipc_level_zero_prov_producer.c b/test/providers/ipc_level_zero_prov_producer.c index e6ffcf2ed6..8a097f77a8 100644 --- a/test/providers/ipc_level_zero_prov_producer.c +++ b/test/providers/ipc_level_zero_prov_producer.c @@ -88,6 +88,20 @@ int main(int argc, char *argv[]) { goto destroy_provider_params; } +#ifdef _WIN32 + // on Windows, we must use the import/export memory exchange policy because IPC + // currently does not work + umf_result = umfLevelZeroMemoryProviderParamsSetMemoryExchangePolicy( + l0_params, + UMF_LEVEL_ZERO_MEMORY_PROVIDER_MEMORY_EXCHANGE_POLICY_IMPORT_EXPORT); + if (umf_result != UMF_RESULT_SUCCESS) { + fprintf(stderr, "Failed to set memory exchange policy in Level Zero " + "Memory Provider params!\n"); + ret = -1; + goto destroy_provider_params; + } +#endif + umf_disjoint_pool_params_handle_t pool_params = NULL; umf_result = umfDisjointPoolParamsCreate(&pool_params); diff --git a/test/providers/provider_level_zero_not_impl.cpp b/test/providers/provider_level_zero_not_impl.cpp index dfbd4a2b21..20df164847 100644 --- a/test/providers/provider_level_zero_not_impl.cpp +++ b/test/providers/provider_level_zero_not_impl.cpp @@ -35,6 +35,10 @@ TEST_F(test, level_zero_provider_not_implemented) { hParams, UMF_LEVEL_ZERO_MEMORY_PROVIDER_FREE_POLICY_DEFAULT); ASSERT_EQ(result, UMF_RESULT_ERROR_NOT_SUPPORTED); + result = umfLevelZeroMemoryProviderParamsSetMemoryExchangePolicy( + hParams, UMF_LEVEL_ZERO_MEMORY_PROVIDER_MEMORY_EXCHANGE_POLICY_IPC); + ASSERT_EQ(result, UMF_RESULT_ERROR_NOT_SUPPORTED); + result = umfLevelZeroMemoryProviderParamsSetDeviceOrdinal(hParams, 0); ASSERT_EQ(result, UMF_RESULT_ERROR_NOT_SUPPORTED);