Skip to content

Commit 66c85f2

Browse files
committed
add memspace filter functions
1 parent ddd572b commit 66c85f2

File tree

14 files changed

+446
-25
lines changed

14 files changed

+446
-25
lines changed

include/umf/base.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
*
3-
* Copyright (C) 2023 Intel Corporation
3+
* Copyright (C) 2023-2024 Intel Corporation
44
*
55
* Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
66
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
@@ -43,7 +43,8 @@ typedef enum umf_result_t {
4343
UMF_RESULT_ERROR_INVALID_ALIGNMENT =
4444
4, ///< Invalid alignment of an argument
4545
UMF_RESULT_ERROR_NOT_SUPPORTED = 5, ///< Operation not supported
46-
46+
UMF_RESULT_ERROR_USER_SPECIFIC =
47+
6, ///< Failure in user provider code (i.e in user provided callback)
4748
UMF_RESULT_ERROR_UNKNOWN = 0x7ffffffe ///< Unknown or internal error
4849
} umf_result_t;
4950

include/umf/memspace.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,60 @@ umf_result_t
131131
umfMemspaceMemtargetRemove(umf_memspace_handle_t hMemspace,
132132
umf_const_memtarget_handle_t hMemtarget);
133133

134+
/// \brief Clones memspace.
135+
///
136+
/// \param hMemspace handle to memspace
137+
/// \param hNewMemspace [out] handle to the newly created memspace
138+
/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
139+
///
140+
umf_result_t umfMemspaceClone(umf_const_memspace_handle_t hMemspace,
141+
umf_memspace_handle_t *hNewMemspace);
142+
143+
/// \brief Custom filter function for umfMemspaceUserFilter
144+
///
145+
/// \param hMemspace handle to memspace
146+
/// \param hMemtarget handle to memory target
147+
/// \param args user provided arguments
148+
/// \return zero if hMemtarget should be removed from memspace, positive otherwise, and negative on error
149+
///
150+
typedef int (*umf_memspace_filter_func_t)(
151+
umf_const_memspace_handle_t hMemspace,
152+
umf_const_memtarget_handle_t hMemtarget, void *args);
153+
154+
/// \brief Removes all memory targets with non-matching numa node ids.
155+
///
156+
/// \param hMemspace handle to memspace
157+
/// \param ids array of numa node ids
158+
/// \param size size of the array
159+
/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
160+
/// If the error code is UMF_RESULT_UNKNOWN the memspace is corrupted, otherwise the memspace is not modified.
161+
///
162+
umf_result_t umfMemspaceFilterById(umf_memspace_handle_t hMemspace,
163+
unsigned *ids, size_t size);
164+
165+
/// \brief Filters out memory targets that capacity is less than specified size.
166+
///
167+
/// \param hMemspace handle to memspace
168+
/// \param size minimum capacity of memory target
169+
/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
170+
/// If the error code is UMF_RESULT_UNKNOWN the memspace is corrupted, otherwise the memspace is not modified.
171+
/// \details Negative values of size parameters are reserved for future
172+
/// extension of functionality of this function.
173+
///
174+
umf_result_t umfMemspaceFilterByCapacity(umf_memspace_handle_t hMemspace,
175+
int64_t size);
176+
177+
/// \brief Filters out memory targets based on user provided function
178+
///
179+
/// \param hMemspace handle to memspace
180+
/// \param filter user provided function
181+
/// \param args user provided arguments
182+
/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
183+
/// If the error code is UMF_RESULT_UNKNOWN the memspace is corrupted, otherwise the memspace is not modified.
184+
///
185+
umf_result_t umfMemspaceUserFilter(umf_memspace_handle_t hMemspace,
186+
umf_memspace_filter_func_t filter,
187+
void *args);
134188
#ifdef __cplusplus
135189
}
136190
#endif

include/umf/memtarget.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ umf_result_t umfMemtargetGetType(umf_const_memtarget_handle_t hMemtarget,
3939
umf_result_t umfMemtargetGetCapacity(umf_const_memtarget_handle_t hMemtarget,
4040
size_t *capacity);
4141

42+
/// \brief Get physical ID of the memory target.
43+
/// \param hMemtarget handle to the memory target
44+
/// \param id [out] id of the memory target
45+
/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
46+
umf_result_t umfMemtargetGetId(umf_const_memtarget_handle_t hMemtarget,
47+
unsigned *id);
48+
4249
#ifdef __cplusplus
4350
}
4451
#endif

src/libumf.def.in

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,18 @@ EXPORTS
4040
umfMempolicyDestroy
4141
umfMempolicySetCustomSplitPartitions
4242
umfMempolicySetInterleavePartSize
43-
umfMemspaceNew
43+
umfMemspaceClone
4444
umfMemspaceDestroy
45-
umfMemspaceMemtargetNum
46-
umfMemspaceMemtargetGet
47-
umfMemtargetGetCapacity
45+
umfMemspaceFilterByCapacity
46+
umfMemspaceFilterById
4847
umfMemspaceMemtargetAdd
48+
umfMemspaceMemtargetGet
49+
umfMemspaceMemtargetNum
4950
umfMemspaceMemtargetRemove
51+
umfMemspaceNew
52+
umfMemspaceUserFilter
53+
umfMemtargetGetCapacity
54+
umfMemtargetGetId
5055
umfMemtargetGetType
5156
umfOpenIPCHandle
5257
umfPoolAlignedMalloc

src/libumf.map.in

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,19 @@ UMF_1.0 {
3434
umfMempolicyDestroy;
3535
umfMempolicySetCustomSplitPartitions;
3636
umfMempolicySetInterleavePartSize;
37-
umfMemspaceNew;
37+
umfMemspaceClone;
3838
umfMemspaceCreateFromNumaArray;
3939
umfMemspaceDestroy;
40+
umfMemspaceFilterByCapacity;
41+
umfMemspaceFilterById;
4042
umfMemspaceMemtargetAdd;
41-
umfMemspaceMemtargetRemove;
42-
umfMemspaceMemtargetNum;
4343
umfMemspaceMemtargetGet;
44+
umfMemspaceMemtargetNum;
45+
umfMemspaceMemtargetRemove;
46+
umfMemspaceNew;
47+
umfMemspaceUserFilter;
4448
umfMemtargetGetCapacity;
49+
umfMemtargetGetId;
4550
umfMemtargetGetType;
4651
umfOpenIPCHandle;
4752
umfPoolAlignedMalloc;

src/memspace.c

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,3 +426,153 @@ umfMemspaceMemtargetRemove(umf_memspace_handle_t hMemspace,
426426
hMemspace->size--;
427427
return UMF_RESULT_SUCCESS;
428428
}
429+
430+
// Helper function - returns zero on success, negative in case of error in filter function
431+
// and positive error code, in case of other errors.
432+
static int umfMemspaceFilterHelper(umf_memspace_handle_t memspace,
433+
umf_memspace_filter_func_t filter,
434+
void *args) {
435+
436+
if (!memspace || !filter) {
437+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
438+
}
439+
440+
size_t idx = 0;
441+
int ret;
442+
umf_memtarget_handle_t *nodesToRemove =
443+
umf_ba_global_alloc(sizeof(*nodesToRemove) * memspace->size);
444+
if (!nodesToRemove) {
445+
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
446+
}
447+
448+
for (size_t i = 0; i < memspace->size; i++) {
449+
ret = filter(memspace, memspace->nodes[i], args);
450+
if (ret < 0) {
451+
LOG_ERR("filter function failed");
452+
goto free_mem;
453+
} else if (ret == 0) {
454+
nodesToRemove[idx++] = memspace->nodes[i];
455+
}
456+
}
457+
458+
size_t i = 0;
459+
for (; i < idx; i++) {
460+
ret = umfMemspaceMemtargetRemove(memspace, nodesToRemove[i]);
461+
if (ret != UMF_RESULT_SUCCESS) {
462+
goto re_add;
463+
}
464+
}
465+
466+
umf_ba_global_free(nodesToRemove);
467+
return UMF_RESULT_SUCCESS;
468+
469+
re_add:
470+
// If target removal failed, add back previously removed targets.
471+
for (size_t j = 0; j < i; j++) {
472+
umf_result_t ret2 = umfMemspaceMemtargetAdd(memspace, nodesToRemove[j]);
473+
if (ret2 != UMF_RESULT_SUCCESS) {
474+
ret =
475+
UMF_RESULT_ERROR_UNKNOWN; // indicate that memspace is corrupted
476+
break;
477+
}
478+
}
479+
free_mem:
480+
umf_ba_global_free(nodesToRemove);
481+
return ret;
482+
}
483+
484+
umf_result_t umfMemspaceUserFilter(umf_memspace_handle_t memspace,
485+
umf_memspace_filter_func_t filter,
486+
void *args) {
487+
488+
if (!memspace || !filter) {
489+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
490+
}
491+
492+
int ret = umfMemspaceFilterHelper(memspace, filter, args);
493+
if (ret < 0) {
494+
return UMF_RESULT_ERROR_USER_SPECIFIC;
495+
}
496+
497+
return ret;
498+
}
499+
500+
typedef struct filter_by_id_args {
501+
unsigned *ids; // array of numa nodes ids
502+
size_t size; // size of the array
503+
} filter_by_id_args_t;
504+
505+
/*
506+
* The following predefined filter callbacks returns umf_result_t codes as negative value
507+
* because only negative values are treated as errors. umfMemspaceFilterHelper() will pass
508+
* this error code through and umfMemspaceFilterBy*() functions will translate this code to positive
509+
* umf_result_t code.
510+
*/
511+
512+
static int filterById(umf_const_memspace_handle_t memspace,
513+
umf_const_memtarget_handle_t target, void *args) {
514+
if (!memspace || !target || !args) {
515+
return -UMF_RESULT_ERROR_INVALID_ARGUMENT;
516+
}
517+
518+
filter_by_id_args_t *filterArgs = args;
519+
for (size_t i = 0; i < filterArgs->size; i++) {
520+
unsigned id;
521+
umf_result_t ret = umfMemtargetGetId(target, &id);
522+
if (ret != UMF_RESULT_SUCCESS) {
523+
return -ret;
524+
}
525+
526+
if (id == filterArgs->ids[i]) {
527+
return 1;
528+
}
529+
}
530+
return 0;
531+
}
532+
533+
static int filterByCapacity(umf_const_memspace_handle_t memspace,
534+
umf_const_memtarget_handle_t target, void *args) {
535+
if (!memspace || !target || !args) {
536+
return -UMF_RESULT_ERROR_INVALID_ARGUMENT;
537+
}
538+
539+
size_t capacity;
540+
umf_result_t ret = umfMemtargetGetCapacity(target, &capacity);
541+
if (ret != UMF_RESULT_SUCCESS) {
542+
return -ret;
543+
}
544+
545+
size_t *targetCapacity = args;
546+
return (capacity >= *targetCapacity) ? 1 : 0;
547+
}
548+
549+
umf_result_t umfMemspaceFilterById(umf_memspace_handle_t memspace,
550+
unsigned *ids, size_t size) {
551+
if (!memspace || !ids || size == 0) {
552+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
553+
}
554+
555+
filter_by_id_args_t args = {ids, size};
556+
int ret = umfMemspaceFilterHelper(memspace, &filterById, &args);
557+
558+
// if umfMemspaceFilter() returned negative umf_result_t change it to positive
559+
return ret < 0 ? -ret : ret;
560+
}
561+
562+
umf_result_t umfMemspaceFilterByCapacity(umf_memspace_handle_t memspace,
563+
int64_t capacity) {
564+
if (!memspace) {
565+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
566+
}
567+
// TODO: At this moment this function filters out memory targets that capacity is
568+
// less than specified size. We can extend this function to support reverse filter,
569+
// by using negative values of capacity parameter.
570+
// For now we just return invalid argument.
571+
if (capacity < 0) {
572+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
573+
}
574+
int ret = umfMemspaceFilterHelper(memspace, &filterByCapacity, &capacity);
575+
576+
// if umfMemspaceFilter() returned negative umf_result_t change it to positive
577+
return ret < 0 ? -ret : ret;
578+
}

src/memspace_internal.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,6 @@ struct umf_memspace_t {
2424
umf_memtarget_handle_t *nodes;
2525
};
2626

27-
///
28-
/// \brief Clones memspace
29-
///
30-
umf_result_t umfMemspaceClone(umf_const_memspace_handle_t hMemspace,
31-
umf_memspace_handle_t *outHandle);
32-
3327
typedef umf_result_t (*umfGetPropertyFn)(umf_const_memtarget_handle_t,
3428
uint64_t *);
3529

src/memtarget.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,15 @@ umf_result_t umfMemtargetGetLatency(umf_memtarget_handle_t srcMemoryTarget,
107107
dstMemoryTarget->priv, latency);
108108
}
109109

110+
umf_result_t umfMemtargetGetId(umf_const_memtarget_handle_t hMemtarget,
111+
unsigned *id) {
112+
if (!hMemtarget || !id) {
113+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
114+
}
115+
116+
return hMemtarget->ops->get_id(hMemtarget->priv, id);
117+
}
118+
110119
umf_result_t umfMemtargetGetType(umf_const_memtarget_handle_t memoryTarget,
111120
umf_memtarget_type_t *type) {
112121
if (!memoryTarget || !type) {

src/memtarget_ops.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ typedef struct umf_memtarget_ops_t {
4545
size_t *latency);
4646

4747
umf_result_t (*get_type)(void *memoryTarget, umf_memtarget_type_t *type);
48+
umf_result_t (*get_id)(void *memoryTarget, unsigned *type);
4849
umf_result_t (*compare)(void *memTarget, void *otherMemTarget, int *result);
4950

5051
} umf_memtarget_ops_t;

src/memtargets/memtarget_numa.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,15 @@ static umf_result_t numa_get_type(void *memTarget, umf_memtarget_type_t *type) {
326326
return UMF_RESULT_SUCCESS;
327327
}
328328

329+
static umf_result_t numa_get_id(void *memTarget, unsigned *id) {
330+
if (!memTarget || !id) {
331+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
332+
}
333+
334+
*id = ((struct numa_memtarget_t *)memTarget)->physical_id;
335+
return UMF_RESULT_SUCCESS;
336+
}
337+
329338
static umf_result_t numa_compare(void *memTarget, void *otherMemTarget,
330339
int *result) {
331340
if (!memTarget || !otherMemTarget || !result) {
@@ -350,6 +359,7 @@ struct umf_memtarget_ops_t UMF_MEMTARGET_NUMA_OPS = {
350359
.get_bandwidth = numa_get_bandwidth,
351360
.get_latency = numa_get_latency,
352361
.get_type = numa_get_type,
362+
.get_id = numa_get_id,
353363
.compare = numa_compare,
354364
.memory_provider_create_from_memspace =
355365
numa_memory_provider_create_from_memspace};

src/provider/provider_level_zero.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -188,12 +188,7 @@ static void ze_memory_provider_finalize(void *provider) {
188188
return;
189189
}
190190

191-
utils_init_once(&ze_is_initialized, init_ze_global_state);
192191
umf_ba_global_free(provider);
193-
194-
// portable version of "ze_is_initialized = UTIL_ONCE_FLAG_INIT;"
195-
static UTIL_ONCE_FLAG is_initialized = UTIL_ONCE_FLAG_INIT;
196-
memcpy(&ze_is_initialized, &is_initialized, sizeof(ze_is_initialized));
197192
}
198193

199194
static bool use_relaxed_allocation(ze_memory_provider_t *ze_provider,

test/memspaces/memspace_fixtures.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,18 @@ struct memspaceProviderTest : ::memspaceGetTest {
102102
umf_memory_provider_handle_t hProvider = nullptr;
103103
};
104104

105+
struct numaNodesCapacityTest : numaNodesTest {
106+
void SetUp() override {
107+
numaNodesTest::SetUp();
108+
109+
for (auto nodeId : nodeIds) {
110+
capacities.push_back(numa_node_size64(nodeId, nullptr));
111+
}
112+
}
113+
114+
std::vector<size_t> capacities;
115+
};
116+
105117
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(memspaceGetTest);
106118
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(memspaceProviderTest);
107119

0 commit comments

Comments
 (0)