Repository: oneapi-src/unified-memory-framework (language: python)

Issue:
Add umfMemspaceMemtarget[Num|Get]



Discussion / hints:

Fix patch:
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 <umf/memory_pool.h>
 #include <umf/memory_provider.h>
 #include <umf/mempolicy.h>
+#include <umf/memtarget.h>
 
 #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 <umf/base.h>
+
 #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};


Test patch:
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 <umf/memspace.h>
 #include <umf/providers/provider_os_memory.h>
 
 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 <umf/base.h>
+#include <umf/memspace.h>
+#include <umf/memtarget.h>
+
+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);
+}