Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion include/umf/memspace.h
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we already have use cases for such API? Does OpenMP need it? I am just curious to understand how it is used in real life.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is restrict_storage//subnumspace one. In their example they want to allocate from every second target(a.k.a. every second memory). We can achieve this also with filters (which I'm going to implement next), but such basic API as create empty memspace and add or remove targets from it, is quite useful too in my opinion. i.e when you want to create pool which allocates from single specific numa node.

Currently we have "umfMemspaceCreateFromNumaArray" to cover this openMP case, but i will consider to remove it(or to not export it to be precise), when this and filtering patch is merged.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but i will consider to remove it

that is what I am worried about. The first release of UMF is coming soon. And we should care about backward compatibility.

So we should be careful with introducing new API - it is not regarding this particular PR, but rather a general rule we should follow. Also, we need to consider an option to mark some API as experimental - it will give our users a notion that experimental API is not stable and might be removed/changed in the future.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vinser52 this would not be merged on v0.9.x branch (2025.0 oneAPI release)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but i will consider to remove it

that is what I am worried about. The first release of UMF is coming soon. And we should care about backward compatibility.

So we should be careful with introducing new API - it is not regarding this particular PR, but rather a general rule we should follow. Also, we need to consider an option to mark some API as experimental - it will give our users a notion that experimental API is not stable and might be removed/changed in the future.

As far i know we are releasing 0.9 because we do not want to commit to stable API (semver specyfication) There is few minor issues with our API they i did not have time to fix. Like wrong variable size, const, signed vs unsigned

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
*
* 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
Expand Down Expand Up @@ -85,6 +85,12 @@ umf_const_memspace_handle_t umfMemspaceHighestBandwidthGet(void);
///
umf_const_memspace_handle_t umfMemspaceLowestLatencyGet(void);

/// \brief Creates new empty memspace, which can be populated with umfMemspaceMemtargetAdd()
/// \param hMemspace [out] handle to the newly created memspace
/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
///
umf_result_t umfMemspaceNew(umf_memspace_handle_t *hMemspace);

/// \brief Returns number of memory targets in memspace.
/// \param hMemspace handle to memspace
/// \return number of memory targets in memspace
Expand All @@ -100,6 +106,31 @@ umf_const_memtarget_handle_t
umfMemspaceMemtargetGet(umf_const_memspace_handle_t hMemspace,
unsigned targetNum);

/// \brief Adds memory target to memspace.
///
/// \details
/// This function duplicates the memory target and then adds it to the memspace.
/// This means that original memtarget handle and the handle of the duplicated memtarget are different
/// and you cannot use it interchangeably.
/// You can use `umfMemspaceMemtargetGet()` to retrieve new handle.
///
/// \param hMemspace handle to memspace
/// \param hMemtarget handle to memory target
/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
///
umf_result_t umfMemspaceMemtargetAdd(umf_memspace_handle_t hMemspace,
umf_const_memtarget_handle_t hMemtarget);

/// \brief Removes memory target from memspace.
///
/// \param hMemspace handle to memspace
/// \param hMemtarget handle to memory target
/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
///
umf_result_t
umfMemspaceMemtargetRemove(umf_memspace_handle_t hMemspace,
umf_const_memtarget_handle_t hMemtarget);

#ifdef __cplusplus
}
#endif
Expand Down
3 changes: 3 additions & 0 deletions src/libumf.def.in
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,13 @@ EXPORTS
umfMempolicyDestroy
umfMempolicySetCustomSplitPartitions
umfMempolicySetInterleavePartSize
umfMemspaceNew
umfMemspaceDestroy
umfMemspaceMemtargetNum
umfMemspaceMemtargetGet
umfMemtargetGetCapacity
umfMemspaceMemtargetAdd
umfMemspaceMemtargetRemove
umfMemtargetGetType
umfOpenIPCHandle
umfPoolAlignedMalloc
Expand Down
4 changes: 4 additions & 0 deletions src/libumf.map.in
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ UMF_1.0 {
umfMempolicyDestroy;
umfMempolicySetCustomSplitPartitions;
umfMempolicySetInterleavePartSize;
umfMemspaceNew;
umfMemspaceCreateFromNumaArray;
umfMemspaceDestroy;
umfMemspaceMemtargetAdd;
umfMemspaceMemtargetRemove;
umfMemspaceMemtargetNum;
umfMemspaceMemtargetGet;
umfMemtargetGetCapacity;
Expand Down
120 changes: 120 additions & 0 deletions src/memspace.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "memspace_internal.h"
#include "memtarget_internal.h"
#include "memtarget_ops.h"
#include "utils_log.h"

#ifndef NDEBUG
static umf_result_t
Expand Down Expand Up @@ -60,6 +61,10 @@ umf_result_t umfPoolCreateFromMemspace(umf_const_memspace_handle_t memspace,
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
}

if (memspace->size == 0) {
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
}

void **privs = NULL;
umf_result_t ret = memoryTargetHandlesToPriv(memspace, &privs);
if (ret != UMF_RESULT_SUCCESS) {
Expand All @@ -85,6 +90,10 @@ umfMemoryProviderCreateFromMemspace(umf_const_memspace_handle_t memspace,
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
}

if (memspace->size == 0) {
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
}

void **privs = NULL;
umf_result_t ret = memoryTargetHandlesToPriv(memspace, &privs);
if (ret != UMF_RESULT_SUCCESS) {
Expand All @@ -102,6 +111,25 @@ umfMemoryProviderCreateFromMemspace(umf_const_memspace_handle_t memspace,
return ret;
}

umf_result_t umfMemspaceNew(umf_memspace_handle_t *hMemspace) {
if (!hMemspace) {
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
}

umf_memspace_handle_t memspace =
umf_ba_global_alloc(sizeof(struct umf_memspace_t));
if (!memspace) {
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
}

memspace->size = 0;
memspace->nodes = NULL;

*hMemspace = memspace;

return UMF_RESULT_SUCCESS;
}

void umfMemspaceDestroy(umf_memspace_handle_t memspace) {
assert(memspace);
for (size_t i = 0; i < memspace->size; i++) {
Expand Down Expand Up @@ -306,3 +334,95 @@ umfMemspaceMemtargetGet(umf_const_memspace_handle_t hMemspace,
}
return hMemspace->nodes[targetNum];
}

umf_result_t umfMemspaceMemtargetAdd(umf_memspace_handle_t hMemspace,
umf_const_memtarget_handle_t hMemtarget) {
if (!hMemspace || !hMemtarget) {
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
}

for (size_t i = 0; i < hMemspace->size; i++) {
int cmp;
umf_result_t ret =
umfMemtargetCompare(hMemspace->nodes[i], hMemtarget, &cmp);
if (ret != UMF_RESULT_SUCCESS) {
return ret;
}

if (cmp == 0) {
LOG_ERR("Memory target already exists in the memspace");
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
} else if (cmp < 0) {
LOG_ERR("You can't mix different memory target types in the same "
"memspace");
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
}
}

umf_memtarget_handle_t *newNodes =
umf_ba_global_alloc(sizeof(*newNodes) * (hMemspace->size + 1));
if (!newNodes) {
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
}

for (size_t i = 0; i < hMemspace->size; i++) {
newNodes[i] = hMemspace->nodes[i];
}
umf_memtarget_t *hMemtargetClone;

umf_result_t ret = umfMemtargetClone(hMemtarget, &hMemtargetClone);
if (ret != UMF_RESULT_SUCCESS) {
umf_ba_global_free(newNodes);
return ret;
}
newNodes[hMemspace->size++] = hMemtargetClone;

umf_ba_global_free(hMemspace->nodes);
hMemspace->nodes = newNodes;
return UMF_RESULT_SUCCESS;
}

umf_result_t
umfMemspaceMemtargetRemove(umf_memspace_handle_t hMemspace,
umf_const_memtarget_handle_t hMemtarget) {
if (!hMemspace || !hMemtarget) {
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
}
unsigned i;
for (i = 0; i < hMemspace->size; i++) {
int cmp;
umf_result_t ret =
umfMemtargetCompare(hMemspace->nodes[i], hMemtarget, &cmp);

if (ret != UMF_RESULT_SUCCESS) {
return ret;
}

if (cmp == 0) {
break;
}
}

if (i == hMemspace->size) {
LOG_ERR("Memory target not found in the memspace");
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
}

umf_memtarget_handle_t *newNodes =
umf_ba_global_alloc(sizeof(*newNodes) * (hMemspace->size - 1));
if (!newNodes) {
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
}

for (unsigned j = 0, z = 0; j < hMemspace->size; j++) {
if (j != i) {
newNodes[z++] = hMemspace->nodes[j];
}
}

umfMemtargetDestroy(hMemspace->nodes[i]);
umf_ba_global_free(hMemspace->nodes);
hMemspace->nodes = newNodes;
hMemspace->size--;
return UMF_RESULT_SUCCESS;
}
32 changes: 31 additions & 1 deletion src/memtarget.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ void umfMemtargetDestroy(umf_memtarget_handle_t memoryTarget) {
umf_ba_global_free(memoryTarget);
}

umf_result_t umfMemtargetClone(umf_memtarget_handle_t memoryTarget,
umf_result_t umfMemtargetClone(umf_const_memtarget_handle_t memoryTarget,
umf_memtarget_handle_t *outHandle) {
assert(memoryTarget);
assert(outHandle);
Expand Down Expand Up @@ -115,3 +115,33 @@ umf_result_t umfMemtargetGetType(umf_const_memtarget_handle_t memoryTarget,

return memoryTarget->ops->get_type(memoryTarget->priv, type);
}

umf_result_t umfMemtargetCompare(umf_const_memtarget_handle_t a,
umf_const_memtarget_handle_t b, int *result) {
umf_memtarget_type_t typeA, typeB;
umf_result_t ret = umfMemtargetGetType(a, &typeA);
if (ret != UMF_RESULT_SUCCESS) {
return ret;
}

ret = umfMemtargetGetType(b, &typeB);
if (ret != UMF_RESULT_SUCCESS) {
return ret;
}

if (typeA != typeB) {
*result = -1;
return UMF_RESULT_SUCCESS;
}

ret = a->ops->compare(a->priv, b->priv, result);
if (ret != UMF_RESULT_SUCCESS) {
return ret;
}

if (*result) {
*result = 1;
}

return UMF_RESULT_SUCCESS;
}
6 changes: 5 additions & 1 deletion src/memtarget_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ umf_result_t umfMemtargetCreate(const umf_memtarget_ops_t *ops, void *params,
umf_memtarget_handle_t *memoryTarget);
void umfMemtargetDestroy(umf_memtarget_handle_t memoryTarget);

umf_result_t umfMemtargetClone(umf_memtarget_handle_t memoryTarget,
umf_result_t umfMemtargetClone(umf_const_memtarget_handle_t memoryTarget,
umf_memtarget_handle_t *outHandle);

umf_result_t umfMemtargetGetBandwidth(umf_memtarget_handle_t srcMemoryTarget,
Expand All @@ -38,6 +38,10 @@ umf_result_t umfMemtargetGetLatency(umf_memtarget_handle_t srcMemoryTarget,
umf_memtarget_handle_t dstMemoryTarget,
size_t *latency);

/// return 0 if memtargets are equal, -1 if they are of different types,
/// and 1 if they are different targets of the same type
umf_result_t umfMemtargetCompare(umf_const_memtarget_handle_t a,
umf_const_memtarget_handle_t b, int *result);
#ifdef __cplusplus
}
#endif
Expand Down
4 changes: 3 additions & 1 deletion src/memtarget_ops.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
*
* 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
Expand Down Expand Up @@ -45,6 +45,8 @@ typedef struct umf_memtarget_ops_t {
size_t *latency);

umf_result_t (*get_type)(void *memoryTarget, umf_memtarget_type_t *type);
umf_result_t (*compare)(void *memTarget, void *otherMemTarget, int *result);

} umf_memtarget_ops_t;

#ifdef __cplusplus
Expand Down
15 changes: 15 additions & 0 deletions src/memtargets/memtarget_numa.c
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,20 @@ static umf_result_t numa_get_type(void *memTarget, umf_memtarget_type_t *type) {
return UMF_RESULT_SUCCESS;
}

static umf_result_t numa_compare(void *memTarget, void *otherMemTarget,
int *result) {
if (!memTarget || !otherMemTarget || !result) {
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
}

struct numa_memtarget_t *numaTarget = (struct numa_memtarget_t *)memTarget;
struct numa_memtarget_t *otherNumaTarget =
(struct numa_memtarget_t *)otherMemTarget;

*result = numaTarget->physical_id != otherNumaTarget->physical_id;
return UMF_RESULT_SUCCESS;
}

struct umf_memtarget_ops_t UMF_MEMTARGET_NUMA_OPS = {
.version = UMF_VERSION_CURRENT,
.initialize = numa_initialize,
Expand All @@ -336,5 +350,6 @@ struct umf_memtarget_ops_t UMF_MEMTARGET_NUMA_OPS = {
.get_bandwidth = numa_get_bandwidth,
.get_latency = numa_get_latency,
.get_type = numa_get_type,
.compare = numa_compare,
.memory_provider_create_from_memspace =
numa_memory_provider_create_from_memspace};
4 changes: 4 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,10 @@ if(LINUX AND (NOT UMF_DISABLE_HWLOC)) # OS-specific functions are implemented
NAME mempolicy
SRCS memspaces/mempolicy.cpp
LIBS ${LIBNUMA_LIBRARIES})
add_umf_test(
NAME memspace
SRCS memspaces/memspace.cpp
LIBS ${LIBNUMA_LIBRARIES})
add_umf_test(
NAME memtarget
SRCS memspaces/memtarget.cpp
Expand Down
Loading
Loading