Skip to content

Commit 822e143

Browse files
committed
Add memspace "highest bandwidth"
This memspace contains memory targets ordered by the highest bandwidth value (targets higher in the ordering are prioritised). Querying the bandwidth value requires HMAT support on the platform, calling umfMemspaceHighestBandwidthGet() will return NULL if it's not supported.
1 parent c75dd86 commit 822e143

File tree

11 files changed

+163
-1
lines changed

11 files changed

+163
-1
lines changed

include/umf/memspace.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ umf_memspace_handle_t umfMemspaceHostAllGet(void);
5656
///
5757
umf_memspace_handle_t umfMemspaceHighestCapacityGet(void);
5858

59+
/// \brief Retrieves predefined highest bandwidth memspace.
60+
/// \return highest bandwidth memspace handle on success or NULL on failure.
61+
///
62+
umf_memspace_handle_t umfMemspaceHighestBandwidthGet(void);
63+
5964
#ifdef __cplusplus
6065
}
6166
#endif

src/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ set(UMF_SOURCES_LINUX
7979
memory_targets/memory_target_numa.c
8080
memspaces/memspace_numa.c
8181
memspaces/memspace_host_all.c
82-
memspaces/memspace_highest_capacity.c)
82+
memspaces/memspace_highest_capacity.c
83+
memspaces/memspace_highest_bandwidth.c)
8384

8485
set(UMF_SOURCES_WINDOWS ${UMF_SOURCES_WINDOWS} provider/provider_os_memory.c
8586
provider/provider_os_memory_windows.c)

src/libumf_linux.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ void __attribute__((destructor)) umfDestroy(void) {
2929
umfMemoryTrackerDestroy(t);
3030
umfMemspaceHostAllDestroy();
3131
umfMemspaceHighestCapacityDestroy();
32+
umfMemspaceHighestBandwidthDestroy();
3233
umfDestroyTopology();
3334
}
3435

src/memory_target.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,11 @@ umf_result_t umfMemoryTargetGetCapacity(umf_memory_target_handle_t memoryTarget,
8484
assert(capacity);
8585
return memoryTarget->ops->get_capacity(memoryTarget->priv, capacity);
8686
}
87+
88+
umf_result_t
89+
umfMemoryTargetGetBandwidth(umf_memory_target_handle_t memoryTarget,
90+
size_t *capacity) {
91+
assert(memoryTarget);
92+
assert(capacity);
93+
return memoryTarget->ops->get_bandwidth(memoryTarget->priv, capacity);
94+
}

src/memory_target.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ umf_result_t umfMemoryTargetClone(umf_memory_target_handle_t memoryTarget,
3737
umf_memory_target_handle_t *outHandle);
3838
umf_result_t umfMemoryTargetGetCapacity(umf_memory_target_handle_t memoryTarget,
3939
size_t *capacity);
40+
umf_result_t
41+
umfMemoryTargetGetBandwidth(umf_memory_target_handle_t memoryTarget,
42+
size_t *bandwidth);
4043

4144
#ifdef __cplusplus
4245
}

src/memory_target_ops.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ typedef struct umf_memory_target_ops_t {
4141
umf_memory_provider_handle_t *provider);
4242

4343
umf_result_t (*get_capacity)(void *memoryTarget, size_t *capacity);
44+
umf_result_t (*get_bandwidth)(void *memoryTarget, size_t *bandwidth);
4445
} umf_memory_target_ops_t;
4546

4647
#ifdef __cplusplus

src/memory_targets/memory_target_numa.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,12 +195,47 @@ static umf_result_t numa_get_capacity(void *memTarget, size_t *capacity) {
195195
return UMF_RESULT_SUCCESS;
196196
}
197197

198+
static umf_result_t numa_get_bandwidth(void *memTarget, size_t *bandwidth) {
199+
hwloc_topology_t topology = umfGetTopology();
200+
if (!topology) {
201+
return UMF_RESULT_ERROR_NOT_SUPPORTED;
202+
}
203+
204+
hwloc_obj_t numaNode = hwloc_get_obj_by_type(
205+
topology, HWLOC_OBJ_NUMANODE,
206+
((struct numa_memory_target_t *)memTarget)->physical_id);
207+
if (!numaNode) {
208+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
209+
}
210+
211+
umf_result_t umf_ret = UMF_RESULT_SUCCESS;
212+
213+
hwloc_const_cpuset_t cCpuset = hwloc_topology_get_allowed_cpuset(topology);
214+
hwloc_cpuset_t cpuset = hwloc_bitmap_dup(cCpuset);
215+
struct hwloc_location initiator = {.location.cpuset = cpuset,
216+
.type = HWLOC_LOCATION_TYPE_CPUSET};
217+
hwloc_uint64_t value = 0;
218+
int ret = hwloc_memattr_get_value(topology, HWLOC_MEMATTR_ID_BANDWIDTH,
219+
numaNode, &initiator, 0, &value);
220+
if (ret) {
221+
umf_ret = (errno == EINVAL) ? UMF_RESULT_ERROR_NOT_SUPPORTED
222+
: UMF_RESULT_ERROR_UNKNOWN;
223+
goto err;
224+
}
225+
226+
*bandwidth = value;
227+
err:
228+
hwloc_bitmap_free(cpuset);
229+
return umf_ret;
230+
}
231+
198232
struct umf_memory_target_ops_t UMF_MEMORY_TARGET_NUMA_OPS = {
199233
.version = UMF_VERSION_CURRENT,
200234
.initialize = numa_initialize,
201235
.finalize = numa_finalize,
202236
.pool_create_from_memspace = numa_pool_create_from_memspace,
203237
.clone = numa_clone,
204238
.get_capacity = numa_get_capacity,
239+
.get_bandwidth = numa_get_bandwidth,
205240
.memory_provider_create_from_memspace =
206241
numa_memory_provider_create_from_memspace};

src/memspace_internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ void umfMemspaceDestroy(umf_memspace_handle_t hMemspace);
4747

4848
void umfMemspaceHostAllDestroy(void);
4949
void umfMemspaceHighestCapacityDestroy(void);
50+
void umfMemspaceHighestBandwidthDestroy(void);
5051

5152
#ifdef __cplusplus
5253
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
*
3+
* Copyright (C) 2024 Intel Corporation
4+
*
5+
* Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
6+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
*
8+
*/
9+
10+
#include <assert.h>
11+
#include <hwloc.h>
12+
#include <stdlib.h>
13+
14+
#include "base_alloc_global.h"
15+
#include "memory_target_numa.h"
16+
#include "memspace_internal.h"
17+
#include "memspace_numa.h"
18+
#include "topology.h"
19+
#include "utils_concurrency.h"
20+
21+
static umf_result_t
22+
umfMemspaceHighestBandwidthCreate(umf_memspace_handle_t *hMemspace) {
23+
if (!hMemspace) {
24+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
25+
}
26+
27+
umf_memspace_handle_t hostAllMemspace = umfMemspaceHostAllGet();
28+
if (!hostAllMemspace) {
29+
return UMF_RESULT_ERROR_UNKNOWN;
30+
}
31+
32+
umf_memspace_handle_t highBandwidthMemspace = NULL;
33+
umf_result_t ret =
34+
umfMemspaceClone(hostAllMemspace, &highBandwidthMemspace);
35+
if (ret != UMF_RESULT_SUCCESS) {
36+
return ret;
37+
}
38+
39+
ret = umfMemspaceSortDesc(highBandwidthMemspace,
40+
&umfMemoryTargetGetBandwidth);
41+
if (ret != UMF_RESULT_SUCCESS) {
42+
// TODO: Should we have an alternative way to query 'bandwidth' value
43+
// of each NUMA node?
44+
// HWLOC could possibly return an 'EINVAL' error, which in this context
45+
// means that the HMAT is unavailable and we can't obtain the
46+
// 'bandwidth' value of any NUMA node.
47+
goto err_destroy_memspace;
48+
}
49+
50+
*hMemspace = highBandwidthMemspace;
51+
return UMF_RESULT_SUCCESS;
52+
53+
err_destroy_memspace:
54+
umfMemspaceDestroy(highBandwidthMemspace);
55+
return ret;
56+
}
57+
58+
static umf_memspace_handle_t UMF_MEMSPACE_HIGHEST_BANDWIDTH = NULL;
59+
static UTIL_ONCE_FLAG UMF_MEMSPACE_HBW_INITIALIZED = UTIL_ONCE_FLAG_INIT;
60+
61+
void umfMemspaceHighestBandwidthDestroy(void) {
62+
if (UMF_MEMSPACE_HIGHEST_BANDWIDTH) {
63+
umfMemspaceDestroy(UMF_MEMSPACE_HIGHEST_BANDWIDTH);
64+
UMF_MEMSPACE_HIGHEST_BANDWIDTH = NULL;
65+
}
66+
}
67+
68+
static void umfMemspaceHighestBandwidthInit(void) {
69+
umf_result_t ret =
70+
umfMemspaceHighestBandwidthCreate(&UMF_MEMSPACE_HIGHEST_BANDWIDTH);
71+
if (ret != UMF_RESULT_SUCCESS) {
72+
assert(ret == UMF_RESULT_ERROR_NOT_SUPPORTED);
73+
}
74+
75+
// TODO: Setup appropriate cleanup when HBW memspace becomes available
76+
// on Windows. HBW memspace depends on OS provider, which currently
77+
// doesn't support Windows.
78+
}
79+
80+
umf_memspace_handle_t umfMemspaceHighestBandwidthGet(void) {
81+
util_init_once(&UMF_MEMSPACE_HBW_INITIALIZED,
82+
umfMemspaceHighestBandwidthInit);
83+
return UMF_MEMSPACE_HIGHEST_BANDWIDTH;
84+
}

test/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,10 @@ if(LINUX) # OS-specific functions are implemented only for Linux now
180180
NAME memspace_highest_capacity
181181
SRCS memspaces/memspace_highest_capacity.cpp
182182
LIBS ${UMF_UTILS_FOR_TEST} ${LIBNUMA_LIBRARIES})
183+
add_umf_test(
184+
NAME memspace_highest_bandwidth
185+
SRCS memspaces/memspace_highest_bandwidth.cpp
186+
LIBS ${UMF_UTILS_FOR_TEST} ${LIBNUMA_LIBRARIES})
183187
endif()
184188

185189
# TODO add support for Windows
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright (C) 2024 Intel Corporation
2+
// Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
3+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4+
5+
#include "memory_target_numa.h"
6+
#include "memspace_helpers.hpp"
7+
#include "memspace_internal.h"
8+
#include "test_helpers.h"
9+
10+
#include <numa.h>
11+
#include <numaif.h>
12+
#include <umf/memspace.h>
13+
14+
using umf_test::test;
15+
16+
TEST_F(numaNodesTest, memspaceGet) {
17+
umf_memspace_handle_t hMemspace = umfMemspaceHighestBandwidthGet();
18+
UT_ASSERTne(hMemspace, nullptr);
19+
}

0 commit comments

Comments
 (0)