Skip to content

Commit 9ab1e48

Browse files
committed
add Level Zero memory provider
1 parent f2b784a commit 9ab1e48

File tree

15 files changed

+451
-1
lines changed

15 files changed

+451
-1
lines changed

.github/workflows/gpu.yml

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
name: GPU
2+
3+
on: workflow_call
4+
5+
permissions:
6+
contents: read
7+
8+
jobs:
9+
ubuntu-build:
10+
name: Build - Ubuntu
11+
12+
strategy:
13+
matrix:
14+
os: ['ubuntu-22.04']
15+
build_type: [Release]
16+
compiler: [{c: gcc, cxx: g++}]
17+
shared_library: ['ON', 'OFF']
18+
runs-on: ${{matrix.os}}
19+
20+
steps:
21+
- name: Install apt packages
22+
run: |
23+
sudo apt-get update
24+
sudo apt-get install -y cmake libhwloc-dev libnuma-dev libjemalloc-dev libtbb-dev
25+
26+
- name: Checkout Level Zero
27+
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
28+
with:
29+
repository: oneapi-src/level-zero
30+
path: level_zero
31+
32+
- name: Build and Install Level Zero
33+
run: |
34+
cd level_zero
35+
mkdir build
36+
cd build
37+
cmake ..
38+
sudo cmake --build . --config Release --target install
39+
cd ..
40+
41+
- name: Checkout
42+
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
43+
44+
- name: Configure build
45+
run: >
46+
cmake
47+
-B ${{github.workspace}}/build
48+
-DCMAKE_BUILD_TYPE=${{matrix.build_type}}
49+
-DCMAKE_C_COMPILER=${{matrix.compiler.c}}
50+
-DCMAKE_CXX_COMPILER=${{matrix.compiler.cxx}}
51+
-DUMF_BUILD_SHARED_LIBRARY=${{matrix.shared_library}}
52+
-DUMF_BUILD_BENCHMARKS=ON
53+
-DUMF_BUILD_TESTS=ON
54+
-DUMF_FORMAT_CODE_STYLE=ON
55+
-DUMF_DEVELOPER_MODE=ON
56+
-DUMF_BUILD_LIBUMF_PROVIDER_LEVEL_ZERO=ON
57+
-DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON
58+
-DUMF_ENABLE_POOL_TRACKING=ON
59+
60+
- name: Build UMF
61+
run: cmake --build ${{github.workspace}}/build -j $(nproc)
62+
63+
- name: Run tests
64+
working-directory: ${{github.workspace}}/build
65+
run: |
66+
ctest --output-on-failure --test-dir test

.github/workflows/pr_push.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,6 @@ jobs:
9191
Benchmark:
9292
needs: [Build]
9393
uses: ./.github/workflows/benchmarks.yml
94+
GPU:
95+
needs: [Build]
96+
uses: ./.github/workflows/gpu.yml

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ project(unified-memory-framework VERSION 0.1.0 LANGUAGES C)
88
# Build Options
99
option(UMF_BUILD_SHARED_LIBRARY "Build UMF as shared library" OFF)
1010
option(UMF_BUILD_OS_MEMORY_PROVIDER "Build OS memory provider" ON)
11+
option(UMF_BUILD_LIBUMF_PROVIDER_LEVEL_ZERO "Build Level Zero memory provider" OFF)
1112
option(UMF_BUILD_LIBUMF_POOL_DISJOINT "Build the libumf_pool_disjoint static library" OFF)
1213
option(UMF_BUILD_LIBUMF_POOL_JEMALLOC "Build the libumf_pool_jemalloc static library" OFF)
1314
option(UMF_BUILD_LIBUMF_POOL_SCALABLE "Build the libumf_pool_scalable static library" OFF)

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ List of options provided by CMake:
8484
| - | - | - | - |
8585
| UMF_BUILD_SHARED_LIBRARY | Build UMF as shared library | ON/OFF | OFF |
8686
| UMF_BUILD_OS_MEMORY_PROVIDER | Build OS memory provider | ON/OFF | ON |
87+
| UMF_BUILD_LIBUMF_PROVIDER_LEVEL_ZERO | Build Level Zero memory provider | ON/OFF | OFF |
8788
| UMF_BUILD_LIBUMF_POOL_DISJOINT | Build the libumf_pool_disjoint static library | ON/OFF | OFF |
8889
| UMF_BUILD_LIBUMF_POOL_JEMALLOC | Build the libumf_pool_jemalloc static library | ON/OFF | OFF |
8990
| UMF_BUILD_LIBUMF_POOL_SCALABLE | Build the libumf_pool_scalable static library | ON/OFF | OFF |

benchmark/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ if (UMF_BUILD_OS_MEMORY_PROVIDER)
5252
endif()
5353
endif()
5454

55+
if (UMF_BUILD_LIBUMF_PROVIDER_LEVEL_ZERO)
56+
target_compile_definitions(ubench PRIVATE UMF_BUILD_LIBUMF_PROVIDER_LEVEL_ZERO=1)
57+
endif()
58+
5559
if (UMF_BUILD_LIBUMF_POOL_DISJOINT)
5660
target_compile_definitions(ubench PRIVATE UMF_BUILD_LIBUMF_POOL_DISJOINT=1)
5761

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright (C) 2024 Intel Corporation
3+
*
4+
* Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
5+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
*/
7+
8+
#ifndef UMF_PROVIDER_LEVEL_ZERO_H
9+
#define UMF_PROVIDER_LEVEL_ZERO_H
10+
11+
#include <level_zero/ze_api.h>
12+
13+
#include "umf/memory_provider.h"
14+
15+
#ifdef __cplusplus
16+
extern "C" {
17+
#endif
18+
19+
/// @brief Level Zero provider settings struct
20+
typedef struct level_zero_memory_provider_params_t {
21+
ze_context_handle_t context;
22+
ze_device_handle_t device;
23+
ze_device_mem_alloc_desc_t device_mem_alloc_desc;
24+
} level_zero_memory_provider_params_t;
25+
26+
umf_memory_provider_ops_t *umfLevelZeroMemoryProviderOps(void);
27+
28+
#ifdef __cplusplus
29+
}
30+
#endif
31+
32+
#endif /* UMF_PROVIDER_LEVEL_ZERO_H */

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,4 @@ install(TARGETS umf
103103
)
104104

105105
add_subdirectory(pool)
106+
add_subdirectory(provider)

src/libumf.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,4 @@ EXPORTS
3939
umfMemoryProviderCreateFromMemspace
4040
umfMemspaceDestroy
4141
umfProxyPoolOps
42+

src/libumf.map

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ UMF_1.0 {
3535
umfMemoryProviderCreateFromMemspace;
3636
umfMemspaceCreateFromNumaArray;
3737
umfMemspaceDestroy;
38+
umfLevelZeroMemoryProviderOps;
3839
local:
3940
*;
4041
};

src/pool/pool_scalable.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
#include <stdbool.h>
1414
#include <stdint.h>
1515
#include <stdio.h>
16-
#include <stdlib.h>
1716
#include <string.h>
1817

1918
#include "umf/pools/pool_scalable.h"

src/provider/CMakeLists.txt

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
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+
if(UMF_BUILD_SHARED_LIBRARY)
6+
set(PROVIDER_EXTRA_SRCS ${BA_SOURCES})
7+
set(PROVIDER_COMPILE_DEFINITIONS UMF_SHARED_LIBRARY)
8+
endif()
9+
10+
# libumf_provider_level_zero
11+
if(UMF_BUILD_LIBUMF_PROVIDER_LEVEL_ZERO)
12+
add_umf_library(NAME level_zero_provider
13+
TYPE STATIC
14+
SRCS provider_level_zero.c ${PROVIDER_EXTRA_SRCS}
15+
LIBS umf_utils)
16+
target_compile_definitions(level_zero_provider PUBLIC ${PROVIDER_COMPILE_DEFINITIONS})
17+
18+
add_library(${PROJECT_NAME}::level_zero_provider ALIAS level_zero_provider)
19+
20+
add_dependencies(level_zero_provider
21+
umf)
22+
23+
target_link_libraries(level_zero_provider PRIVATE
24+
umf)
25+
26+
target_include_directories(level_zero_provider PUBLIC
27+
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include/umf/providers>
28+
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
29+
)
30+
31+
install(TARGETS level_zero_provider
32+
EXPORT ${PROJECT_NAME}-targets
33+
)
34+
endif()

src/provider/provider_level_zero.c

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
/*
2+
* Copyright (C) 2024 Intel Corporation
3+
*
4+
* Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
5+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
*/
7+
8+
#include <assert.h>
9+
#include <dlfcn.h>
10+
#include <pthread.h>
11+
#include <stdbool.h>
12+
#include <stddef.h>
13+
#include <stdio.h> // TODO remove
14+
#include <unistd.h>
15+
16+
#include <umf.h>
17+
#include <umf/memory_provider_ops.h>
18+
#include <umf/providers/provider_level_zero.h>
19+
20+
#include "base_alloc_global.h"
21+
#include "utils_common.h"
22+
#include "utils_concurrency.h"
23+
#include "utils_sanitizers.h"
24+
25+
typedef struct ze_ops_t {
26+
ze_result_t (*zeMemAllocDevice)(ze_context_handle_t,
27+
const ze_device_mem_alloc_desc_t *, size_t,
28+
size_t, ze_device_handle_t, void *);
29+
ze_result_t (*zeMemFree)(ze_context_handle_t, void *);
30+
} ze_ops_t;
31+
32+
static ze_ops_t g_ze_ops;
33+
static UTIL_ONCE_FLAG ze_is_initialized = UTIL_ONCE_FLAG_INIT;
34+
static bool Init_ze_global_state_failed;
35+
36+
static void init_ze_global_state(void) {
37+
const char so_name[] = "libze_loader.so";
38+
void *ze_handle = dlopen(so_name, RTLD_LAZY);
39+
if (!ze_handle) {
40+
fprintf(stderr, "%s not found.\n", so_name);
41+
Init_ze_global_state_failed = true;
42+
return;
43+
}
44+
45+
*(void **)&g_ze_ops.zeMemAllocDevice = dlsym(ze_handle, "zeMemAllocDevice");
46+
*(void **)&g_ze_ops.zeMemFree = dlsym(ze_handle, "zeMemFree");
47+
48+
if (!g_ze_ops.zeMemAllocDevice || !g_ze_ops.zeMemFree) {
49+
fprintf(stderr, "Could not find symbols in %s.\n", so_name);
50+
dlclose(ze_handle);
51+
Init_ze_global_state_failed = true;
52+
return;
53+
}
54+
}
55+
56+
typedef struct ze_memory_provider_t {
57+
ze_context_handle_t context;
58+
ze_device_handle_t device;
59+
ze_device_mem_alloc_desc_t device_mem_alloc_desc;
60+
61+
// saved pointer to the global base allocator
62+
umf_ba_pool_t *base_allocator;
63+
} ze_memory_provider_t;
64+
65+
enum umf_result_t ze_memory_provider_initialize(void *params, void **provider) {
66+
level_zero_memory_provider_params_t *ze_params =
67+
(level_zero_memory_provider_params_t *)params;
68+
69+
util_init_once(&ze_is_initialized, init_ze_global_state);
70+
if (Init_ze_global_state_failed) {
71+
fprintf(stderr, "loading Level Zero symbols failed\n");
72+
return UMF_RESULT_ERROR_UNKNOWN;
73+
}
74+
75+
umf_ba_pool_t *base_allocator =
76+
umf_ba_get_pool(sizeof(ze_memory_provider_t));
77+
if (!base_allocator) {
78+
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
79+
}
80+
81+
ze_memory_provider_t *ze_provider = umf_ba_alloc(base_allocator);
82+
if (!ze_provider) {
83+
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
84+
}
85+
86+
if (ze_params->device_mem_alloc_desc.stype !=
87+
ZE_STRUCTURE_TYPE_DEVICE_MEM_ALLOC_DESC) {
88+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
89+
}
90+
91+
ze_provider->base_allocator = base_allocator;
92+
ze_provider->context = ze_params->context;
93+
ze_provider->device = ze_params->device;
94+
ze_provider->device_mem_alloc_desc = ze_params->device_mem_alloc_desc;
95+
96+
// TODO what about chained desc?
97+
assert(ze_params->device_mem_alloc_desc.pNext == NULL);
98+
99+
*provider = ze_provider;
100+
101+
return UMF_RESULT_SUCCESS;
102+
}
103+
104+
void ze_memory_provider_finalize(void *provider) {
105+
util_init_once(&ze_is_initialized, init_ze_global_state);
106+
107+
assert(provider);
108+
ze_memory_provider_t *ze_provider = (ze_memory_provider_t *)provider;
109+
umf_ba_free(ze_provider->base_allocator, ze_provider);
110+
}
111+
112+
static enum umf_result_t ze_memory_provider_alloc(void *provider, size_t size,
113+
size_t alignment,
114+
void **resultPtr) {
115+
assert(provider);
116+
assert(resultPtr);
117+
118+
ze_memory_provider_t *ze_provider = (ze_memory_provider_t *)provider;
119+
g_ze_ops.zeMemAllocDevice(ze_provider->context,
120+
&ze_provider->device_mem_alloc_desc, size,
121+
alignment, ze_provider->device, resultPtr);
122+
123+
return UMF_RESULT_SUCCESS;
124+
}
125+
126+
static enum umf_result_t ze_memory_provider_free(void *provider, void *ptr,
127+
size_t bytes) {
128+
(void)bytes;
129+
130+
assert(provider);
131+
ze_memory_provider_t *ze_provider = (ze_memory_provider_t *)provider;
132+
g_ze_ops.zeMemFree(ze_provider->context, ptr);
133+
134+
return UMF_RESULT_SUCCESS;
135+
}
136+
137+
void ze_memory_provider_get_last_native_error(void *provider,
138+
const char **ppMessage,
139+
int32_t *pError) {
140+
(void)provider;
141+
(void)ppMessage;
142+
143+
assert(pError);
144+
// TODO
145+
*pError = 0;
146+
}
147+
148+
static enum umf_result_t
149+
ze_memory_provider_get_min_page_size(void *provider, void *ptr,
150+
size_t *pageSize) {
151+
(void)provider;
152+
(void)ptr;
153+
154+
*pageSize = 1024 * 4; // TODO
155+
return UMF_RESULT_SUCCESS;
156+
}
157+
158+
static enum umf_result_t
159+
ze_memory_provider_get_recommended_page_size(void *provider, size_t size,
160+
size_t *pageSize) {
161+
(void)provider;
162+
(void)size;
163+
164+
*pageSize = 1024 * 4; // TODO
165+
return UMF_RESULT_SUCCESS;
166+
}
167+
168+
const char *ze_memory_provider_get_name(void *provider) {
169+
(void)provider;
170+
return "UMF_ZE_PROVIDER";
171+
}
172+
173+
static enum umf_result_t ze_memory_provider_allocation_merge(void *hProvider,
174+
void *lowPtr,
175+
void *highPtr,
176+
size_t totalSize) {
177+
(void)hProvider;
178+
(void)lowPtr;
179+
(void)highPtr;
180+
(void)totalSize;
181+
182+
return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC;
183+
}
184+
185+
static struct umf_memory_provider_ops_t UMF_LEVEL_ZERO_MEMORY_PROVIDER_OPS = {
186+
.version = UMF_VERSION_CURRENT,
187+
.initialize = ze_memory_provider_initialize,
188+
.finalize = ze_memory_provider_finalize,
189+
.alloc = ze_memory_provider_alloc,
190+
.free = ze_memory_provider_free,
191+
.get_last_native_error = ze_memory_provider_get_last_native_error,
192+
.get_recommended_page_size = ze_memory_provider_get_recommended_page_size,
193+
.get_min_page_size = ze_memory_provider_get_min_page_size,
194+
.purge_lazy = NULL,
195+
.purge_force = NULL,
196+
.get_name = ze_memory_provider_get_name,
197+
.allocation_split = NULL,
198+
.allocation_merge = ze_memory_provider_allocation_merge,
199+
};
200+
201+
umf_memory_provider_ops_t *umfLevelZeroMemoryProviderOps(void) {
202+
return &UMF_LEVEL_ZERO_MEMORY_PROVIDER_OPS;
203+
}

0 commit comments

Comments
 (0)