Skip to content

Initial memspace and memory_target APIs #53

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 11, 2024
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
2 changes: 2 additions & 0 deletions include/umf.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,7 @@

#include <umf/memory_pool.h>
#include <umf/memory_provider.h>
#include <umf/memspace.h>
#include <umf/memspace_policy.h>

#endif /* UMF_UNIFIED_MEMORY_FRAMEWORK_H */
51 changes: 51 additions & 0 deletions include/umf/memspace.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
*
* Copyright (C) 2023 Intel Corporation
*
* Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*
*/

#ifndef UMF_MEMSPACE_H
#define UMF_MEMSPACE_H 1

#include <umf/base.h>
#include <umf/memory_pool.h>
#include <umf/memory_provider.h>
#include <umf/memspace_policy.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef struct umf_memspace_t *umf_memspace_handle_t;

///
/// \brief Creates new memory pool from memspace and policy.
/// \param hMemspace handle to memspace
/// \param hPolicy handle to policy
/// \param hPool [out] handle to the newly created memory pool
/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
///
umf_result_t umfPoolCreateFromMemspace(umf_memspace_handle_t hMemspace,
umf_memspace_policy_handle_t hPolicy,
umf_memory_pool_handle_t *hPool);

///
/// \brief Creates new memory provider from memspace and policy.
/// \param hMemspace handle to memspace
/// \param hPolicy handle to policy
/// \param hProvider [out] handle to the newly created memory provider
/// \return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
///
umf_result_t
umfMemoryProviderCreateFromMemspace(umf_memspace_handle_t hMemspace,
umf_memspace_policy_handle_t hPolicy,
umf_memory_provider_handle_t *hProvider);

#ifdef __cplusplus
}
#endif

#endif /* UMF_MEMSPACE_H */
25 changes: 25 additions & 0 deletions include/umf/memspace_policy.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
*
* Copyright (C) 2023 Intel Corporation
*
* Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*
*/

#ifndef UMF_MEMSPACE_POLICY_H
#define UMF_MEMSPACE_POLICY_H 1

#include <umf/base.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef struct umf_memspace_policy_t *umf_memspace_policy_handle_t;

#ifdef __cplusplus
}
#endif

#endif /* UMF_MEMSPACE_POLICY_H */
7 changes: 6 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ set(UMF_SOURCES
memory_pool.c
memory_provider.c
memory_provider_get_last_failed.c
memory_target.c
memspace.c
provider/provider_tracking.c
critnib/critnib.c
)
Expand All @@ -22,7 +24,10 @@ set(UMF_SOURCES_WINDOWS

if(UMF_BUILD_OS_MEMORY_PROVIDER)
set(UMF_SOURCES ${UMF_SOURCES} provider/provider_os_memory.c)
set(UMF_SOURCES_LINUX ${UMF_SOURCES_LINUX} provider/provider_os_memory_linux.c)
set(UMF_SOURCES_LINUX ${UMF_SOURCES_LINUX}
provider/provider_os_memory_linux.c
memory_targets/memory_target_numa.c
memspaces/memspace_numa.c)
set(UMF_SOURCES_WINDOWS ${UMF_SOURCES_WINDOWS} provider/provider_os_memory_windows.c)
if(LINUX)
set(UMF_LIBS ${UMF_LIBS} numa)
Expand Down
51 changes: 51 additions & 0 deletions src/memory_target.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
*
* Copyright (C) 2023 Intel Corporation
*
* Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*
*/

#include <assert.h>
#include <stdlib.h>

#include "memory_target.h"
#include "memory_target_ops.h"

umf_result_t umfMemoryTargetCreate(const umf_memory_target_ops_t *ops,
void *params,
umf_memory_target_handle_t *memoryTarget) {
if (!ops || !memoryTarget) {
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
}

umf_memory_target_handle_t target =
(umf_memory_target_t *)malloc(sizeof(umf_memory_target_t));
if (!target) {
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
}

assert(ops->version == UMF_VERSION_CURRENT);

target->ops = ops;

void *target_priv;
umf_result_t ret = ops->initialize(params, &target_priv);
if (ret != UMF_RESULT_SUCCESS) {
free(target);
return ret;
}

target->priv = target_priv;

*memoryTarget = target;

return UMF_RESULT_SUCCESS;
}

void umfMemoryTargetDestroy(umf_memory_target_handle_t memoryTarget) {
assert(memoryTarget);
memoryTarget->ops->finalize(memoryTarget->priv);
free(memoryTarget);
}
39 changes: 39 additions & 0 deletions src/memory_target.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
*
* Copyright (C) 2023 Intel Corporation
*
* Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*
*/

#ifndef UMF_MEMORY_TARGET_H
#define UMF_MEMORY_TARGET_H 1

#include <umf/base.h>

#ifdef __cplusplus
extern "C" {
#endif

struct umf_memory_target_ops_t;
typedef struct umf_memory_target_ops_t umf_memory_target_ops_t;

typedef struct umf_memory_target_t {
const umf_memory_target_ops_t *ops;
void *priv;
} umf_memory_target_t;

typedef umf_memory_target_t *umf_memory_target_handle_t;

umf_result_t umfMemoryTargetCreate(const umf_memory_target_ops_t *ops,
void *params,
umf_memory_target_handle_t *memoryTarget);

void umfMemoryTargetDestroy(umf_memory_target_handle_t memoryTarget);

#ifdef __cplusplus
}
#endif

#endif /* UMF_MEMORY_TARGET_H */
46 changes: 46 additions & 0 deletions src/memory_target_ops.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
*
* Copyright (C) 2023 Intel Corporation
*
* Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*
*/

#ifndef UMF_MEMORY_TARGET_OPS_H
#define UMF_MEMORY_TARGET_OPS_H 1

#include <stdbool.h>

#include <umf/base.h>
#include <umf/memspace.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef struct umf_memory_target_t *umf_memory_target_handle_t;

typedef struct umf_memory_target_ops_t {
/// Version of the ops structure.
/// Should be initialized using UMF_VERSION_CURRENT
uint32_t version;

umf_result_t (*initialize)(void *params, void **memoryTarget);
void (*finalize)(void *memoryTarget);

umf_result_t (*pool_create_from_memspace)(
umf_memspace_handle_t memspace, void **memoryTargets, size_t numTargets,
umf_memspace_policy_handle_t policy, umf_memory_pool_handle_t *pool);

umf_result_t (*memory_provider_create_from_memspace)(
umf_memspace_handle_t memspace, void **memoryTargets, size_t numTargets,
Copy link
Contributor

Choose a reason for hiding this comment

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

what if memspace consists of multiple memory_targets? How we will choose which memory_target should we ask to create a pool or provider from memspace?

Copy link
Member Author

Choose a reason for hiding this comment

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

That's why we only support memory targets of the same type for now. See here:

assert(verifyMemTargetsTypes(memspace) == UMF_RESULT_SUCCESS);

Copy link
Contributor

Choose a reason for hiding this comment

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

I understand that today we support only memory targets of the same type (same ops structure). My question is mostly about the architecture/design, not the current implementation. if we are creating pool/provider from memspace perhaps the current design is wrong and memspace should be responsible for pool/provider creation? In the future I can imagine memspace which consists of GPU memory target and numa memory target - in that case I expect that we will choose GPU memory provider (L0 or cuda) and create USM shared pool.

What do you think?

umf_memspace_policy_handle_t policy,
umf_memory_provider_handle_t *provider);
} umf_memory_target_ops_t;

#ifdef __cplusplus
}
#endif

#endif /* #ifndef UMF_MEMORY_TARGET_OPS_H */
136 changes: 136 additions & 0 deletions src/memory_targets/memory_target_numa.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/*
*
* Copyright (C) 2023 Intel Corporation
*
* Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*
*/

#include <assert.h>
#include <numa.h>
#include <stdlib.h>

#include "../memory_pool_internal.h"
#include "memory_target_numa.h"
#include <umf/pools/pool_disjoint.h>
#include <umf/providers/provider_os_memory.h>

struct numa_memory_target_t {
size_t id;
};

static umf_result_t numa_initialize(void *params, void **memTarget) {
if (params == NULL || memTarget == NULL) {
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
}

struct umf_numa_memory_target_config_t *config =
(struct umf_numa_memory_target_config_t *)params;

struct numa_memory_target_t *numaTarget =
malloc(sizeof(struct numa_memory_target_t));
if (!numaTarget) {
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
}

numaTarget->id = config->id;
*memTarget = numaTarget;
return UMF_RESULT_SUCCESS;
}

static void numa_finalize(void *memTarget) { free(memTarget); }

static const umf_os_memory_provider_params_t
UMF_OS_MEMORY_PROVIDER_PARAMS_DEFAULT = {
// Visibility & protection
.protection = UMF_PROTECTION_READ | UMF_PROTECTION_WRITE,
.visibility = UMF_VISIBILITY_PRIVATE,

// NUMA config
.nodemask = NULL,
.maxnode = 0, // TODO: numa_max_node/GetNumaHighestNodeNumber
.numa_mode = UMF_NUMA_MODE_DEFAULT,
.numa_flags = UMF_NUMA_FLAGS_STRICT, // TODO: determine default behavior

// Logging
.traces = 0, // TODO: parse env variable for log level?
};

static size_t numa_targets_get_maxnode(struct numa_memory_target_t **targets,
size_t numTargets) {
size_t maxNode = 0;
for (size_t i = 0; i < numTargets; i++) {
maxNode = maxNode > targets[i]->id ? maxNode : targets[i]->id;
}
return maxNode;
}

static struct bitmask *
numa_targets_create_nodemask(struct numa_memory_target_t **targets,
size_t numTargets) {
assert(targets);
size_t maxNode = numa_targets_get_maxnode(targets, numTargets);
struct bitmask *mask = numa_bitmask_alloc(maxNode + 1);
if (!mask) {
return NULL;
}

for (size_t i = 0; i < numTargets; i++) {
numa_bitmask_setbit(mask, targets[i]->id);
}

return mask;
}

static enum umf_result_t numa_memory_provider_create_from_memspace(
umf_memspace_handle_t memspace, void **memTargets, size_t numTargets,
umf_memspace_policy_handle_t policy,
umf_memory_provider_handle_t *provider) {
(void)memspace;
// TODO: apply policy
(void)policy;

struct numa_memory_target_t **numaTargets =
(struct numa_memory_target_t **)memTargets;

// Create node mask from IDs
struct bitmask *nodemask =
numa_targets_create_nodemask(numaTargets, numTargets);

umf_os_memory_provider_params_t params =
UMF_OS_MEMORY_PROVIDER_PARAMS_DEFAULT;
params.nodemask = nodemask->maskp;
params.maxnode = nodemask->size;

umf_memory_provider_handle_t numaProvider = NULL;
enum umf_result_t ret = umfMemoryProviderCreate(&UMF_OS_MEMORY_PROVIDER_OPS,
&params, &numaProvider);
numa_bitmask_free(nodemask);
if (ret) {
return ret;
}

*provider = numaProvider;

return UMF_RESULT_SUCCESS;
}

static umf_result_t numa_pool_create_from_memspace(
umf_memspace_handle_t memspace, void **memTargets, size_t numTargets,
umf_memspace_policy_handle_t policy, umf_memory_pool_handle_t *pool) {
(void)memspace;
(void)memTargets;
(void)numTargets;
(void)policy;
(void)pool;
return UMF_RESULT_ERROR_NOT_SUPPORTED;
}

struct umf_memory_target_ops_t UMF_MEMORY_TARGET_NUMA_OPS = {
.version = UMF_VERSION_CURRENT,
.initialize = numa_initialize,
.finalize = numa_finalize,
.pool_create_from_memspace = numa_pool_create_from_memspace,
.memory_provider_create_from_memspace =
numa_memory_provider_create_from_memspace};
Loading