Skip to content

Commit 7c35d41

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. Introduce UMF_MEMSPACE_HIGHEST_BANDWIDTH env var. This environment variable is used to forcefully assign NUMA nodes to the memspace "highest bandwidth". The ordering of memory targets within this memspace will correspond to the sequence of NUMA nodes specified in the environment variable.
1 parent 129a2ad commit 7c35d41

13 files changed

+346
-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
@@ -80,7 +80,8 @@ set(UMF_SOURCES_LINUX
8080
memory_targets/memory_target_numa.c
8181
memspaces/memspace_numa.c
8282
memspaces/memspace_host_all.c
83-
memspaces/memspace_highest_capacity.c)
83+
memspaces/memspace_highest_capacity.c
84+
memspaces/memspace_highest_bandwidth.c)
8485

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

src/libumf.map

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ UMF_1.0 {
2929
umfMemoryProviderPutIPCHandle;
3030
umfMemspaceCreateFromNumaArray;
3131
umfMemspaceDestroy;
32+
umfMemspaceHighestBandwidthGet;
3233
umfMemspaceHighestCapacityGet;
3334
umfMemspaceHostAllGet;
3435
umfOpenIPCHandle;

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: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,14 @@ umf_result_t umfMemoryTargetGetCapacity(umf_memory_target_handle_t memoryTarget,
8383
assert(capacity);
8484
return memoryTarget->ops->get_capacity(memoryTarget->priv, capacity);
8585
}
86+
87+
umf_result_t
88+
umfMemoryTargetGetBandwidth(umf_memory_target_handle_t srcMemoryTarget,
89+
umf_memory_target_handle_t dstMemoryTarget,
90+
size_t *bandwidth) {
91+
assert(srcMemoryTarget);
92+
assert(dstMemoryTarget);
93+
assert(bandwidth);
94+
return srcMemoryTarget->ops->get_bandwidth(
95+
srcMemoryTarget->priv, dstMemoryTarget->priv, bandwidth);
96+
}

src/memory_target.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ 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 srcMemoryTarget,
42+
umf_memory_target_handle_t dstMemoryTarget,
43+
size_t *bandwidth);
4044

4145
#ifdef __cplusplus
4246
}

src/memory_target_ops.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ 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 *srcMemoryTarget, void *dstMemoryTarget,
45+
size_t *bandwidth);
4446
} umf_memory_target_ops_t;
4547

4648
#ifdef __cplusplus

src/memory_targets/memory_target_numa.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,12 +143,49 @@ static umf_result_t numa_get_capacity(void *memTarget, size_t *capacity) {
143143
return UMF_RESULT_SUCCESS;
144144
}
145145

146+
static umf_result_t numa_get_bandwidth(void *srcMemoryTarget,
147+
void *dstMemoryTarget,
148+
size_t *bandwidth) {
149+
hwloc_topology_t topology = umfGetTopology();
150+
if (!topology) {
151+
return UMF_RESULT_ERROR_NOT_SUPPORTED;
152+
}
153+
154+
hwloc_obj_t srcNumaNode = hwloc_get_obj_by_type(
155+
topology, HWLOC_OBJ_NUMANODE,
156+
((struct numa_memory_target_t *)srcMemoryTarget)->physical_id);
157+
if (!srcNumaNode) {
158+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
159+
}
160+
161+
hwloc_obj_t dstNumaNode = hwloc_get_obj_by_type(
162+
topology, HWLOC_OBJ_NUMANODE,
163+
((struct numa_memory_target_t *)dstMemoryTarget)->physical_id);
164+
if (!dstNumaNode) {
165+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
166+
}
167+
168+
struct hwloc_location initiator = {.location.cpuset = srcNumaNode->cpuset,
169+
.type = HWLOC_LOCATION_TYPE_CPUSET};
170+
hwloc_uint64_t value = 0;
171+
int ret = hwloc_memattr_get_value(topology, HWLOC_MEMATTR_ID_BANDWIDTH,
172+
dstNumaNode, &initiator, 0, &value);
173+
if (ret) {
174+
return (errno == EINVAL) ? UMF_RESULT_ERROR_NOT_SUPPORTED
175+
: UMF_RESULT_ERROR_UNKNOWN;
176+
}
177+
178+
*bandwidth = value;
179+
return UMF_RESULT_SUCCESS;
180+
}
181+
146182
struct umf_memory_target_ops_t UMF_MEMORY_TARGET_NUMA_OPS = {
147183
.version = UMF_VERSION_CURRENT,
148184
.initialize = numa_initialize,
149185
.finalize = numa_finalize,
150186
.pool_create_from_memspace = numa_pool_create_from_memspace,
151187
.clone = numa_clone,
152188
.get_capacity = numa_get_capacity,
189+
.get_bandwidth = numa_get_bandwidth,
153190
.memory_provider_create_from_memspace =
154191
numa_memory_provider_create_from_memspace};

src/memspace.c

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,3 +208,89 @@ umfMemspaceSortDesc(umf_memspace_handle_t hMemspace,
208208

209209
return UMF_RESULT_SUCCESS;
210210
}
211+
212+
enum umf_result_t umfMemspaceFilter(
213+
umf_memspace_handle_t hMemspace,
214+
umf_result_t (*getTarget)(umf_memory_target_handle_t initiator,
215+
umf_memory_target_handle_t *nodes,
216+
size_t numNodes,
217+
umf_memory_target_handle_t *target),
218+
umf_memspace_handle_t *filteredMemspace) {
219+
if (!hMemspace || !getTarget) {
220+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
221+
}
222+
223+
umf_memory_target_handle_t *uniqueBestNodes = umf_ba_global_alloc(
224+
hMemspace->size * sizeof(umf_memory_target_handle_t *));
225+
if (!uniqueBestNodes) {
226+
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
227+
}
228+
229+
umf_result_t ret = UMF_RESULT_SUCCESS;
230+
231+
size_t numUniqueBestNodes = 0;
232+
for (size_t nodeIdx = 0; nodeIdx < hMemspace->size; nodeIdx++) {
233+
umf_memory_target_handle_t target = NULL;
234+
ret = getTarget(hMemspace->nodes[nodeIdx], hMemspace->nodes,
235+
hMemspace->size, &target);
236+
if (ret != UMF_RESULT_SUCCESS) {
237+
goto err_free_best_targets;
238+
}
239+
240+
// check if the target is already present in the best nodes
241+
size_t bestTargetIdx;
242+
for (bestTargetIdx = 0; bestTargetIdx < numUniqueBestNodes;
243+
bestTargetIdx++) {
244+
if (uniqueBestNodes[bestTargetIdx] == target) {
245+
break;
246+
}
247+
}
248+
249+
// if the target is not present, add it to the best nodes
250+
if (bestTargetIdx == numUniqueBestNodes) {
251+
uniqueBestNodes[numUniqueBestNodes++] = target;
252+
}
253+
}
254+
255+
// copy the unique best nodes into a new memspace
256+
umf_memspace_handle_t newMemspace =
257+
umf_ba_global_alloc(sizeof(struct umf_memspace_t));
258+
if (!newMemspace) {
259+
ret = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
260+
goto err_free_best_targets;
261+
}
262+
263+
newMemspace->size = numUniqueBestNodes;
264+
newMemspace->nodes = umf_ba_global_alloc(
265+
sizeof(umf_memory_target_handle_t) * newMemspace->size);
266+
if (!newMemspace->nodes) {
267+
ret = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
268+
goto err_free_new_memspace;
269+
}
270+
271+
size_t cloneIdx = 0;
272+
for (size_t cloneIdx = 0; cloneIdx < newMemspace->size; cloneIdx++) {
273+
ret = umfMemoryTargetClone(uniqueBestNodes[cloneIdx],
274+
&newMemspace->nodes[cloneIdx]);
275+
if (ret != UMF_RESULT_SUCCESS) {
276+
goto err_free_cloned_nodes;
277+
}
278+
}
279+
280+
*filteredMemspace = newMemspace;
281+
umf_ba_global_free(uniqueBestNodes);
282+
283+
return UMF_RESULT_SUCCESS;
284+
285+
err_free_cloned_nodes:
286+
while (cloneIdx != 0) {
287+
cloneIdx--;
288+
umfMemoryTargetDestroy(newMemspace->nodes[cloneIdx]);
289+
}
290+
umf_ba_global_free(newMemspace->nodes);
291+
err_free_new_memspace:
292+
umf_ba_global_free(newMemspace);
293+
err_free_best_targets:
294+
umf_ba_global_free(uniqueBestNodes);
295+
return ret;
296+
}

src/memspace_internal.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,18 @@ typedef umf_result_t (*umfGetPropertyFn)(umf_memory_target_handle_t,
3939
enum umf_result_t umfMemspaceSortDesc(umf_memspace_handle_t hMemspace,
4040
umfGetPropertyFn getProperty);
4141

42+
typedef umf_result_t (*umfGetTargetFn)(umf_memory_target_handle_t initiator,
43+
umf_memory_target_handle_t *nodes,
44+
size_t numNodes,
45+
umf_memory_target_handle_t *target);
46+
47+
///
48+
/// \brief Filters the targets using getTarget() to create a new memspace
49+
///
50+
enum umf_result_t umfMemspaceFilter(umf_memspace_handle_t hMemspace,
51+
umfGetTargetFn getTarget,
52+
umf_memspace_handle_t *filteredMemspace);
53+
4254
///
4355
/// \brief Destroys memspace
4456
/// \param hMemspace handle to memspace
@@ -47,6 +59,7 @@ void umfMemspaceDestroy(umf_memspace_handle_t hMemspace);
4759

4860
void umfMemspaceHostAllDestroy(void);
4961
void umfMemspaceHighestCapacityDestroy(void);
62+
void umfMemspaceHighestBandwidthDestroy(void);
5063

5164
#ifdef __cplusplus
5265
}

0 commit comments

Comments
 (0)