diff --git a/include/umf/memspace.h b/include/umf/memspace.h index 2d2d77728..10cf0417d 100644 --- a/include/umf/memspace.h +++ b/include/umf/memspace.h @@ -14,6 +14,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -84,6 +85,21 @@ umf_const_memspace_handle_t umfMemspaceHighestBandwidthGet(void); /// umf_const_memspace_handle_t umfMemspaceLowestLatencyGet(void); +/// \brief Returns number of memory targets in memspace. +/// \param hMemspace handle to memspace +/// \return number of memory targets in memspace +/// +size_t umfMemspaceMemtargetNum(umf_const_memspace_handle_t hMemspace); + +/// \brief Returns memory target by index. +/// \param hMemspace handle to memspace +/// \param targetNum index of the memory target +/// \return memory target handle on success or NULL on invalid input. +/// +umf_const_memtarget_handle_t +umfMemspaceMemtargetGet(umf_const_memspace_handle_t hMemspace, + unsigned targetNum); + #ifdef __cplusplus } #endif diff --git a/include/umf/memtarget.h b/include/umf/memtarget.h index 47f938691..2a7850015 100644 --- a/include/umf/memtarget.h +++ b/include/umf/memtarget.h @@ -10,6 +10,8 @@ #ifndef UMF_MEMTARGET_H #define UMF_MEMTARGET_H 1 +#include + #ifdef __cplusplus extern "C" { #endif @@ -17,6 +19,18 @@ extern "C" { typedef struct umf_memtarget_t *umf_memtarget_handle_t; typedef const struct umf_memtarget_t *umf_const_memtarget_handle_t; +typedef enum umf_memtarget_type_t { + UMF_MEMTARGET_TYPE_UNKNOWN = 0, + UMF_MEMTARGET_TYPE_NUMA = 1, +} umf_memtarget_type_t; + +/// \brief Gets the type of the memory target. +/// \param hMemtarget handle to the memory target +/// \param type [out] type of the memory target +/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure. +umf_result_t umfMemtargetGetType(umf_const_memtarget_handle_t hMemtarget, + umf_memtarget_type_t *type); + #ifdef __cplusplus } #endif diff --git a/scripts/docs_config/api.rst b/scripts/docs_config/api.rst index 1233f59f7..ea0912785 100644 --- a/scripts/docs_config/api.rst +++ b/scripts/docs_config/api.rst @@ -116,6 +116,15 @@ Mempolicy .. doxygenfile:: mempolicy.h :sections: define enum typedef func +Memtarget +========================================== + +TODO: Add general information about memtarges. + +Memtarget +------------------------------------------ +.. doxygenfile:: memtarget.h + :sections: define enum typedef func Inter-Process Communication ========================================== diff --git a/src/libumf.def.in b/src/libumf.def.in index 8ee99e024..00a1995ae 100644 --- a/src/libumf.def.in +++ b/src/libumf.def.in @@ -41,6 +41,9 @@ EXPORTS umfMempolicySetCustomSplitPartitions umfMempolicySetInterleavePartSize umfMemspaceDestroy + umfMemspaceMemtargetNum + umfMemspaceMemtargetGet + umfMemtargetGetType umfOpenIPCHandle umfOsMemoryProviderOps umfPoolAlignedMalloc diff --git a/src/libumf.map b/src/libumf.map index cb09cdb94..2dc6956c9 100644 --- a/src/libumf.map +++ b/src/libumf.map @@ -37,10 +37,13 @@ UMF_1.0 { umfMempolicySetInterleavePartSize; umfMemspaceCreateFromNumaArray; umfMemspaceDestroy; + umfMemspaceMemtargetNum; + umfMemspaceMemtargetGet; umfMemspaceHighestBandwidthGet; umfMemspaceHighestCapacityGet; umfMemspaceHostAllGet; umfMemspaceLowestLatencyGet; + umfMemtargetGetType; umfOpenIPCHandle; umfOsMemoryProviderOps; umfPoolAlignedMalloc; diff --git a/src/memspace.c b/src/memspace.c index 0dfbfeae3..01e20e617 100644 --- a/src/memspace.c +++ b/src/memspace.c @@ -292,3 +292,19 @@ umf_result_t umfMemspaceFilter(umf_const_memspace_handle_t hMemspace, umf_ba_global_free(uniqueBestNodes); return ret; } + +size_t umfMemspaceMemtargetNum(umf_const_memspace_handle_t hMemspace) { + if (!hMemspace) { + return 0; + } + return hMemspace->size; +} + +umf_const_memtarget_handle_t +umfMemspaceMemtargetGet(umf_const_memspace_handle_t hMemspace, + unsigned targetNum) { + if (!hMemspace || targetNum >= hMemspace->size) { + return NULL; + } + return hMemspace->nodes[targetNum]; +} diff --git a/src/memtarget.c b/src/memtarget.c index 33c737ae0..4c851a772 100644 --- a/src/memtarget.c +++ b/src/memtarget.c @@ -106,3 +106,12 @@ umf_result_t umfMemtargetGetLatency(umf_memtarget_handle_t srcMemoryTarget, return srcMemoryTarget->ops->get_latency(srcMemoryTarget->priv, dstMemoryTarget->priv, latency); } + +umf_result_t umfMemtargetGetType(umf_const_memtarget_handle_t memoryTarget, + umf_memtarget_type_t *type) { + if (!memoryTarget || !type) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + return memoryTarget->ops->get_type(memoryTarget->priv, type); +} diff --git a/src/memtarget_ops.h b/src/memtarget_ops.h index 85555f0ce..08936fcde 100644 --- a/src/memtarget_ops.h +++ b/src/memtarget_ops.h @@ -43,6 +43,8 @@ typedef struct umf_memtarget_ops_t { size_t *bandwidth); umf_result_t (*get_latency)(void *srcMemoryTarget, void *dstMemoryTarget, size_t *latency); + + umf_result_t (*get_type)(void *memoryTarget, umf_memtarget_type_t *type); } umf_memtarget_ops_t; #ifdef __cplusplus diff --git a/src/memtargets/memtarget_numa.c b/src/memtargets/memtarget_numa.c index 553c780bc..32f9bf448 100644 --- a/src/memtargets/memtarget_numa.c +++ b/src/memtargets/memtarget_numa.c @@ -317,6 +317,15 @@ static umf_result_t numa_get_latency(void *srcMemoryTarget, return UMF_RESULT_SUCCESS; } +static umf_result_t numa_get_type(void *memTarget, umf_memtarget_type_t *type) { + if (!memTarget || !type) { + return UMF_RESULT_ERROR_INVALID_ARGUMENT; + } + + *type = UMF_MEMTARGET_TYPE_NUMA; + return UMF_RESULT_SUCCESS; +} + struct umf_memtarget_ops_t UMF_MEMTARGET_NUMA_OPS = { .version = UMF_VERSION_CURRENT, .initialize = numa_initialize, @@ -326,5 +335,6 @@ struct umf_memtarget_ops_t UMF_MEMTARGET_NUMA_OPS = { .get_capacity = numa_get_capacity, .get_bandwidth = numa_get_bandwidth, .get_latency = numa_get_latency, + .get_type = numa_get_type, .memory_provider_create_from_memspace = numa_memory_provider_create_from_memspace}; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 890ac5572..78c3e9c2b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -215,6 +215,10 @@ if(LINUX) # OS-specific functions are implemented only for Linux now NAME mempolicy SRCS memspaces/mempolicy.cpp LIBS ${LIBNUMA_LIBRARIES}) + add_umf_test( + NAME memtarget + SRCS memspaces/memtarget.cpp + LIBS ${LIBNUMA_LIBRARIES}) if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND UMF_BUILD_FUZZTESTS) add_subdirectory(fuzz) endif() diff --git a/test/memspaces/memspace_numa.cpp b/test/memspaces/memspace_numa.cpp index b50eceac9..c8485fadc 100644 --- a/test/memspaces/memspace_numa.cpp +++ b/test/memspaces/memspace_numa.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2023 Intel Corporation +// Copyright (C) 2023-2024 Intel Corporation // Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception @@ -7,6 +7,7 @@ #include "memspace_helpers.hpp" #include "memspace_internal.h" +#include #include struct memspaceNumaTest : ::numaNodesTest { @@ -56,6 +57,10 @@ TEST_F(numaNodesTest, createDestroy) { nodeIds.data(), nodeIds.size(), &hMemspace); ASSERT_EQ(ret, UMF_RESULT_SUCCESS); ASSERT_NE(hMemspace, nullptr); + EXPECT_EQ(umfMemspaceMemtargetNum(hMemspace), nodeIds.size()); + for (size_t i = 0; i < umfMemspaceMemtargetNum(hMemspace); ++i) { + EXPECT_NE(umfMemspaceMemtargetGet(hMemspace, i), nullptr); + } umfMemspaceDestroy(hMemspace); } @@ -91,6 +96,22 @@ TEST_F(memspaceNumaTest, providerFromNumaMemspace) { umfMemoryProviderDestroy(hProvider); } +TEST_F(numaNodesTest, memtargetsInvalid) { + umf_memspace_handle_t hMemspace = nullptr; + EXPECT_EQ(umfMemspaceMemtargetNum(nullptr), 0); + EXPECT_EQ(umfMemspaceMemtargetGet(nullptr, 0), nullptr); + + umf_result_t ret = umfMemspaceCreateFromNumaArray( + nodeIds.data(), nodeIds.size(), &hMemspace); + ASSERT_EQ(ret, UMF_RESULT_SUCCESS); + ASSERT_NE(hMemspace, nullptr); + + ASSERT_EQ(umfMemspaceMemtargetNum(hMemspace), nodeIds.size()); + EXPECT_EQ(umfMemspaceMemtargetGet(hMemspace, nodeIds.size()), nullptr); + + umfMemspaceDestroy(hMemspace); +} + TEST_F(memspaceNumaProviderTest, allocFree) { void *ptr = nullptr; size_t size = SIZE_4K; diff --git a/test/memspaces/memtarget.cpp b/test/memspaces/memtarget.cpp new file mode 100644 index 000000000..84001a705 --- /dev/null +++ b/test/memspaces/memtarget.cpp @@ -0,0 +1,39 @@ +// Copyright (C) 2024 Intel Corporation +// Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include "memspace_helpers.hpp" + +#include +#include +#include + +using umf_test::test; + +TEST_F(test, memTargetNuma) { + auto memspace = umfMemspaceHostAllGet(); + ASSERT_NE(memspace, nullptr); + + for (size_t i = 0; i < umfMemspaceMemtargetNum(memspace); i++) { + auto hTarget = umfMemspaceMemtargetGet(memspace, i); + ASSERT_NE(hTarget, nullptr); + umf_memtarget_type_t type; + auto ret = umfMemtargetGetType(hTarget, &type); + EXPECT_EQ(ret, UMF_RESULT_SUCCESS); + EXPECT_EQ(type, UMF_MEMTARGET_TYPE_NUMA); + } +} + +TEST_F(test, memTargetInvalid) { + auto memspace = umfMemspaceHostAllGet(); + ASSERT_NE(memspace, nullptr); + umf_memtarget_type_t type; + auto ret = umfMemtargetGetType(NULL, &type); + EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + ret = umfMemtargetGetType(NULL, NULL); + EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); + auto hTarget = umfMemspaceMemtargetGet(memspace, 0); + ASSERT_NE(hTarget, nullptr); + ret = umfMemtargetGetType(hTarget, NULL); + EXPECT_EQ(ret, UMF_RESULT_ERROR_INVALID_ARGUMENT); +}