diff --git a/.github/workflows/.spellcheck-conf.toml b/.github/workflows/.spellcheck-conf.toml index 288af6a19..bb0f480d6 100644 --- a/.github/workflows/.spellcheck-conf.toml +++ b/.github/workflows/.spellcheck-conf.toml @@ -1,6 +1,6 @@ [default] # Don't correct the following words: -extend-ignore-words-re = ["ASSER", "Tne", "ba", "BA", "PN"] +extend-ignore-words-re = ["ASSER", "Tne", "ba", "BA", "PN", "usm"] [files] # completely exclude those files from consideration: diff --git a/.github/workflows/reusable_basic.yml b/.github/workflows/reusable_basic.yml index 81ca53f10..123813500 100644 --- a/.github/workflows/reusable_basic.yml +++ b/.github/workflows/reusable_basic.yml @@ -195,6 +195,8 @@ jobs: ${{ matrix.compiler.cxx == 'icpx' && '. /opt/intel/oneapi/setvars.sh' || true }} cmake --build ${{env.BUILD_DIR}} -j $(nproc) + # UMF_LOG="level:debug;flush:debug;output:stderr;pid:no" + # -R "test_provider_os_memory" - name: Run tests working-directory: ${{env.BUILD_DIR}} run: | diff --git a/docs/config/api.rst b/docs/config/api.rst index 879623428..37aa075d5 100644 --- a/docs/config/api.rst +++ b/docs/config/api.rst @@ -170,6 +170,12 @@ Memtarget .. doxygenfile:: experimental/memtarget.h :sections: define enum typedef func +Memory Properties +========================================== + +.. doxygenfile:: memory_props.h + :sections: define enum typedef func var + Inter-Process Communication ========================================== diff --git a/docs/config/spelling_exceptions.txt b/docs/config/spelling_exceptions.txt index d4e40a3ec..c49ab6db0 100644 --- a/docs/config/spelling_exceptions.txt +++ b/docs/config/spelling_exceptions.txt @@ -47,6 +47,7 @@ partList pid poolable preallocated +propertyId providerIpcData providential ptr @@ -71,4 +72,5 @@ umfPoolMallocUsableSize umfPoolRealloc umfMemspaceUserFilter umfMemspaceMemtargetAdd -unfreed \ No newline at end of file +unfreed +usm diff --git a/include/umf/base.h b/include/umf/base.h index b5415c8aa..af332b4d8 100644 --- a/include/umf/base.h +++ b/include/umf/base.h @@ -51,6 +51,33 @@ typedef enum umf_result_t { UMF_RESULT_ERROR_UNKNOWN = 0x7ffffffe ///< Unknown error } umf_result_t; +/// @brief Handle to the memory properties structure +typedef struct umf_memory_properties_t *umf_memory_properties_handle_t; + +/// @brief ID of the memory property +typedef enum umf_memory_property_id_t { + UMF_MEMORY_PROPERTY_INVALID = -1, ///< Invalid property + + // UMF specific + UMF_MEMORY_PROPERTY_PROVIDER_HANDLE = 0, ///< Handle to the memory provider + UMF_MEMORY_PROPERTY_POOL_HANDLE = 1, ///< Handle to the memory pool + + // generic pointer properties + UMF_MEMORY_PROPERTY_POINTER_TYPE = + 2, ///< Type of the pointer (umf_usm_memory_type_t) + UMF_MEMORY_PROPERTY_BASE_ADDRESS = 3, ///< Base address of the allocation + UMF_MEMORY_PROPERTY_BASE_SIZE = 4, ///< Base size of the allocation + UMF_MEMORY_PROPERTY_BUFFER_ID = 5, ///< Unique identifier for the buffer + + // GPU specific + UMF_MEMORY_PROPERTY_CONTEXT = 6, ///< GPU context of the allocation + UMF_MEMORY_PROPERTY_DEVICE = 7, ///< GPU device where the allocation resides + + /// @cond + UMF_MEMORY_PROPERTY_MAX_RESERVED = 0x1000, ///< Maximum reserved value + /// @endcond +} umf_memory_property_id_t; + /// @brief Type of the CTL query typedef enum umf_ctl_query_type { CTL_QUERY_READ, diff --git a/include/umf/memory_props.h b/include/umf/memory_props.h new file mode 100644 index 000000000..33fac315b --- /dev/null +++ b/include/umf/memory_props.h @@ -0,0 +1,46 @@ +/* + * + * Copyright (C) 2025 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_PROPS_H +#define UMF_MEMORY_PROPS_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/// @brief Get the memory properties handle for a given pointer +/// \details +/// The handle returned by this function is valid until the memory pointed +/// to by the pointer is freed. +/// @param ptr pointer to the allocated memory +/// @param props_handle [out] pointer to the memory properties handle +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure +umf_result_t +umfGetMemoryPropertiesHandle(const void *ptr, + umf_memory_properties_handle_t *props_handle); + +/// @brief Get a specific memory property from the properties handle +/// @param props_handle handle to the memory properties +/// @param memory_property_id ID of the memory property to get +/// @param max_property_size size of the property value buffer +/// @param property_value [out] pointer to the value of the memory property +/// which will be filled +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure +umf_result_t umfGetMemoryProperty(umf_memory_properties_handle_t props_handle, + umf_memory_property_id_t memory_property_id, + size_t max_property_size, + void *property_value); + +#ifdef __cplusplus +} +#endif + +#endif /* UMF_MEMORY_PROPS_H */ diff --git a/include/umf/memory_provider.h b/include/umf/memory_provider.h index b98b89346..ad26fd980 100644 --- a/include/umf/memory_provider.h +++ b/include/umf/memory_provider.h @@ -265,6 +265,21 @@ umf_result_t umfMemoryProviderAllocationMerge(umf_memory_provider_handle_t hProvider, void *lowPtr, void *highPtr, size_t totalSize); +/// +/// @brief Retrieve properties of the memory allocation. +/// @param hProvider pointer to the memory provider +/// @param ptr pointer to the allocated memory +/// @param propertyId identifier of the memory property to retrieve +/// @param max_property_size size of the property value buffer +/// @param property_value [out] pointer to the value of the memory property +/// which will be filled +/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure +/// +umf_result_t umfMemoryProviderGetAllocationProperties( + umf_memory_provider_handle_t hProvider, const void *ptr, + umf_memory_property_id_t propertyId, size_t max_property_size, + void *property_value); + #ifdef __cplusplus } #endif diff --git a/include/umf/memory_provider_ops.h b/include/umf/memory_provider_ops.h index 13793124d..3adab3288 100644 --- a/include/umf/memory_provider_ops.h +++ b/include/umf/memory_provider_ops.h @@ -275,6 +275,21 @@ typedef struct umf_memory_provider_ops_t { void *arg, size_t size, umf_ctl_query_type_t queryType); + /// + /// @brief Retrieve properties of the memory allocation. + /// @param provider pointer to the memory provider + /// @param ptr pointer to the allocated memory + /// @param memory_property_id identifier of the memory property to retrieve + /// @param max_property_size size of the property value buffer + /// @param property_value [out] pointer to the value of the memory property + /// which will be filled + /// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure + /// + umf_result_t (*ext_get_allocation_properties)( + void *provider, const void *ptr, + umf_memory_property_id_t memory_property_id, size_t max_property_size, + void *value); + } umf_memory_provider_ops_t; #ifdef __cplusplus diff --git a/scripts/qemu/run-tests.sh b/scripts/qemu/run-tests.sh index 341e2f9ab..35caf05dc 100755 --- a/scripts/qemu/run-tests.sh +++ b/scripts/qemu/run-tests.sh @@ -28,7 +28,9 @@ numactl -H cd build echo "## Running all tests ..." +#UMF_LOG="level:debug;flush:debug;output:stderr;pid:no" ctest --verbose +# --output-on-failure -R "memoryPool" echo "## Running tests bound to a numa node 0 and node 1 ..." numactl -N 0 ctest --output-on-failure diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d11e04c4f..99bb7e2cf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -44,6 +44,7 @@ set(UMF_SOURCES ipc.c ipc_cache.c memory_pool.c + memory_props.c memory_provider.c memory_provider_get_last_failed.c memtarget.c diff --git a/src/ipc.c b/src/ipc.c index d4e5cc806..aa7388af6 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -58,14 +58,19 @@ umf_result_t umfGetIPCHandle(const void *ptr, umf_ipc_handle_t *umfIPCHandle, } size_t ipcHandleSize = 0; - umf_alloc_info_t allocInfo; - umf_result_t ret = umfMemoryTrackerGetAllocInfo(ptr, &allocInfo); + umf_memory_properties_handle_t props = NULL; + umf_result_t ret = umfGetMemoryPropertiesHandle(ptr, &props); if (ret != UMF_RESULT_SUCCESS) { - LOG_ERR("cannot get alloc info for ptr = %p.", ptr); + LOG_ERR("cannot get alloc props for ptr = %p.", ptr); return ret; } - ret = umfPoolGetIPCHandleSize(allocInfo.pool, &ipcHandleSize); + if (props == NULL || props->pool == NULL) { + LOG_ERR("cannot get pool from alloc info for ptr = %p.", ptr); + return UMF_RESULT_ERROR_UNKNOWN; + } + + ret = umfPoolGetIPCHandleSize(props->pool, &ipcHandleSize); if (ret != UMF_RESULT_SUCCESS) { LOG_ERR("cannot get IPC handle size."); return ret; @@ -79,11 +84,14 @@ umf_result_t umfGetIPCHandle(const void *ptr, umf_ipc_handle_t *umfIPCHandle, // We cannot use umfPoolGetMemoryProvider function because it returns // upstream provider but we need tracking one - umf_memory_provider_handle_t provider = allocInfo.pool->provider; - assert(provider); + if (props == NULL || props->pool == NULL || props->pool->provider == NULL) { + LOG_ERR("cannot get memory provider from pool"); + umf_ba_global_free(ipcData); + return UMF_RESULT_ERROR_UNKNOWN; + } + umf_memory_provider_handle_t provider = props->pool->provider; - ret = umfMemoryProviderGetIPCHandle(provider, allocInfo.base, - allocInfo.baseSize, + ret = umfMemoryProviderGetIPCHandle(provider, props->base, props->base_size, (void *)ipcData->providerIpcData); if (ret != UMF_RESULT_SUCCESS) { LOG_ERR("failed to get IPC handle."); @@ -92,10 +100,10 @@ umf_result_t umfGetIPCHandle(const void *ptr, umf_ipc_handle_t *umfIPCHandle, } // ipcData->handle_id is filled by tracking provider - ipcData->base = allocInfo.base; + ipcData->base = props->base; ipcData->pid = utils_getpid(); - ipcData->baseSize = allocInfo.baseSize; - ipcData->offset = (uintptr_t)ptr - (uintptr_t)allocInfo.base; + ipcData->baseSize = props->base_size; + ipcData->offset = (uintptr_t)ptr - (uintptr_t)props->base; *umfIPCHandle = ipcData; *size = ipcHandleSize; diff --git a/src/libumf.def b/src/libumf.def index 0159ddbe2..d8e12b9ba 100644 --- a/src/libumf.def +++ b/src/libumf.def @@ -140,7 +140,10 @@ EXPORTS umfCtlExec umfCtlGet umfCtlSet + umfGetMemoryPropertiesHandle + umfGetMemoryProperty umfJemallocPoolParamsCreate umfJemallocPoolParamsDestroy umfJemallocPoolParamsSetNumArenas + umfMemoryProviderGetAllocationProperties umfPoolGetName diff --git a/src/libumf.map b/src/libumf.map index 348675ff0..4dd8441b3 100644 --- a/src/libumf.map +++ b/src/libumf.map @@ -134,9 +134,12 @@ UMF_1.0 { umfCtlExec; umfCtlGet; umfCtlSet; + umfGetMemoryPropertiesHandle; + umfGetMemoryProperty; umfJemallocPoolParamsCreate; umfJemallocPoolParamsDestroy; umfJemallocPoolParamsSetNumArenas; + umfMemoryProviderGetAllocationProperties; umfPoolGetName; local: *; diff --git a/src/memory_pool.c b/src/memory_pool.c index 0af7b6b62..86fc45071 100644 --- a/src/memory_pool.c +++ b/src/memory_pool.c @@ -286,8 +286,16 @@ umf_result_t umfFree(void *ptr) { umf_result_t umfPoolByPtr(const void *ptr, umf_memory_pool_handle_t *pool) { UMF_CHECK((pool != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); - *pool = umfMemoryTrackerGetPool(ptr); - return *pool ? UMF_RESULT_SUCCESS : UMF_RESULT_ERROR_INVALID_ARGUMENT; + + umf_memory_properties_handle_t props = NULL; + umf_result_t ret = umfGetMemoryPropertiesHandle(ptr, &props); + if (ret != UMF_RESULT_SUCCESS || props == NULL || props->pool == NULL) { + *pool = NULL; + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + *pool = props->pool; + return UMF_RESULT_SUCCESS; } umf_result_t umfPoolGetMemoryProvider(umf_memory_pool_handle_t hPool, diff --git a/src/memory_props.c b/src/memory_props.c new file mode 100644 index 000000000..027805562 --- /dev/null +++ b/src/memory_props.c @@ -0,0 +1,118 @@ +/* + * + * Copyright (C) 2025 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 "memory_props_internal.h" +#include "memory_provider_internal.h" +#include "provider/provider_tracking.h" + +umf_result_t +umfGetMemoryPropertiesHandle(const void *ptr, + umf_memory_properties_handle_t *props_handle) { + if (UNLIKELY(props_handle == NULL)) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + tracker_alloc_info_t *info = NULL; + umf_result_t ret = umfMemoryTrackerGetAllocInfo(ptr, &info); + if (ret == UMF_RESULT_SUCCESS) { + *props_handle = &info->props; + return UMF_RESULT_SUCCESS; + } + + // try to get IPC info + umf_ipc_info_t ipc_info; + ret = umfMemoryTrackerGetIpcInfo(ptr, &ipc_info); + if (ret != UMF_RESULT_SUCCESS) { + LOG_ERR("Failed to get memory properties handle for ptr=%p", ptr); + return ret; + } + + *props_handle = ipc_info.props; + return UMF_RESULT_SUCCESS; +} + +umf_result_t umfGetMemoryProperty(umf_memory_properties_handle_t props_handle, + umf_memory_property_id_t memory_property_id, + size_t max_property_size, void *value) { + if (UNLIKELY((value == NULL) || (props_handle == NULL) || + (max_property_size == 0))) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + umf_memory_provider_t *provider = props_handle->provider; + + switch (memory_property_id) { + case UMF_MEMORY_PROPERTY_INVALID: + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + + case UMF_MEMORY_PROPERTY_POOL_HANDLE: + if (UNLIKELY(max_property_size < sizeof(umf_memory_pool_handle_t))) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + *(umf_memory_pool_handle_t *)value = props_handle->pool; + return UMF_RESULT_SUCCESS; + + case UMF_MEMORY_PROPERTY_PROVIDER_HANDLE: + if (UNLIKELY(max_property_size < + sizeof(umf_memory_provider_handle_t))) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + *(umf_memory_provider_handle_t *)value = provider; + return UMF_RESULT_SUCCESS; + + case UMF_MEMORY_PROPERTY_BUFFER_ID: + if (UNLIKELY(max_property_size < sizeof(uint64_t))) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + *(uint64_t *)value = props_handle->id; + return UMF_RESULT_SUCCESS; + + case UMF_MEMORY_PROPERTY_BASE_ADDRESS: + if (UNLIKELY(max_property_size < sizeof(uintptr_t))) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + *(uintptr_t *)value = (uintptr_t)props_handle->base; + return UMF_RESULT_SUCCESS; + + case UMF_MEMORY_PROPERTY_BASE_SIZE: + if (UNLIKELY(max_property_size < sizeof(size_t))) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + *(size_t *)value = props_handle->base_size; + return UMF_RESULT_SUCCESS; + + case UMF_MEMORY_PROPERTY_POINTER_TYPE: + // NOTE: this property is "cached" in the props_handle but the value is + // determined by the memory provider and set during addition to the + // tracker. + if (UNLIKELY(max_property_size < sizeof(umf_usm_memory_type_t))) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + *(umf_usm_memory_type_t *)value = props_handle->memory_type; + return UMF_RESULT_SUCCESS; + + // GPU Memory Provider specific properties + case UMF_MEMORY_PROPERTY_CONTEXT: + case UMF_MEMORY_PROPERTY_DEVICE: + return provider->ops.ext_get_allocation_properties( + provider->provider_priv, props_handle->base, memory_property_id, + max_property_size, value); + + default: + break; + }; + + return UMF_RESULT_ERROR_INVALID_ARGUMENT; +} diff --git a/src/memory_props_internal.h b/src/memory_props_internal.h new file mode 100644 index 000000000..0a92fca3e --- /dev/null +++ b/src/memory_props_internal.h @@ -0,0 +1,37 @@ +/* + * + * Copyright (C) 2025 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_PROPS_INTERNAL_H +#define UMF_MEMORY_PROPS_INTERNAL_H 1 + +#include + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct umf_memory_properties_t { + umf_memory_pool_handle_t pool; + umf_memory_provider_handle_t provider; + uint64_t id; + void *base; + size_t base_size; + umf_usm_memory_type_t memory_type; +} umf_memory_properties_t; + +#ifdef __cplusplus +} +#endif + +#endif // UMF_MEMORY_PROPS_INTERNAL_H diff --git a/src/memory_provider.c b/src/memory_provider.c index 27f33f86f..24a944246 100644 --- a/src/memory_provider.c +++ b/src/memory_provider.c @@ -18,6 +18,7 @@ #include "base_alloc.h" #include "base_alloc_global.h" #include "libumf.h" +#include "memory_props_internal.h" #include "memory_provider_internal.h" #include "utils_assert.h" @@ -121,40 +122,63 @@ static umf_result_t umfDefaultCtlHandle(void *provider, int operationType, return UMF_RESULT_ERROR_NOT_SUPPORTED; } +static umf_result_t umfDefaultGetAllocationProperties( + void *provider, const void *ptr, umf_memory_property_id_t propertyId, + size_t max_property_size, void *property_value) { + (void)provider; + (void)ptr; + (void)propertyId; + (void)max_property_size; + (void)property_value; + return UMF_RESULT_ERROR_NOT_SUPPORTED; +} + void assignOpsExtDefaults(umf_memory_provider_ops_t *ops) { if (!ops->ext_purge_lazy) { ops->ext_purge_lazy = umfDefaultPurgeLazy; } + if (!ops->ext_purge_force) { ops->ext_purge_force = umfDefaultPurgeForce; } + if (!ops->ext_allocation_split) { ops->ext_allocation_split = umfDefaultAllocationSplit; } + if (!ops->ext_allocation_merge) { ops->ext_allocation_merge = umfDefaultAllocationMerge; } + + if (!ops->ext_ctl) { + ops->ext_ctl = umfDefaultCtlHandle; + } + + if (!ops->ext_get_allocation_properties) { + ops->ext_get_allocation_properties = umfDefaultGetAllocationProperties; + } } void assignOpsIpcDefaults(umf_memory_provider_ops_t *ops) { if (!ops->ext_get_ipc_handle_size) { ops->ext_get_ipc_handle_size = umfDefaultGetIPCHandleSize; } + if (!ops->ext_get_ipc_handle) { ops->ext_get_ipc_handle = umfDefaultGetIPCHandle; } + if (!ops->ext_put_ipc_handle) { ops->ext_put_ipc_handle = umfDefaultPutIPCHandle; } + if (!ops->ext_open_ipc_handle) { ops->ext_open_ipc_handle = umfDefaultOpenIPCHandle; } + if (!ops->ext_close_ipc_handle) { ops->ext_close_ipc_handle = umfDefaultCloseIPCHandle; } - if (!ops->ext_ctl) { - ops->ext_ctl = umfDefaultCtlHandle; - } } #define CHECK_OP(ops, fn) \ @@ -316,7 +340,9 @@ umf_result_t umfMemoryProviderGetName(umf_memory_provider_handle_t hProvider, const char **name) { UMF_CHECK((hProvider != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); UMF_CHECK((name != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); - return hProvider->ops.get_name(hProvider->provider_priv, name); + umf_result_t res = hProvider->ops.get_name(hProvider->provider_priv, name); + checkErrorAndSetLastProvider(res, hProvider); + return res; } umf_result_t umfMemoryProviderPurgeLazy(umf_memory_provider_handle_t hProvider, @@ -356,8 +382,14 @@ umfMemoryProviderAllocationSplit(umf_memory_provider_handle_t hProvider, 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); + umf_result_t res = UMF_RESULT_SUCCESS; + if (!hProvider->ops.ext_allocation_split) { + res = UMF_RESULT_ERROR_NOT_SUPPORTED; + } else { + res = hProvider->ops.ext_allocation_split(hProvider->provider_priv, ptr, + totalSize, firstSize); + } + checkErrorAndSetLastProvider(res, hProvider); return res; } @@ -374,8 +406,14 @@ umfMemoryProviderAllocationMerge(umf_memory_provider_handle_t hProvider, 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); + umf_result_t res = UMF_RESULT_SUCCESS; + if (!hProvider->ops.ext_allocation_merge) { + res = UMF_RESULT_ERROR_NOT_SUPPORTED; + } else { + res = hProvider->ops.ext_allocation_merge(hProvider->provider_priv, + lowPtr, highPtr, totalSize); + } + checkErrorAndSetLastProvider(res, hProvider); return res; } @@ -385,8 +423,17 @@ 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.ext_get_ipc_handle_size(hProvider->provider_priv, - size); + + umf_result_t res = UMF_RESULT_SUCCESS; + if (!hProvider->ops.ext_get_ipc_handle_size) { + res = UMF_RESULT_ERROR_NOT_SUPPORTED; + } else { + res = hProvider->ops.ext_get_ipc_handle_size(hProvider->provider_priv, + size); + } + + checkErrorAndSetLastProvider(res, hProvider); + return res; } umf_result_t @@ -395,9 +442,19 @@ umfMemoryProviderGetIPCHandle(umf_memory_provider_handle_t hProvider, void *providerIpcData) { UMF_CHECK((hProvider != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); UMF_CHECK((ptr != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); + UMF_CHECK((size != 0), UMF_RESULT_ERROR_INVALID_ARGUMENT); UMF_CHECK((providerIpcData != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); - return hProvider->ops.ext_get_ipc_handle(hProvider->provider_priv, ptr, - size, providerIpcData); + + umf_result_t res = UMF_RESULT_SUCCESS; + if (!hProvider->ops.ext_get_ipc_handle) { + res = UMF_RESULT_ERROR_NOT_SUPPORTED; + } else { + res = hProvider->ops.ext_get_ipc_handle(hProvider->provider_priv, ptr, + size, providerIpcData); + } + + checkErrorAndSetLastProvider(res, hProvider); + return res; } umf_result_t @@ -405,8 +462,17 @@ 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.ext_put_ipc_handle(hProvider->provider_priv, - providerIpcData); + + umf_result_t res = UMF_RESULT_SUCCESS; + if (!hProvider->ops.ext_put_ipc_handle) { + res = UMF_RESULT_ERROR_NOT_SUPPORTED; + } else { + res = hProvider->ops.ext_put_ipc_handle(hProvider->provider_priv, + providerIpcData); + } + + checkErrorAndSetLastProvider(res, hProvider); + return res; } umf_result_t @@ -415,8 +481,17 @@ umfMemoryProviderOpenIPCHandle(umf_memory_provider_handle_t hProvider, 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.ext_open_ipc_handle(hProvider->provider_priv, - providerIpcData, ptr); + + umf_result_t res = UMF_RESULT_SUCCESS; + if (!hProvider->ops.ext_open_ipc_handle) { + res = UMF_RESULT_ERROR_NOT_SUPPORTED; + } else { + res = hProvider->ops.ext_open_ipc_handle(hProvider->provider_priv, + providerIpcData, ptr); + } + + checkErrorAndSetLastProvider(res, hProvider); + return res; } umf_result_t @@ -424,6 +499,41 @@ 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.ext_close_ipc_handle(hProvider->provider_priv, ptr, - size); + UMF_CHECK((size != 0), UMF_RESULT_ERROR_INVALID_ARGUMENT); + + umf_result_t res = UMF_RESULT_SUCCESS; + if (!hProvider->ops.ext_close_ipc_handle) { + res = UMF_RESULT_ERROR_NOT_SUPPORTED; + } else { + res = hProvider->ops.ext_close_ipc_handle(hProvider->provider_priv, ptr, + size); + } + + checkErrorAndSetLastProvider(res, hProvider); + return res; +} + +umf_result_t umfMemoryProviderGetAllocationProperties( + umf_memory_provider_handle_t hProvider, const void *ptr, + umf_memory_property_id_t propertyId, size_t max_property_size, + void *property_value) { + + UMF_CHECK((hProvider != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); + UMF_CHECK((property_value != NULL), UMF_RESULT_ERROR_INVALID_ARGUMENT); + UMF_CHECK((max_property_size != 0), UMF_RESULT_ERROR_INVALID_ARGUMENT); + UMF_CHECK((propertyId >= UMF_MEMORY_PROPERTY_INVALID && + propertyId < UMF_MEMORY_PROPERTY_MAX_RESERVED), + UMF_RESULT_ERROR_INVALID_ARGUMENT); + + umf_result_t res = UMF_RESULT_SUCCESS; + if (!hProvider->ops.ext_get_allocation_properties) { + res = UMF_RESULT_ERROR_NOT_SUPPORTED; + } else { + res = hProvider->ops.ext_get_allocation_properties( + hProvider->provider_priv, ptr, propertyId, max_property_size, + property_value); + } + + checkErrorAndSetLastProvider(res, hProvider); + return res; } diff --git a/src/pool/pool_disjoint.c b/src/pool/pool_disjoint.c index 51e0e85ac..9cab51ceb 100644 --- a/src/pool/pool_disjoint.c +++ b/src/pool/pool_disjoint.c @@ -904,14 +904,19 @@ umf_result_t disjoint_pool_malloc_usable_size(void *pool, const void *ptr, critnib_release(disjoint_pool->known_slabs, ref_slab); } - umf_alloc_info_t allocInfo = {NULL, 0, NULL}; - umf_result_t ret = umfMemoryTrackerGetAllocInfo(ptr, &allocInfo); - if (ret != UMF_RESULT_SUCCESS) { - *size = 0; - return ret; + umf_memory_properties_handle_t props = NULL; + umf_result_t umf_result = umfGetMemoryPropertiesHandle(ptr, &props); + if (umf_result != UMF_RESULT_SUCCESS) { + return umf_result; + } + + if (props == NULL) { + TLS_last_allocation_error = UMF_RESULT_ERROR_UNKNOWN; + LOG_ERR("failed to get allocation info from the memory tracker"); + return UMF_RESULT_ERROR_UNKNOWN; } - *size = allocInfo.baseSize; + *size = props->base_size; return UMF_RESULT_SUCCESS; } @@ -947,15 +952,21 @@ umf_result_t disjoint_pool_free(void *pool, void *ptr) { critnib_release(disjoint_pool->known_slabs, ref_slab); } - umf_alloc_info_t allocInfo = {NULL, 0, NULL}; - umf_result_t ret = umfMemoryTrackerGetAllocInfo(ptr, &allocInfo); + umf_memory_properties_handle_t props = NULL; + umf_result_t ret = umfGetMemoryPropertiesHandle(ptr, &props); if (ret != UMF_RESULT_SUCCESS) { TLS_last_allocation_error = ret; LOG_ERR("failed to get allocation info from the memory tracker"); return ret; } - size_t size = allocInfo.baseSize; + if (props == NULL) { + TLS_last_allocation_error = UMF_RESULT_ERROR_UNKNOWN; + LOG_ERR("failed to get allocation info from the memory tracker"); + return UMF_RESULT_ERROR_UNKNOWN; + } + + size_t size = props->base_size; umf_memory_provider_handle_t provider = disjoint_pool->provider; ret = umfMemoryProviderFree(provider, ptr, size); if (ret != UMF_RESULT_SUCCESS) { diff --git a/src/pool/pool_proxy.c b/src/pool/pool_proxy.c index c6bf74124..3da9a4ee6 100644 --- a/src/pool/pool_proxy.c +++ b/src/pool/pool_proxy.c @@ -100,11 +100,22 @@ static umf_result_t proxy_free(void *pool, void *ptr) { struct proxy_memory_pool *hPool = (struct proxy_memory_pool *)pool; if (ptr) { - umf_alloc_info_t allocInfo = {NULL, 0, NULL}; - umf_result_t umf_result = umfMemoryTrackerGetAllocInfo(ptr, &allocInfo); - if (umf_result == UMF_RESULT_SUCCESS) { - size = allocInfo.baseSize; + umf_memory_properties_handle_t props = NULL; + umf_result_t umf_result = umfGetMemoryPropertiesHandle(ptr, &props); + + if (umf_result != UMF_RESULT_SUCCESS) { + TLS_last_allocation_error = umf_result; + LOG_ERR("failed to get allocation info from the memory tracker"); + return umf_result; + } + + if (props == NULL) { + TLS_last_allocation_error = UMF_RESULT_ERROR_UNKNOWN; + LOG_ERR("failed to get allocation info from the memory tracker"); + return UMF_RESULT_ERROR_UNKNOWN; } + + size = props->base_size; } return umfMemoryProviderFree(hPool->hProvider, ptr, size); diff --git a/src/provider/provider_cuda.c b/src/provider/provider_cuda.c index d024ae0ea..420c64e17 100644 --- a/src/provider/provider_cuda.c +++ b/src/provider/provider_cuda.c @@ -12,6 +12,8 @@ #include #include +#include "memory_props_internal.h" +#include "memory_provider_internal.h" #include "provider_cuda_internal.h" #include "utils_load_library.h" #include "utils_log.h" @@ -685,6 +687,45 @@ cu_memory_provider_close_ipc_handle(void *provider, void *ptr, size_t size) { return UMF_RESULT_SUCCESS; } +static umf_result_t cu_memory_provider_get_allocation_properties( + void *provider, const void *ptr, + umf_memory_property_id_t memory_property_id, size_t max_property_size, + void *value) { + + // unused + (void)ptr; + + cu_memory_provider_t *cuda_provider = (cu_memory_provider_t *)provider; + + switch (memory_property_id) { + case UMF_MEMORY_PROPERTY_POINTER_TYPE: + if (UNLIKELY(max_property_size < sizeof(umf_usm_memory_type_t))) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + *(umf_usm_memory_type_t *)value = cuda_provider->memory_type; + return UMF_RESULT_SUCCESS; + + case UMF_MEMORY_PROPERTY_CONTEXT: + if (UNLIKELY(max_property_size < sizeof(CUcontext))) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + *(CUcontext *)value = cuda_provider->context; + return UMF_RESULT_SUCCESS; + + case UMF_MEMORY_PROPERTY_DEVICE: + if (UNLIKELY(max_property_size < sizeof(CUdevice))) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + *(CUdevice *)value = cuda_provider->device; + return UMF_RESULT_SUCCESS; + + default: + break; + }; + + return UMF_RESULT_ERROR_INVALID_ARGUMENT; +} + static umf_memory_provider_ops_t UMF_CUDA_MEMORY_PROVIDER_OPS = { .version = UMF_PROVIDER_OPS_VERSION_CURRENT, .initialize = cu_memory_provider_initialize, @@ -707,6 +748,9 @@ static umf_memory_provider_ops_t UMF_CUDA_MEMORY_PROVIDER_OPS = { .ext_put_ipc_handle = cu_memory_provider_put_ipc_handle, .ext_open_ipc_handle = cu_memory_provider_open_ipc_handle, .ext_close_ipc_handle = cu_memory_provider_close_ipc_handle, + .ext_ctl = NULL, + .ext_get_allocation_properties = + cu_memory_provider_get_allocation_properties, }; const umf_memory_provider_ops_t *umfCUDAMemoryProviderOps(void) { diff --git a/src/provider/provider_devdax_memory.c b/src/provider/provider_devdax_memory.c index 995f50cf5..18dbd2d50 100644 --- a/src/provider/provider_devdax_memory.c +++ b/src/provider/provider_devdax_memory.c @@ -555,7 +555,10 @@ static umf_memory_provider_ops_t UMF_DEVDAX_MEMORY_PROVIDER_OPS = { .ext_get_ipc_handle = devdax_get_ipc_handle, .ext_put_ipc_handle = devdax_put_ipc_handle, .ext_open_ipc_handle = devdax_open_ipc_handle, - .ext_close_ipc_handle = devdax_close_ipc_handle}; + .ext_close_ipc_handle = devdax_close_ipc_handle, + .ext_ctl = NULL, + .ext_get_allocation_properties = NULL, +}; const umf_memory_provider_ops_t *umfDevDaxMemoryProviderOps(void) { return &UMF_DEVDAX_MEMORY_PROVIDER_OPS; diff --git a/src/provider/provider_file_memory.c b/src/provider/provider_file_memory.c index 78cfb2cc2..7956b3c79 100644 --- a/src/provider/provider_file_memory.c +++ b/src/provider/provider_file_memory.c @@ -882,7 +882,10 @@ static umf_memory_provider_ops_t UMF_FILE_MEMORY_PROVIDER_OPS = { .ext_get_ipc_handle = file_get_ipc_handle, .ext_put_ipc_handle = file_put_ipc_handle, .ext_open_ipc_handle = file_open_ipc_handle, - .ext_close_ipc_handle = file_close_ipc_handle}; + .ext_close_ipc_handle = file_close_ipc_handle, + .ext_ctl = NULL, + .ext_get_allocation_properties = NULL, +}; const umf_memory_provider_ops_t *umfFileMemoryProviderOps(void) { return &UMF_FILE_MEMORY_PROVIDER_OPS; diff --git a/src/provider/provider_fixed_memory.c b/src/provider/provider_fixed_memory.c index 5f047442a..b25a165cb 100644 --- a/src/provider/provider_fixed_memory.c +++ b/src/provider/provider_fixed_memory.c @@ -309,7 +309,9 @@ static umf_memory_provider_ops_t UMF_FIXED_MEMORY_PROVIDER_OPS = { .ext_put_ipc_handle = NULL, .ext_open_ipc_handle = NULL, .ext_close_ipc_handle = NULL, - .ext_ctl = fixed_ctl}; + .ext_ctl = fixed_ctl, + .ext_get_allocation_properties = NULL, +}; const umf_memory_provider_ops_t *umfFixedMemoryProviderOps(void) { return &UMF_FIXED_MEMORY_PROVIDER_OPS; diff --git a/src/provider/provider_level_zero.c b/src/provider/provider_level_zero.c index d24cef5af..a639ae730 100644 --- a/src/provider/provider_level_zero.c +++ b/src/provider/provider_level_zero.c @@ -11,9 +11,12 @@ #include #include +#include #include #include +#include "memory_props_internal.h" +#include "memory_provider_internal.h" #include "provider_ctl_stats_type.h" #include "provider_level_zero_internal.h" #include "utils_load_library.h" @@ -32,6 +35,7 @@ void fini_ze_global_state(void) { #include "base_alloc_global.h" #include "libumf.h" +#include "provider_level_zero_internal.h" #include "utils_assert.h" #include "utils_common.h" #include "utils_concurrency.h" @@ -818,6 +822,45 @@ static umf_result_t ze_ctl(void *provider, int operationType, const char *name, query_type, arg, size); } +static umf_result_t ze_memory_provider_get_allocation_properties( + void *provider, const void *ptr, + umf_memory_property_id_t memory_property_id, size_t max_property_size, + void *value) { + (void)ptr; + + struct ze_memory_provider_t *ze_provider = + (struct ze_memory_provider_t *)provider; + + switch (memory_property_id) { + case UMF_MEMORY_PROPERTY_POINTER_TYPE: + if (UNLIKELY(max_property_size < sizeof(umf_usm_memory_type_t))) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + *(umf_usm_memory_type_t *)value = + ze2umf_memory_type(ze_provider->memory_type); + return UMF_RESULT_SUCCESS; + + case UMF_MEMORY_PROPERTY_CONTEXT: + if (UNLIKELY(max_property_size < sizeof(ze_context_handle_t))) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + *(ze_context_handle_t *)value = ze_provider->context; + return UMF_RESULT_SUCCESS; + + case UMF_MEMORY_PROPERTY_DEVICE: + if (UNLIKELY(max_property_size < sizeof(ze_device_handle_t))) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + *(ze_device_handle_t *)value = ze_provider->device; + return UMF_RESULT_SUCCESS; + + default: + break; + } + + return UMF_RESULT_ERROR_INVALID_ARGUMENT; +} + static umf_memory_provider_ops_t UMF_LEVEL_ZERO_MEMORY_PROVIDER_OPS = { .version = UMF_PROVIDER_OPS_VERSION_CURRENT, .initialize = ze_memory_provider_initialize, @@ -838,6 +881,8 @@ static umf_memory_provider_ops_t UMF_LEVEL_ZERO_MEMORY_PROVIDER_OPS = { .ext_open_ipc_handle = ze_memory_provider_open_ipc_handle, .ext_close_ipc_handle = ze_memory_provider_close_ipc_handle, .ext_ctl = ze_ctl, + .ext_get_allocation_properties = + ze_memory_provider_get_allocation_properties, }; const umf_memory_provider_ops_t *umfLevelZeroMemoryProviderOps(void) { diff --git a/src/provider/provider_os_memory.c b/src/provider/provider_os_memory.c index bc6ba5241..71eb80290 100644 --- a/src/provider/provider_os_memory.c +++ b/src/provider/provider_os_memory.c @@ -1413,7 +1413,8 @@ static umf_result_t os_open_ipc_handle(void *provider, void *providerIpcData, 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"); + LOG_PERR("memory mapping failed: %zu bytes at fd=%d, offset=%zu", + os_ipc_data->size, fd, os_ipc_data->fd_offset); ret = UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC; } @@ -1471,6 +1472,7 @@ static umf_memory_provider_ops_t UMF_OS_MEMORY_PROVIDER_OPS = { .ext_open_ipc_handle = os_open_ipc_handle, .ext_close_ipc_handle = os_close_ipc_handle, .ext_ctl = os_ctl, + .ext_get_allocation_properties = NULL, }; const umf_memory_provider_ops_t *umfOsMemoryProviderOps(void) { diff --git a/src/provider/provider_tracking.c b/src/provider/provider_tracking.c index 386eef0ba..c5f4d3adf 100644 --- a/src/provider/provider_tracking.c +++ b/src/provider/provider_tracking.c @@ -15,6 +15,7 @@ #include #include +#include #include #include "base_alloc_global.h" @@ -22,6 +23,8 @@ #include "ipc_cache.h" #include "ipc_internal.h" #include "memory_pool_internal.h" +#include "memory_props_internal.h" +#include "memory_provider_internal.h" #include "provider_tracking.h" #include "utils_common.h" #include "utils_concurrency.h" @@ -32,6 +35,8 @@ uint64_t IPC_HANDLE_ID = 0; +uint64_t unique_alloc_id = 0; // requires atomic access + struct umf_memory_tracker_t { umf_ba_pool_t *alloc_info_allocator; // Multilevel maps are needed to support the case @@ -43,19 +48,8 @@ struct umf_memory_tracker_t { critnib *ipc_segments_map; }; -typedef struct tracker_alloc_info_t { - umf_memory_pool_handle_t pool; - size_t size; - // number of overlapping memory regions - // in the next level of map - // falling within the current range - size_t n_children; -#if !defined(NDEBUG) && defined(UMF_DEVELOPER_MODE) - uint64_t is_freed; -#endif -} tracker_alloc_info_t; - typedef struct tracker_ipc_info_t { + umf_memory_properties_t props; size_t size; umf_memory_provider_handle_t provider; ipc_opened_cache_value_t *ipc_cache_value; @@ -113,7 +107,8 @@ static tracker_alloc_info_t *get_most_nested_alloc_segment( continue; } - utils_atomic_load_acquire_u64((uint64_t *)&rvalue->size, &rsize); + utils_atomic_load_acquire_u64((uint64_t *)&rvalue->props.base_size, + &rsize); utils_atomic_load_acquire_size_t(&rvalue->n_children, &n_children); if (found && ((uintptr_t)ptr < rkey + rsize) && n_children) { if (level == MAX_LEVELS_OF_ALLOC_SEGMENT_MAP - 1) { @@ -192,8 +187,26 @@ umfMemoryTrackerAddAtLevel(umf_memory_tracker_handle_t hTracker, int level, return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY; } - value->pool = pool; - value->size = size; + // get provider + umf_memory_provider_handle_t provider = NULL; + umfPoolGetMemoryProvider(pool, &provider); + + // get memory type + umf_usm_memory_type_t memory_type = UMF_MEMORY_TYPE_UNKNOWN; + if (provider && provider->ops.ext_get_allocation_properties) { + provider->ops.ext_get_allocation_properties( + provider->provider_priv, ptr, UMF_MEMORY_PROPERTY_POINTER_TYPE, + sizeof(umf_usm_memory_type_t), &memory_type); + } + + memset(&value->props, 0, sizeof(umf_memory_properties_t)); + value->props.id = utils_atomic_increment_u64(&unique_alloc_id); + value->props.base = (void *)ptr; + value->props.base_size = size; + value->props.pool = pool; + value->props.provider = provider; + value->props.memory_type = memory_type; + value->n_children = 0; #if !defined(NDEBUG) && defined(UMF_DEVELOPER_MODE) value->is_freed = 0; @@ -214,8 +227,8 @@ umfMemoryTrackerAddAtLevel(umf_memory_tracker_handle_t hTracker, int level, "child #%zu added to memory region: tracker=%p, level=%i, " "pool=%p, ptr=%p, size=%zu", n_children, (void *)hTracker, level - 1, - (void *)parent_value->pool, (void *)parent_key, - parent_value->size); + (void *)parent_value->props.pool, (void *)parent_key, + parent_value->props.base_size); assert(ref_parent_value); critnib_release(hTracker->alloc_segments_map[level - 1], ref_parent_value); @@ -286,7 +299,8 @@ static umf_result_t umfMemoryTrackerAdd(umf_memory_tracker_handle_t hTracker, assert(is_freed != 0xDEADBEEF); #endif - utils_atomic_load_acquire_u64((uint64_t *)&rvalue->size, &rsize); + utils_atomic_load_acquire_u64((uint64_t *)&rvalue->props.base_size, + &rsize); if ((uintptr_t)ptr < rkey + rsize) { if (level == MAX_LEVELS_OF_ALLOC_SEGMENT_MAP - 1) { @@ -300,8 +314,8 @@ static umf_result_t umfMemoryTrackerAdd(umf_memory_tracker_handle_t hTracker, "cannot insert to the tracker value (pool=%p, ptr=%p, " "size=%zu) " "that exceeds the parent value (pool=%p, ptr=%p, size=%zu)", - (void *)pool, ptr, size, (void *)rvalue->pool, (void *)rkey, - (size_t)rsize); + (void *)pool, ptr, size, (void *)rvalue->props.pool, + (void *)rkey, (size_t)rsize); return UMF_RESULT_ERROR_INVALID_ARGUMENT; } parent_key = rkey; @@ -363,7 +377,8 @@ static umf_result_t umfMemoryTrackerRemove(umf_memory_tracker_handle_t hTracker, LOG_DEBUG("memory region removed: tracker=%p, level=%i, pool=%p, ptr=%p, " "size=%zu", - (void *)hTracker, level, (void *)value->pool, ptr, value->size); + (void *)hTracker, level, (void *)value->props.pool, ptr, + value->props.base_size); // release the reference to the value got from critnib_remove() assert(ref_value); @@ -375,8 +390,9 @@ static umf_result_t umfMemoryTrackerRemove(umf_memory_tracker_handle_t hTracker, LOG_DEBUG( "child #%zu removed from memory region: tracker=%p, level=%i, " "pool=%p, ptr=%p, size=%zu", - n_children, (void *)hTracker, level - 1, (void *)parent_value->pool, - (void *)parent_key, parent_value->size); + n_children, (void *)hTracker, level - 1, + (void *)parent_value->props.pool, (void *)parent_key, + parent_value->props.base_size); assert(ref_parent_value); assert(level >= 1); @@ -409,6 +425,13 @@ umfMemoryTrackerAddIpcSegment(umf_memory_tracker_handle_t hTracker, value->provider = provider; value->ipc_cache_value = cache_entry; + memset(&value->props, 0, sizeof(umf_memory_properties_t)); + value->props.id = utils_atomic_increment_u64(&unique_alloc_id); + value->props.base = (void *)ptr; + value->props.base_size = size; + value->props.pool = NULL; // unknown + value->props.provider = provider; + int ret = critnib_insert(hTracker->ipc_segments_map, (uintptr_t)ptr, value, 0); if (ret == 0) { @@ -458,37 +481,27 @@ umfMemoryTrackerRemoveIpcSegment(umf_memory_tracker_handle_t hTracker, return UMF_RESULT_SUCCESS; } -umf_memory_pool_handle_t umfMemoryTrackerGetPool(const void *ptr) { - umf_alloc_info_t allocInfo = {NULL, 0, NULL}; - umf_result_t ret = umfMemoryTrackerGetAllocInfo(ptr, &allocInfo); - if (ret != UMF_RESULT_SUCCESS) { - return NULL; - } - - return allocInfo.pool; -} - umf_result_t umfMemoryTrackerGetAllocInfo(const void *ptr, - umf_alloc_info_t *pAllocInfo) { - assert(pAllocInfo); + tracker_alloc_info_t **info) { + assert(info); - if (ptr == NULL) { + if (UNLIKELY(ptr == NULL)) { return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - if (TRACKER == NULL) { + if (UNLIKELY(TRACKER == NULL)) { LOG_ERR("tracker does not exist"); return UMF_RESULT_ERROR_NOT_SUPPORTED; } - if (TRACKER->alloc_segments_map[0] == NULL) { + if (UNLIKELY(TRACKER->alloc_segments_map[0] == NULL)) { LOG_ERR("tracker's alloc_segments_map does not exist"); return UMF_RESULT_ERROR_NOT_SUPPORTED; } tracker_alloc_info_t *top_most_value = NULL; tracker_alloc_info_t *rvalue = NULL; - uintptr_t top_most_key = 0; + //uintptr_t top_most_key = 0; uintptr_t rkey = 0; uint64_t rsize = 0; size_t n_children = 0; @@ -514,7 +527,7 @@ umf_result_t umfMemoryTrackerGetAllocInfo(const void *ptr, critnib_release(TRACKER->alloc_segments_map[level], ref_value); } top_most_value = NULL; - top_most_key = 0; + //top_most_key = 0; rkey = 0; rsize = 0; level = 0; @@ -525,10 +538,11 @@ umf_result_t umfMemoryTrackerGetAllocInfo(const void *ptr, continue; } - utils_atomic_load_acquire_u64((uint64_t *)&rvalue->size, &rsize); + utils_atomic_load_acquire_u64((uint64_t *)&rvalue->props.base_size, + &rsize); utils_atomic_load_acquire_size_t(&rvalue->n_children, &n_children); if (found && (uintptr_t)ptr < rkey + rsize) { - top_most_key = rkey; + //top_most_key = rkey; top_most_value = rvalue; if (ref_top_most_value) { assert(level >= 1); @@ -555,9 +569,7 @@ umf_result_t umfMemoryTrackerGetAllocInfo(const void *ptr, return UMF_RESULT_ERROR_INVALID_ARGUMENT; } - pAllocInfo->base = (void *)top_most_key; - pAllocInfo->baseSize = top_most_value->size; - pAllocInfo->pool = top_most_value->pool; + *info = top_most_value; assert(ref_top_most_value); critnib_release(TRACKER->alloc_segments_map[ref_level], ref_top_most_value); @@ -603,6 +615,8 @@ umf_result_t umfMemoryTrackerGetIpcInfo(const void *ptr, pIpcInfo->baseSize = rvalue->size; pIpcInfo->provider = rvalue->provider; + pIpcInfo->props = &rvalue->props; + if (ref_value) { critnib_release(TRACKER->ipc_segments_map, ref_value); } @@ -692,9 +706,9 @@ static umf_result_t trackingAllocationSplit(void *hProvider, void *ptr, ret = UMF_RESULT_ERROR_INVALID_ARGUMENT; goto err; } - if (value->size != totalSize) { + if (value->props.base_size != totalSize) { LOG_ERR("tracked size=%zu does not match requested size to split: %zu", - value->size, totalSize); + value->props.base_size, totalSize); ret = UMF_RESULT_ERROR_INVALID_ARGUMENT; goto err; } @@ -732,7 +746,8 @@ static umf_result_t trackingAllocationSplit(void *hProvider, void *ptr, } // update the size of the first part - utils_atomic_store_release_u64((uint64_t *)&value->size, firstSize); + utils_atomic_store_release_u64((uint64_t *)&value->props.base_size, + firstSize); critnib_release(provider->hTracker->alloc_segments_map[level], ref_value); utils_mutex_unlock(&provider->hTracker->splitMergeMutex); @@ -805,12 +820,12 @@ static umf_result_t trackingAllocationMerge(void *hProvider, void *lowPtr, ret = UMF_RESULT_ERROR_INVALID_ARGUMENT; goto err_fatal; } - if (lowValue->pool != highValue->pool) { + if (lowValue->props.pool != highValue->props.pool) { LOG_FATAL("pool mismatch"); ret = UMF_RESULT_ERROR_INVALID_ARGUMENT; goto err_fatal; } - if (lowValue->size + highValue->size != totalSize) { + if (lowValue->props.base_size + highValue->props.base_size != totalSize) { LOG_FATAL("lowValue->size + highValue->size != totalSize"); ret = UMF_RESULT_ERROR_INVALID_ARGUMENT; goto err_fatal; @@ -824,7 +839,8 @@ static umf_result_t trackingAllocationMerge(void *hProvider, void *lowPtr, } // we only need to update the size of the first part - utils_atomic_store_release_u64((uint64_t *)&lowValue->size, totalSize); + utils_atomic_store_release_u64((uint64_t *)&lowValue->props.base_size, + totalSize); size_t low_children = lowValue->n_children; size_t high_children = highValue->n_children; @@ -950,12 +966,13 @@ static void check_if_tracker_is_empty(umf_memory_tracker_handle_t hTracker, while (1 == critnib_find(hTracker->alloc_segments_map[i], last_key, FIND_G, &rkey, (void **)&rvalue, &ref_value)) { - if (rvalue && ((rvalue->pool == pool) || pool == NULL)) { + if (rvalue && ((rvalue->props.pool == pool) || pool == NULL)) { n_items++; LOG_DEBUG( "found abandoned allocation in the tracking provider: " "pool=%p, ptr=%p, size=%zu", - (void *)rvalue->pool, (void *)rkey, (size_t)rvalue->size); + (void *)rvalue->props.pool, (void *)rkey, + (size_t)rvalue->props.base_size); } if (ref_value) { @@ -1295,6 +1312,16 @@ static umf_result_t trackingCloseIpcHandle(void *provider, void *ptr, return umf_result; } +static umf_result_t +trackingGetAllocationProperties(void *provider, const void *ptr, + umf_memory_property_id_t memory_property_id, + size_t max_property_size, void *value) { + umf_tracking_memory_provider_t *p = + (umf_tracking_memory_provider_t *)provider; + return umfMemoryProviderGetAllocationProperties( + p->hUpstream, ptr, memory_property_id, max_property_size, value); +} + umf_memory_provider_ops_t UMF_TRACKING_MEMORY_PROVIDER_OPS = { .version = UMF_PROVIDER_OPS_VERSION_CURRENT, .initialize = trackingInitialize, @@ -1313,7 +1340,10 @@ umf_memory_provider_ops_t UMF_TRACKING_MEMORY_PROVIDER_OPS = { .ext_get_ipc_handle = trackingGetIpcHandle, .ext_put_ipc_handle = trackingPutIpcHandle, .ext_open_ipc_handle = trackingOpenIpcHandle, - .ext_close_ipc_handle = trackingCloseIpcHandle}; + .ext_close_ipc_handle = trackingCloseIpcHandle, + .ext_ctl = NULL, + .ext_get_allocation_properties = trackingGetAllocationProperties, +}; static void free_ipc_cache_value(void *unused, void *ipc_cache_value) { (void)unused; diff --git a/src/provider/provider_tracking.h b/src/provider/provider_tracking.h index d7ee06c1b..9b6884928 100644 --- a/src/provider/provider_tracking.h +++ b/src/provider/provider_tracking.h @@ -20,6 +20,7 @@ #include "base_alloc.h" #include "critnib.h" +#include "memory_props_internal.h" #include "utils_concurrency.h" #ifdef __cplusplus @@ -34,18 +35,23 @@ extern umf_memory_tracker_handle_t TRACKER; umf_result_t umfMemoryTrackerCreate(umf_memory_tracker_handle_t *handle); void umfMemoryTrackerDestroy(umf_memory_tracker_handle_t handle); -umf_memory_pool_handle_t umfMemoryTrackerGetPool(const void *ptr); +typedef struct tracker_alloc_info_t { + umf_memory_properties_t props; -typedef struct umf_alloc_info_t { - void *base; - size_t baseSize; - umf_memory_pool_handle_t pool; -} umf_alloc_info_t; + // number of overlapping memory regions in the next level of map falling + // within the current range + size_t n_children; +#if !defined(NDEBUG) && defined(UMF_DEVELOPER_MODE) + uint64_t is_freed; +#endif +} tracker_alloc_info_t; umf_result_t umfMemoryTrackerGetAllocInfo(const void *ptr, - umf_alloc_info_t *pAllocInfo); + tracker_alloc_info_t **info); typedef struct umf_ipc_info_t { + umf_memory_properties_handle_t props; + void *base; size_t baseSize; umf_memory_provider_handle_t provider; diff --git a/src/utils/utils_assert.h b/src/utils/utils_assert.h index 437eef932..319b8e68c 100644 --- a/src/utils/utils_assert.h +++ b/src/utils/utils_assert.h @@ -1,6 +1,6 @@ /* * - * Copyright (C) 2023-2024 Intel Corporation + * Copyright (C) 2023-2025 Intel Corporation * * Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception @@ -10,11 +10,13 @@ #ifndef UMF_ASSERT_H #define UMF_ASSERT_H 1 -#include "utils_log.h" #include #include #include +#include "utils_common.h" +#include "utils_log.h" + #ifdef __cplusplus extern "C" { #endif @@ -50,7 +52,7 @@ extern "C" { #define UMF_CHECK(condition, errorStatus) \ do { \ - if (!(condition)) { \ + if (UNLIKELY(!(condition))) { \ LOG_FATAL("UMF check failed: " #condition " in %s", __func__); \ return errorStatus; \ } \ diff --git a/src/utils/utils_common.h b/src/utils/utils_common.h index 0fa860a0e..17dd006ad 100644 --- a/src/utils/utils_common.h +++ b/src/utils/utils_common.h @@ -57,11 +57,17 @@ typedef enum umf_purge_advise_t { #define __TLS __declspec(thread) +#define LIKELY(x) (x) +#define UNLIKELY(x) (x) + #else /* Linux */ #define __TLS __thread -#endif /* _WIN32 */ +#define LIKELY(x) __builtin_expect(!!(x), 1) +#define UNLIKELY(x) __builtin_expect(!!(x), 0) + +#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); diff --git a/src/utils/utils_level_zero.cpp b/src/utils/utils_level_zero.cpp index 6daab3e69..e2b62064c 100644 --- a/src/utils/utils_level_zero.cpp +++ b/src/utils/utils_level_zero.cpp @@ -752,6 +752,18 @@ ze_memory_type_t utils_ze_get_mem_type(ze_context_handle_t context, void *ptr) { return alloc_props.type; } +void utils_ze_get_mem_props(ze_context_handle_t context, void *ptr, + ze_memory_allocation_properties_t *alloc_props, + ze_device_handle_t *device) { + alloc_props->stype = ZE_STRUCTURE_TYPE_MEMORY_ALLOCATION_PROPERTIES; + alloc_props->pNext = NULL; + alloc_props->type = ZE_MEMORY_TYPE_UNKNOWN; + alloc_props->id = 0; + alloc_props->pageSize = 0; + + libze_ops.zeMemGetAllocProperties(context, ptr, alloc_props, device); +} + int64_t utils_ze_get_num_memory_properties(ze_device_handle_t device) { uint32_t pCount = 0; ze_result_t ze_result = diff --git a/src/utils/utils_level_zero.h b/src/utils/utils_level_zero.h index 00f55b351..41e183288 100644 --- a/src/utils/utils_level_zero.h +++ b/src/utils/utils_level_zero.h @@ -44,6 +44,10 @@ 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); +void utils_ze_get_mem_props(ze_context_handle_t context, void *ptr, + ze_memory_allocation_properties_t *alloc_props, + ze_device_handle_t *device); + int64_t utils_ze_get_num_memory_properties(ze_device_handle_t device); #ifdef __cplusplus diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a56d29934..f9a71754e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -54,11 +54,13 @@ function(build_umf_test) if(UMF_CUDA_ENABLED) set(INC_DIRS ${INC_DIRS} ${CUDA_INCLUDE_DIRS}) set(LIB_DIRS ${LIB_DIRS} ${CUDA_LIBRARY_DIRS}) + set(CPL_DEFS ${CPL_DEFS} UMF_CUDA_ENABLED=1) endif() if(UMF_LEVEL_ZERO_ENABLED) set(INC_DIRS ${INC_DIRS} ${LEVEL_ZERO_INCLUDE_DIRS}) set(LIB_DIRS ${LIB_DIRS} ${ZE_LOADER_LIBRARY_DIRS}) + set(CPL_DEFS ${CPL_DEFS} UMF_LEVEL_ZERO_ENABLED=1) endif() if(NOT UMF_DISABLE_HWLOC) @@ -363,6 +365,10 @@ if(LINUX AND (NOT UMF_DISABLE_HWLOC)) # OS-specific functions are implemented NAME provider_tracking_fixture_tests SRCS provider_tracking_fixture_tests.cpp malloc_compliance_tests.cpp LIBS ${UMF_UTILS_FOR_TEST} ${UMF_BA_FOR_TEST}) + add_umf_test( + NAME provider_props + SRCS props/provider_props.cpp + LIBS ${UMF_UTILS_FOR_TEST} ${UMF_BA_FOR_TEST}) # This test requires Linux-only file memory provider if(UMF_POOL_JEMALLOC_ENABLED) @@ -434,6 +440,12 @@ if(UMF_BUILD_GPU_TESTS AND UMF_LEVEL_ZERO_ENABLED) LIBS ${UMF_UTILS_FOR_TEST} ${UMF_BA_FOR_TEST}) target_compile_definitions(test_provider_level_zero_dlopen_local PUBLIC USE_DLOPEN=1 OPEN_ZE_LIBRARY_GLOBAL=0) + + add_umf_test( + NAME provider_props_level_zero + SRCS props/provider_props_level_zero.cpp + ${UMF_UTILS_DIR}/utils_level_zero.cpp + LIBS ${UMF_UTILS_FOR_TEST} ${UMF_BA_FOR_TEST} ze_loader) endif() if(NOT UMF_BUILD_LEVEL_ZERO_PROVIDER) @@ -466,6 +478,11 @@ if(UMF_BUILD_GPU_TESTS AND UMF_BUILD_CUDA_PROVIDER) LIBS ${UMF_UTILS_FOR_TEST} ${UMF_BA_FOR_TEST}) target_compile_definitions(test_provider_cuda_dlopen_local PUBLIC USE_DLOPEN=1 OPEN_CU_LIBRARY_GLOBAL=0) + + add_umf_test( + NAME provider_props_cuda + SRCS props/provider_props_cuda.cpp providers/cuda_helpers.cpp + LIBS ${UMF_UTILS_FOR_TEST} ${UMF_BA_FOR_TEST} cuda) else() message( STATUS diff --git a/test/common/pool_null.c b/test/common/pool_null.c index ccabfee56..60433bee6 100644 --- a/test/common/pool_null.c +++ b/test/common/pool_null.c @@ -5,9 +5,10 @@ #include #include -#include "pool_null.h" #include +#include "pool_null.h" + static umf_result_t nullInitialize(umf_memory_provider_handle_t provider, const void *params, void **pool) { (void)provider; diff --git a/test/common/pool_trace.c b/test/common/pool_trace.c index ce944479f..04b2ded88 100644 --- a/test/common/pool_trace.c +++ b/test/common/pool_trace.c @@ -5,9 +5,10 @@ #include #include -#include "pool_trace.h" #include +#include "pool_trace.h" + typedef struct trace_pool { umf_pool_trace_params_t params; } trace_pool_t; diff --git a/test/common/provider_null.c b/test/common/provider_null.c index 380cba47d..5940e4565 100644 --- a/test/common/provider_null.c +++ b/test/common/provider_null.c @@ -5,9 +5,11 @@ #include #include -#include "provider_null.h" +#include #include +#include "provider_null.h" + static umf_result_t nullInitialize(const void *params, void **pool) { (void)params; *pool = NULL; @@ -133,6 +135,18 @@ static umf_result_t nullCloseIpcHandle(void *provider, void *ptr, size_t size) { return UMF_RESULT_SUCCESS; } +static umf_result_t +nullGetAllocationProperties(void *provider, const void *ptr, + umf_memory_property_id_t propertyId, + size_t max_property_size, void *value) { + (void)provider; + (void)ptr; + (void)propertyId; + (void)max_property_size; + (void)value; + return UMF_RESULT_SUCCESS; +} + umf_memory_provider_ops_t UMF_NULL_PROVIDER_OPS = { .version = UMF_PROVIDER_OPS_VERSION_CURRENT, .initialize = nullInitialize, @@ -152,4 +166,5 @@ umf_memory_provider_ops_t UMF_NULL_PROVIDER_OPS = { .ext_put_ipc_handle = nullPutIpcHandle, .ext_open_ipc_handle = nullOpenIpcHandle, .ext_close_ipc_handle = nullCloseIpcHandle, + .ext_get_allocation_properties = nullGetAllocationProperties, }; diff --git a/test/common/provider_trace.c b/test/common/provider_trace.c index adb808336..71674edec 100644 --- a/test/common/provider_trace.c +++ b/test/common/provider_trace.c @@ -195,6 +195,20 @@ static umf_result_t traceCloseIpcHandle(void *provider, void *ptr, ptr, size); } +static umf_result_t +traceGetAllocationProperties(void *provider, const void *ptr, + umf_memory_property_id_t memory_property_id, + size_t max_property_size, void *property_value) { + umf_provider_trace_params_t *traceProvider = + (umf_provider_trace_params_t *)provider; + + traceProvider->trace_handler(traceProvider->trace_context, + "get_allocation_properties"); + return umfMemoryProviderGetAllocationProperties( + traceProvider->hUpstreamProvider, ptr, memory_property_id, + max_property_size, property_value); +} + umf_memory_provider_ops_t UMF_TRACE_PROVIDER_OPS = { .version = UMF_PROVIDER_OPS_VERSION_CURRENT, .initialize = traceInitialize, @@ -214,4 +228,6 @@ umf_memory_provider_ops_t UMF_TRACE_PROVIDER_OPS = { .ext_put_ipc_handle = tracePutIpcHandle, .ext_open_ipc_handle = traceOpenIpcHandle, .ext_close_ipc_handle = traceCloseIpcHandle, + .ext_ctl = NULL, + .ext_get_allocation_properties = traceGetAllocationProperties, }; diff --git a/test/common/test_helpers.h b/test/common/test_helpers.h index 494528b57..4f1318c55 100644 --- a/test/common/test_helpers.h +++ b/test/common/test_helpers.h @@ -1,4 +1,4 @@ -// Copyright (C) 2023-2024 Intel Corporation +// Copyright (C) 2023-2025 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 @@ -9,8 +9,10 @@ #include #include #include + #include #include +#include #include #include "provider_trace.h" diff --git a/test/memoryProviderAPI.cpp b/test/memoryProviderAPI.cpp index 33e298dc6..7e8c93940 100644 --- a/test/memoryProviderAPI.cpp +++ b/test/memoryProviderAPI.cpp @@ -94,6 +94,14 @@ TEST_F(test, memoryProviderTrace) { ASSERT_EQ(ret, UMF_RESULT_SUCCESS); ASSERT_EQ(calls["allocation_split"], 1UL); ASSERT_EQ(calls.size(), ++call_count); + + umf_memory_provider_handle_t provider = nullptr; + ret = umfMemoryProviderGetAllocationProperties( + tracingProvider.get(), ptr, UMF_MEMORY_PROPERTY_PROVIDER_HANDLE, + sizeof(void *), &provider); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_EQ(calls["get_allocation_properties"], 1UL); + ASSERT_EQ(calls.size(), ++call_count); } TEST_F(test, memoryProviderOpsNullPurgeLazyField) { @@ -330,6 +338,21 @@ TEST_F(test, memoryProviderOpsNullAllocationSplitAllocationMergeNegative) { umfMemoryProviderDestroy(hProvider); } +TEST_F(test, memoryProviderOpsNullGetAllocationProperties) { + umf_memory_provider_ops_t provider_ops = UMF_NULL_PROVIDER_OPS; + umf_memory_provider_handle_t hProvider; + + umf_result_t ret = + umfMemoryProviderCreate(&provider_ops, nullptr, &hProvider); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + + ret = umfMemoryProviderGetAllocationProperties( + hProvider, nullptr, UMF_MEMORY_PROPERTY_PROVIDER_HANDLE, 0, nullptr); + ASSERT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + umfMemoryProviderDestroy(hProvider); +} + struct providerInitializeTest : umf_test::test, ::testing::WithParamInterface {}; @@ -389,4 +412,5 @@ INSTANTIATE_TEST_SUITE_P( umf_test::withGeneratedArgs(umfMemoryProviderGetMinPageSize), umf_test::withGeneratedArgs(umfMemoryProviderPurgeLazy), umf_test::withGeneratedArgs(umfMemoryProviderPurgeForce), - umf_test::withGeneratedArgs(umfMemoryProviderGetName))); + umf_test::withGeneratedArgs(umfMemoryProviderGetName), + umf_test::withGeneratedArgs(umfMemoryProviderGetAllocationProperties))); diff --git a/test/props/provider_props.cpp b/test/props/provider_props.cpp new file mode 100644 index 000000000..a9e6865e9 --- /dev/null +++ b/test/props/provider_props.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2025 Intel Corporation + * + * Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +*/ + +#include "provider_props.hpp" + +void createFixedProvider(umf_memory_provider_handle_t *out_provider, + void *out_data) { + constexpr size_t buffer_size = 1024 * 1024; + + void *memory_buffer = malloc(buffer_size); + ASSERT_NE(memory_buffer, nullptr); + + umf_fixed_memory_provider_params_handle_t params = nullptr; + umf_result_t res = + umfFixedMemoryProviderParamsCreate(memory_buffer, buffer_size, ¶ms); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); + ASSERT_NE(params, nullptr); + + res = umfMemoryProviderCreate(umfFixedMemoryProviderOps(), params, + out_provider); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); + ASSERT_NE(out_provider, nullptr); + + umfFixedMemoryProviderParamsDestroy(params); + + *(uintptr_t *)out_data = (uintptr_t)memory_buffer; +} + +void destroyFixedProvider(umf_memory_provider_handle_t provider, void *data) { + umfMemoryProviderDestroy(provider); + free(data); +} + +void createOsMemoryProvider(umf_memory_provider_handle_t *out_provider, + void *out_data) { + + umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr; + umf_result_t res = + umfOsMemoryProviderParamsCreate(&os_memory_provider_params); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); + ASSERT_NE(os_memory_provider_params, nullptr); + + umf_memory_provider_handle_t os_memory_provider = nullptr; + res = + umfMemoryProviderCreate(umfOsMemoryProviderOps(), + os_memory_provider_params, &os_memory_provider); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); + ASSERT_NE(os_memory_provider, nullptr); + + res = umfOsMemoryProviderParamsDestroy(os_memory_provider_params); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); + + *out_provider = os_memory_provider; + *(uintptr_t *)out_data = (uintptr_t)NULL; +} + +void destroyOsMemoryProvider(umf_memory_provider_handle_t provider, + void *data) { + (void)data; // unused + + umfMemoryProviderDestroy(provider); +} + +INSTANTIATE_TEST_SUITE_P( + providerPropsTest, ProviderPropsTest, + ::testing::Values(testParams{createFixedProvider, destroyFixedProvider, + "fixedProvider"}, + testParams{createOsMemoryProvider, + destroyOsMemoryProvider, "osMemoryProvider"}), + nameGen); diff --git a/test/props/provider_props.hpp b/test/props/provider_props.hpp new file mode 100644 index 000000000..5a9ba67c9 --- /dev/null +++ b/test/props/provider_props.hpp @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2025 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 "base.hpp" +#include "test_helpers.h" + +using umf_test::test; + +using testParams = + std::tuple, + std::function, + const char *>; + +std::string nameGen(const testing::TestParamInfo param) { + return std::get<2>(param.param); +} + +struct ProviderPropsTest : umf_test::test, + ::testing::WithParamInterface { + void SetUp() override { + test::SetUp(); + + auto [create_fun, destroy_fun, name] = this->GetParam(); + provider_create = create_fun; + provider_destroy = destroy_fun; + (void)name; // unused + + provider_create(&provider, &data); + ASSERT_NE(provider, nullptr); + + umf_result_t umf_result = + umfPoolCreate(umfProxyPoolOps(), provider, nullptr, 0, &pool); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + } + + void TearDown() override { + umfPoolDestroy(pool); + provider_destroy(provider, data); + test::TearDown(); + } + + umf_memory_provider_handle_t provider; + umf_memory_pool_handle_t pool; + + std::function provider_create; + std::function provider_destroy; + void *data; +}; + +TEST_P(ProviderPropsTest, genericProps) { + umf_result_t umf_result; + const size_t alloc_size = 8; + + void *ptr = umfPoolMalloc(pool, alloc_size); + ASSERT_NE(ptr, nullptr); + + umf_memory_properties_handle_t props_handle = nullptr; + umf_result = umfGetMemoryPropertiesHandle(ptr, &props_handle); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(props_handle, nullptr); + + umf_memory_provider_handle_t param_provider = nullptr; + umf_result = + umfGetMemoryProperty(props_handle, UMF_MEMORY_PROPERTY_PROVIDER_HANDLE, + sizeof(param_provider), ¶m_provider); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_EQ(param_provider, provider); + + umf_memory_pool_handle_t param_pool = nullptr; + umf_result = + umfGetMemoryProperty(props_handle, UMF_MEMORY_PROPERTY_POOL_HANDLE, + sizeof(param_pool), ¶m_pool); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_EQ(param_pool, pool); + + void *base_address = nullptr; + umf_result = + umfGetMemoryProperty(props_handle, UMF_MEMORY_PROPERTY_BASE_ADDRESS, + sizeof(base_address), &base_address); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_EQ(base_address, ptr); + + size_t size = 0; + umf_result = umfGetMemoryProperty( + props_handle, UMF_MEMORY_PROPERTY_BASE_SIZE, sizeof(size), &size); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_EQ(size, alloc_size); + + uint64_t buffer_id = 0; + umf_result = + umfGetMemoryProperty(props_handle, UMF_MEMORY_PROPERTY_BUFFER_ID, + sizeof(buffer_id), &buffer_id); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_GE(buffer_id, 0); + + umf_result = umfPoolFree(pool, ptr); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); +} + +TEST_P(ProviderPropsTest, baseAddressFromMiddle) { + umf_result_t umf_result; + const size_t alloc_size = 8; + + void *ptr = umfPoolMalloc(pool, alloc_size); + ASSERT_NE(ptr, nullptr); + + void *ptr_mid = (void *)((uintptr_t)ptr + (alloc_size / 2)); + umf_memory_properties_handle_t props_handle = nullptr; + umf_result = umfGetMemoryPropertiesHandle(ptr_mid, &props_handle); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(props_handle, nullptr); + + uintptr_t param_base_address = 0; + umf_result = + umfGetMemoryProperty(props_handle, UMF_MEMORY_PROPERTY_BASE_ADDRESS, + sizeof(param_base_address), ¶m_base_address); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_EQ(param_base_address, (uintptr_t)ptr); + + umf_result = umfPoolFree(pool, ptr); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); +} + +TEST_P(ProviderPropsTest, uniqueBufferId) { + size_t alloc_size = 8; + size_t num_allocs = 10; + umf_result_t umf_result; + std::set buffer_ids; + + for (size_t i = 0; i < num_allocs; ++i) { + void *ptr = umfPoolMalloc(pool, alloc_size); + ASSERT_NE(ptr, nullptr); + + umf_memory_properties_handle_t props_handle = nullptr; + umf_result = umfGetMemoryPropertiesHandle(ptr, &props_handle); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(props_handle, nullptr); + + uint64_t buffer_id = 0; + umf_result = + umfGetMemoryProperty(props_handle, UMF_MEMORY_PROPERTY_BUFFER_ID, + sizeof(buffer_id), &buffer_id); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_GE(buffer_id, 0); + + // Ensure that the buffer ID is unique by inserting it into a set and + // checking if it was already present + ASSERT_TRUE(buffer_ids.find(buffer_id) == buffer_ids.end()); + ASSERT_TRUE(buffer_ids.insert(buffer_id).second); + + umf_result = umfPoolFree(pool, ptr); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + } +} + +// Negative tests + +TEST_P(ProviderPropsTest, invalidPointer) { + umf_memory_properties_handle_t props_handle = nullptr; + umf_result_t umf_result = + umfGetMemoryPropertiesHandle(nullptr, &props_handle); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); + ASSERT_EQ(props_handle, nullptr); + + uintptr_t invalid_ptr = 0xdeadbeef; + umf_result = + umfGetMemoryPropertiesHandle((void *)invalid_ptr, &props_handle); + ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT); + ASSERT_EQ(props_handle, nullptr); +} + +TEST_P(ProviderPropsTest, invalidPropertyId) { + void *ptr = umfPoolMalloc(pool, 8); + ASSERT_NE(ptr, nullptr); + + umf_memory_properties_handle_t props_handle = nullptr; + umf_result_t res = umfGetMemoryPropertiesHandle(ptr, &props_handle); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); + ASSERT_NE(props_handle, nullptr); + + void *value = nullptr; + res = umfGetMemoryProperty(props_handle, UMF_MEMORY_PROPERTY_INVALID, + sizeof(value), &value); + ASSERT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + res = umfPoolFree(pool, ptr); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); +} + +TEST_P(ProviderPropsTest, invalidPropertyValue) { + void *ptr = umfPoolMalloc(pool, 8); + ASSERT_NE(ptr, nullptr); + + umf_memory_properties_handle_t props_handle = nullptr; + umf_result_t res = umfGetMemoryPropertiesHandle(ptr, &props_handle); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); + ASSERT_NE(props_handle, nullptr); + + res = umfGetMemoryProperty(props_handle, UMF_MEMORY_PROPERTY_BASE_ADDRESS, + sizeof(int), NULL); + ASSERT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + res = umfPoolFree(pool, ptr); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); +} + +TEST_P(ProviderPropsTest, invalidPropertySize) { + void *ptr = umfPoolMalloc(pool, 8); + ASSERT_NE(ptr, nullptr); + + umf_memory_properties_handle_t props_handle = nullptr; + umf_result_t res = umfGetMemoryPropertiesHandle(ptr, &props_handle); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); + ASSERT_NE(props_handle, nullptr); + + int value = 0; + res = umfGetMemoryProperty(props_handle, UMF_MEMORY_PROPERTY_BASE_ADDRESS, + size_t(0), &value); + ASSERT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT); + + res = umfPoolFree(pool, ptr); + ASSERT_EQ(res, UMF_RESULT_SUCCESS); +} + +TEST_P(ProviderPropsTest, nullPropertiesHandle) { + int val = 0; + umf_result_t res = umfGetMemoryProperty( + NULL, UMF_MEMORY_PROPERTY_BASE_ADDRESS, sizeof(val), &val); + ASSERT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT); +} diff --git a/test/props/provider_props_cuda.cpp b/test/props/provider_props_cuda.cpp new file mode 100644 index 000000000..19655ef21 --- /dev/null +++ b/test/props/provider_props_cuda.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2025 Intel Corporation + * + * Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +*/ + +#include "provider_props.hpp" +#include "providers/cuda_helpers.h" + +void createCudaMemoryProvider(umf_memory_provider_handle_t *out_provider, + void *out_data) { + CUdevice hDevice = -1; + CUcontext hContext = NULL; + + int ret = init_cuda(); + ASSERT_EQ(ret, 0); + + ret = get_cuda_device(&hDevice); + ASSERT_EQ(ret, 0); + ASSERT_NE(hDevice, -1); + + ret = create_context(hDevice, &hContext); + ASSERT_EQ(ret, 0); + ASSERT_NE(hContext, nullptr); + + umf_cuda_memory_provider_params_handle_t cu_params = NULL; + umf_result_t umf_result = umfCUDAMemoryProviderParamsCreate(&cu_params); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(cu_params, nullptr); + + umf_result = umfCUDAMemoryProviderParamsSetContext(cu_params, hContext); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_result = umfCUDAMemoryProviderParamsSetDevice(cu_params, hDevice); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_result = umfCUDAMemoryProviderParamsSetMemoryType( + cu_params, UMF_MEMORY_TYPE_DEVICE); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + umf_memory_provider_handle_t provider = nullptr; + umf_result = umfMemoryProviderCreate(umfCUDAMemoryProviderOps(), cu_params, + &provider); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(provider, nullptr); + + umfCUDAMemoryProviderParamsDestroy(cu_params); + + *out_provider = provider; + *(uintptr_t *)out_data = (uintptr_t)hContext; +} + +void destroyCudaMemoryProvider(umf_memory_provider_handle_t provider, + void *data) { + destroy_context((CUcontext)data); + umfMemoryProviderDestroy(provider); +} + +// todo provider ex +INSTANTIATE_TEST_SUITE_P(providerPropsTest, ProviderPropsTest, + ::testing::Values(testParams{createCudaMemoryProvider, + destroyCudaMemoryProvider, + "cudaMemoryProvider"}), + nameGen); diff --git a/test/props/provider_props_level_zero.cpp b/test/props/provider_props_level_zero.cpp new file mode 100644 index 000000000..23f1bbc4e --- /dev/null +++ b/test/props/provider_props_level_zero.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2025 Intel Corporation + * + * Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +*/ + +#include "provider_props.hpp" +#include "utils/utils_level_zero.h" + +void levelZeroMemoryProviderCreate(umf_memory_provider_handle_t *out_provider, + void *out_data) { + + ze_driver_handle_t hDriver = nullptr; + ze_device_handle_t hDevice = nullptr; + ze_context_handle_t hContext = nullptr; + uint32_t driver_idx = 0; + + int ret = utils_ze_init_level_zero(); + ASSERT_EQ(ret, 0); + + ret = utils_ze_find_driver_with_gpu(&driver_idx, &hDriver); + ASSERT_EQ(ret, 0); + + ret = utils_ze_find_gpu_device(hDriver, &hDevice); + ASSERT_EQ(ret, 0); + + ret = utils_ze_create_context(hDriver, &hContext); + ASSERT_EQ(ret, 0); + + umf_level_zero_memory_provider_params_handle_t params = nullptr; + umf_result_t result = umfLevelZeroMemoryProviderParamsCreate(¶ms); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + result = umfLevelZeroMemoryProviderParamsSetContext(params, hContext); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + result = umfLevelZeroMemoryProviderParamsSetDevice(params, hDevice); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + result = umfLevelZeroMemoryProviderParamsSetMemoryType( + params, UMF_MEMORY_TYPE_DEVICE); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + + umf_memory_provider_handle_t provider = nullptr; + umf_result_t umf_result = umfMemoryProviderCreate( + umfLevelZeroMemoryProviderOps(), params, &provider); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(provider, nullptr); + + result = umfLevelZeroMemoryProviderParamsDestroy(params); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + + *out_provider = provider; + *(uintptr_t *)out_data = (uintptr_t)hContext; +} + +void levelZeroMemoryProviderDestroy(umf_memory_provider_handle_t provider, + void *data) { + umfMemoryProviderDestroy(provider); + utils_ze_destroy_context((ze_context_handle_t)data); +} + +INSTANTIATE_TEST_SUITE_P(providerPropsTest, ProviderPropsTest, + ::testing::Values(testParams{ + levelZeroMemoryProviderCreate, + levelZeroMemoryProviderDestroy, + "levelZeroProvider"}), + nameGen); diff --git a/test/providers/provider_cuda.cpp b/test/providers/provider_cuda.cpp index 9b0d29f4b..a5ccd724d 100644 --- a/test/providers/provider_cuda.cpp +++ b/test/providers/provider_cuda.cpp @@ -9,6 +9,7 @@ #include +#include #include #include "cuda_helpers.h" @@ -496,6 +497,87 @@ TEST_P(umfCUDAProviderTest, multiContext) { ASSERT_EQ(ret, 0); } +TEST_P(umfCUDAProviderTest, memProps) { + umf_memory_provider_handle_t provider = nullptr; + umf_result_t umf_result = + umfMemoryProviderCreate(umfCUDAMemoryProviderOps(), params, &provider); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(provider, nullptr); + + umf_memory_pool_handle_t pool = NULL; + umf_result = umfPoolCreate(umfProxyPoolOps(), provider, NULL, 0, &pool); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + size_t size = 1024; + void *ptr = umfPoolMalloc(pool, size); + ASSERT_NE(ptr, nullptr); + + umf_memory_properties_handle_t props_handle = NULL; + umf_result_t result = umfGetMemoryPropertiesHandle(ptr, &props_handle); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + ASSERT_NE(props_handle, nullptr); + + umf_usm_memory_type_t type = UMF_MEMORY_TYPE_UNKNOWN; + result = umfGetMemoryProperty( + props_handle, UMF_MEMORY_PROPERTY_POINTER_TYPE, sizeof(type), &type); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + ASSERT_EQ(type, expected_memory_type); + + void *baseAddress = nullptr; + result = + umfGetMemoryProperty(props_handle, UMF_MEMORY_PROPERTY_BASE_ADDRESS, + sizeof(baseAddress), &baseAddress); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + ASSERT_EQ(baseAddress, ptr); + + size_t baseSize = 0; + result = umfGetMemoryProperty(props_handle, UMF_MEMORY_PROPERTY_BASE_SIZE, + sizeof(baseSize), &baseSize); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + ASSERT_GE(baseSize, size); + + int64_t bufferId = 0; + result = umfGetMemoryProperty(props_handle, UMF_MEMORY_PROPERTY_BUFFER_ID, + sizeof(bufferId), &bufferId); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + ASSERT_GE(bufferId, 0); + + if (expected_memory_type != UMF_MEMORY_TYPE_HOST) { + CUdevice device = -1; + result = umfGetMemoryProperty(props_handle, UMF_MEMORY_PROPERTY_DEVICE, + sizeof(device), &device); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + ASSERT_EQ(device, cudaTestHelper.get_test_device()); + } + + CUcontext context = nullptr; + result = umfGetMemoryProperty(props_handle, UMF_MEMORY_PROPERTY_CONTEXT, + sizeof(context), &context); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + ASSERT_EQ(context, cudaTestHelper.get_test_context()); + + // check the props of pointer from the middle of alloc + void *midPtr = static_cast(ptr) + size / 2; + result = umfGetMemoryPropertiesHandle(midPtr, &props_handle); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + ASSERT_NE(props_handle, nullptr); + result = umfGetMemoryProperty( + props_handle, UMF_MEMORY_PROPERTY_POINTER_TYPE, sizeof(type), &type); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + ASSERT_EQ(type, expected_memory_type); + + result = + umfGetMemoryProperty(props_handle, UMF_MEMORY_PROPERTY_BASE_ADDRESS, + sizeof(baseAddress), &baseAddress); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + ASSERT_EQ(baseAddress, ptr); + + umfFree(ptr); + + umfPoolDestroy(pool); + umfMemoryProviderDestroy(provider); +} + struct umfCUDAProviderAllocFlagsTest : umf_test::test, ::testing::WithParamInterface< diff --git a/test/providers/provider_level_zero.cpp b/test/providers/provider_level_zero.cpp index d6d479a14..8629989f0 100644 --- a/test/providers/provider_level_zero.cpp +++ b/test/providers/provider_level_zero.cpp @@ -9,6 +9,7 @@ #include +#include #include #include "ipcFixtures.hpp" @@ -246,6 +247,7 @@ struct umfLevelZeroProviderTest test::SetUp(); umf_usm_memory_type_t memory_type = this->GetParam(); + umfExpectedMemoryType = memory_type; params = nullptr; memAccessor = nullptr; @@ -298,6 +300,7 @@ struct umfLevelZeroProviderTest std::unique_ptr memAccessor = nullptr; ze_context_handle_t hContext = nullptr; ze_memory_type_t zeMemoryTypeExpected = ZE_MEMORY_TYPE_UNKNOWN; + umf_usm_memory_type_t umfExpectedMemoryType = UMF_MEMORY_TYPE_UNKNOWN; }; GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(umfLevelZeroProviderTest); @@ -484,6 +487,89 @@ TEST_P(umfLevelZeroProviderTest, setDeviceOrdinalValid) { } } +TEST_P(umfLevelZeroProviderTest, memProps) { + umf_memory_provider_handle_t provider = nullptr; + umf_result_t umf_result = umfMemoryProviderCreate( + umfLevelZeroMemoryProviderOps(), params, &provider); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + ASSERT_NE(provider, nullptr); + + umf_memory_pool_handle_t pool = NULL; + umf_result = umfPoolCreate(umfProxyPoolOps(), provider, NULL, 0, &pool); + ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS); + + size_t size = 1024; + void *ptr = umfPoolMalloc(pool, size); + ASSERT_NE(ptr, nullptr); + + umf_memory_properties_handle_t props_handle = NULL; + umf_result_t result = umfGetMemoryPropertiesHandle(ptr, &props_handle); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + ASSERT_NE(props_handle, nullptr); + + umf_usm_memory_type_t type = UMF_MEMORY_TYPE_UNKNOWN; + result = umfGetMemoryProperty( + props_handle, UMF_MEMORY_PROPERTY_POINTER_TYPE, sizeof(type), &type); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + ASSERT_EQ(type, umfExpectedMemoryType); + + // TODO move generic tests for memory properties to some common code + // base address and size + void *baseAddress = nullptr; + result = + umfGetMemoryProperty(props_handle, UMF_MEMORY_PROPERTY_BASE_ADDRESS, + sizeof(baseAddress), &baseAddress); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + ASSERT_EQ(baseAddress, ptr); + + size_t baseSize = 0; + result = umfGetMemoryProperty(props_handle, UMF_MEMORY_PROPERTY_BASE_SIZE, + sizeof(baseSize), &baseSize); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + ASSERT_GE(baseSize, size); + + int64_t bufferId = 0; + result = umfGetMemoryProperty(props_handle, UMF_MEMORY_PROPERTY_BUFFER_ID, + sizeof(bufferId), &bufferId); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + ASSERT_GE(bufferId, 0); + + if (umfExpectedMemoryType != UMF_MEMORY_TYPE_HOST) { + ze_device_handle_t device = nullptr; + result = umfGetMemoryProperty(props_handle, UMF_MEMORY_PROPERTY_DEVICE, + sizeof(device), &device); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + ASSERT_EQ(device, l0TestHelper.get_test_device()); + } + + ze_context_handle_t context = nullptr; + result = umfGetMemoryProperty(props_handle, UMF_MEMORY_PROPERTY_CONTEXT, + sizeof(context), &context); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + ASSERT_EQ(context, l0TestHelper.get_test_context()); + + // check the props of pointer from the middle of alloc + void *midPtr = static_cast(ptr) + size / 2; + result = umfGetMemoryPropertiesHandle(midPtr, &props_handle); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + ASSERT_NE(props_handle, nullptr); + result = umfGetMemoryProperty( + props_handle, UMF_MEMORY_PROPERTY_POINTER_TYPE, sizeof(type), &type); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + ASSERT_EQ(type, umfExpectedMemoryType); + + result = + umfGetMemoryProperty(props_handle, UMF_MEMORY_PROPERTY_BASE_ADDRESS, + sizeof(baseAddress), &baseAddress); + ASSERT_EQ(result, UMF_RESULT_SUCCESS); + ASSERT_EQ(baseAddress, ptr); + + umfFree(ptr); + + umfPoolDestroy(pool); + umfMemoryProviderDestroy(provider); +} + // TODO add tests that mixes Level Zero Memory Provider and Disjoint Pool INSTANTIATE_TEST_SUITE_P(umfLevelZeroProviderTestSuite,