Skip to content

Commit f092d2e

Browse files
committed
add an example for mix of Disjoint Pool and L0
1 parent e331e55 commit f092d2e

File tree

10 files changed

+468
-19
lines changed

10 files changed

+468
-19
lines changed

.github/workflows/gpu.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ jobs:
4141
-DUMF_BUILD_BENCHMARKS=ON
4242
-DUMF_BUILD_TESTS=ON
4343
-DUMF_BUILD_GPU_TESTS=ON
44+
-DUMF_BUILD_GPU_EXAMPLES=ON
4445
-DUMF_FORMAT_CODE_STYLE=ON
4546
-DUMF_DEVELOPER_MODE=ON
4647
-DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON

CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ option(UMF_BUILD_GPU_TESTS "Build UMF GPU tests" OFF)
2222
option(UMF_BUILD_BENCHMARKS "Build UMF benchmarks" OFF)
2323
option(UMF_BUILD_BENCHMARKS_MT "Build UMF multithreaded benchmarks" OFF)
2424
option(UMF_BUILD_EXAMPLES "Build UMF examples" ON)
25+
option(UMF_BUILD_GPU_EXAMPLES "Build UMF GPU examples" OFF)
2526
option(UMF_ENABLE_POOL_TRACKING "Build UMF with pool tracking" ON)
2627
option(UMF_DEVELOPER_MODE "Enable developer checks, treats warnings as errors"
2728
OFF)
@@ -435,7 +436,8 @@ endif()
435436
install(FILES ${CMAKE_SOURCE_DIR}/LICENSE.TXT
436437
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME}/")
437438

438-
install(FILES examples/basic/basic.c
439+
install(FILES examples/basic/gpu_shared_memory.c
440+
examples/basic/utils_level_zero.h examples/basic/basic.c
439441
DESTINATION "${CMAKE_INSTALL_DOCDIR}/examples")
440442

441443
# Add the include directory and the headers target to the install.

README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,13 @@ The Unified Memory Framework (UMF) is a library for constructing allocators and
1717

1818
## Usage
1919

20-
For a quick introduction to UMF usage, see [Example usage](https://oneapi-src.github.io/unified-memory-framework/example-usage.html),
21-
which includes the code of the basic [example](https://github.com/oneapi-src/unified-memory-framework/blob/main/examples/basic/basic.c).
20+
For a quick introduction to UMF usage, please see
21+
[examples](https://oneapi-src.github.io/unified-memory-framework/examples.html)
22+
documentation, which includes the code of the
23+
[basic example](https://github.com/oneapi-src/unified-memory-framework/blob/main/examples/basic/basic.c)
24+
and the more advanced one that allocates
25+
[USM memory from the GPU device](https://github.com/oneapi-src/unified-memory-framework/blob/main/examples/basic/gpu_shared_memory.c)
26+
using the Level Zero API and UMF Level Zero memory provider.
2227

2328
## Build
2429

@@ -100,6 +105,7 @@ List of options provided by CMake:
100105
| UMF_BUILD_GPU_TESTS | Build UMF GPU tests | ON/OFF | OFF |
101106
| UMF_BUILD_BENCHMARKS | Build UMF benchmarks | ON/OFF | OFF |
102107
| UMF_BUILD_EXAMPLES | Build UMF examples | ON/OFF | ON |
108+
| UMF_BUILD_GPU_EXAMPLES | Build UMF GPU examples | ON/OFF | OFF |
103109
| UMF_ENABLE_POOL_TRACKING | Build UMF with pool tracking | ON/OFF | ON |
104110
| UMF_DEVELOPER_MODE | Treat warnings as errors and enables additional checks | ON/OFF | OFF |
105111
| UMF_FORMAT_CODE_STYLE | Add clang, cmake, and black -format-check and -format-apply targets to make | ON/OFF | OFF |

examples/CMakeLists.txt

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,41 @@ if(UMF_BUILD_LIBUMF_POOL_SCALABLE AND UMF_ENABLE_POOL_TRACKING)
2323

2424
set_tests_properties(${EXAMPLE_NAME} PROPERTIES LABELS "example")
2525

26+
if(WINDOWS)
27+
# append PATH to DLLs
28+
set_property(TEST ${EXAMPLE_NAME} PROPERTY ENVIRONMENT_MODIFICATION
29+
"${DLL_PATH_LIST}")
30+
endif()
31+
else()
32+
message(STATUS "Basic example requires UMF_BUILD_LIBUMF_POOL_SCALABLE and "
33+
"UMF_ENABLE_POOL_TRACKING to be turned ON - skipping")
34+
endif()
35+
36+
if(UMF_BUILD_GPU_EXAMPLES
37+
AND UMF_BUILD_LIBUMF_POOL_DISJOINT
38+
AND UMF_BUILD_LEVEL_ZERO_PROVIDER
39+
AND LINUX)
40+
set(EXAMPLE_NAME umf_example_gpu_shared_memory)
41+
42+
add_umf_executable(
43+
NAME ${EXAMPLE_NAME}
44+
SRCS basic/gpu_shared_memory.c
45+
LIBS umf disjoint_pool ze_loader)
46+
47+
target_include_directories(
48+
${EXAMPLE_NAME}
49+
PRIVATE ${LEVEL_ZERO_INCLUDE_DIRS} ${UMF_CMAKE_SOURCE_DIR}/src/utils
50+
${UMF_CMAKE_SOURCE_DIR}/include)
51+
52+
target_link_directories(${EXAMPLE_NAME} PRIVATE ${LIBHWLOC_LIBRARY_DIRS})
53+
54+
add_test(
55+
NAME ${EXAMPLE_NAME}
56+
COMMAND ${EXAMPLE_NAME}
57+
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
58+
59+
set_tests_properties(${EXAMPLE_NAME} PROPERTIES LABELS "example")
60+
2661
if(WINDOWS)
2762
# append PATH to DLLs
2863
set_property(TEST ${EXAMPLE_NAME} PROPERTY ENVIRONMENT_MODIFICATION
@@ -31,6 +66,7 @@ if(UMF_BUILD_LIBUMF_POOL_SCALABLE AND UMF_ENABLE_POOL_TRACKING)
3166
else()
3267
message(
3368
STATUS
34-
"Basic example requires UMF_BUILD_LIBUMF_POOL_SCALABLE and UMF_ENABLE_POOL_TRACKING
35-
to be turned ON - skipping")
69+
"GPU shared memory example requires UMF_BUILD_GPU_EXAMPLES, "
70+
"UMF_BUILD_LEVEL_ZERO_PROVIDER and UMF_BUILD_LIBUMF_POOL_DISJOINT "
71+
"to be turned ON - skipping")
3672
endif()

examples/README.md

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,29 @@
11
# Examples
22

3-
This directory contains examples of UMF usage. Each example has a brief description below.
3+
This directory contains examples of UMF usage. Each example has a brief
4+
description below.
45

56
## Basic
67

7-
This example covers the basics of UMF API. It walks you through a basic usage of a memory provider and a pool allocator. OS memory provider and Scalable pool are used for this purpose.
8+
This example covers the basics of UMF API. It walks you through a basic usage
9+
of a memory provider and a pool allocator. OS memory provider and Scalable pool
10+
are used for this purpose.
811

9-
### Required CMake configuration flags
10-
* UMF_BUILD_LIBUMF_POOL_SCALABLE=ON
11-
* UMF_ENABLE_POOL_TRACKING=ON
12+
### Requirements
13+
* libtbb-dev needed for Scalable Pool
14+
* set UMF_BUILD_LIBUMF_POOL_SCALABLE and UMF_ENABLE_POOL_TRACKING CMake
15+
configuration flags to ON
16+
17+
## GPU shared memory
18+
19+
This example demonstrates the usage of Intel's Level Zero API for accessing GPU
20+
memory. It initializes the Level Zero driver, discovers all the driver
21+
instances, and creates GPU context for the first found GPU device. Next, it
22+
sets up a combination of UMF Level Zero memory provider and a Disjoint Pool
23+
memory pool to allocate from shared memory. If any step fails, the program
24+
cleans up and exits with an error status.
25+
26+
### Requirements
27+
* Level Zero headers and libraries
28+
* compatible GPU with installed driver
29+
* set UMF_BUILD_GPU_EXAMPLES, UMF_BUILD_LIBUMF_POOL_DISJOINT and UMF_BUILD_LEVEL_ZERO_PROVIDER CMake configuration flags to ON

examples/basic/gpu_shared_memory.c

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
/*
2+
*
3+
* Copyright (C) 2024 Intel Corporation
4+
*
5+
* Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
6+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
*
8+
*/
9+
10+
#include <umf/memory_pool.h>
11+
#include <umf/pools/pool_disjoint.h>
12+
#include <umf/providers/provider_level_zero.h>
13+
14+
#include "utils_level_zero.h"
15+
16+
int main(void) {
17+
// A result object for storing UMF API result status
18+
umf_result_t res;
19+
20+
uint32_t driverId = 0;
21+
ze_driver_handle_t hDriver = NULL;
22+
ze_device_handle_t hDevice = NULL;
23+
ze_context_handle_t hContext = NULL;
24+
25+
// Initialize Level Zero
26+
int ret = init_level_zero();
27+
if (ret != 0) {
28+
fprintf(stderr, "Failed to init Level 0!\n");
29+
return ret;
30+
}
31+
32+
ret = find_driver_with_gpu(&driverId, &hDriver);
33+
if (ret || hDriver == NULL) {
34+
fprintf(stderr, "Cannot find L0 driver with GPU device!\n");
35+
return ret;
36+
}
37+
38+
ret = find_gpu_device(hDriver, &hDevice);
39+
if (ret || hDevice == NULL) {
40+
fprintf(stderr, "Cannot find GPU device!\n");
41+
return ret;
42+
}
43+
44+
ret = create_context(hDriver, &hContext);
45+
if (ret != 0) {
46+
fprintf(stderr, "Failed to create L0 context!\n");
47+
return ret;
48+
}
49+
50+
// Setup parameters for the Level Zero memory provider. It will be used for
51+
// allocating memory from Level Zero devices.
52+
level_zero_memory_provider_params_t ze_memory_provider_params;
53+
ze_memory_provider_params.level_zero_context_handle = hContext;
54+
ze_memory_provider_params.level_zero_device_handle = hDevice;
55+
// Set the memory type to shared to allow the memory to be accessed on both
56+
// CPU and GPU.
57+
ze_memory_provider_params.memory_type = UMF_MEMORY_TYPE_SHARED;
58+
59+
// Create Level Zero memory provider
60+
umf_memory_provider_handle_t ze_memory_provider;
61+
res = umfMemoryProviderCreate(umfLevelZeroMemoryProviderOps(),
62+
&ze_memory_provider_params,
63+
&ze_memory_provider);
64+
if (res != UMF_RESULT_SUCCESS) {
65+
fprintf(stderr, "Failed to create a memory provider!\n");
66+
ret = -1;
67+
goto level_zero_destroy;
68+
}
69+
70+
printf("Level Zero memory provider created at %p\n",
71+
(void *)ze_memory_provider);
72+
73+
// Setup parameters for the Disjoint Pool. It will be used for managing the
74+
// memory allocated using memory provider.
75+
umf_disjoint_pool_params_t disjoint_memory_pool_params =
76+
umfDisjointPoolParamsDefault();
77+
// Set the Slab Min Size to 64KB - the page size for GPU allocations
78+
disjoint_memory_pool_params.SlabMinSize = 64 * 1024L;
79+
// We would keep only single slab per each allocation bucket
80+
disjoint_memory_pool_params.Capacity = 1;
81+
// Set the maximum poolable size to 64KB - objects with size above this
82+
// limit will not be stored/allocated from the pool.
83+
disjoint_memory_pool_params.MaxPoolableSize = 64 * 1024L;
84+
// Enable tracing
85+
disjoint_memory_pool_params.PoolTrace = 1;
86+
87+
// Create Disjoint Pool memory pool.
88+
umf_memory_pool_handle_t ze_disjoint_memory_pool;
89+
res = umfPoolCreate(umfDisjointPoolOps(), ze_memory_provider,
90+
&disjoint_memory_pool_params, UMF_POOL_CREATE_FLAG_NONE,
91+
&ze_disjoint_memory_pool);
92+
if (res != UMF_RESULT_SUCCESS) {
93+
fprintf(stderr, "Failed to create a memory pool!\n");
94+
ret = -1;
95+
goto memory_provider_destroy;
96+
}
97+
98+
printf("Disjoint Pool created at %p\n", (void *)ze_disjoint_memory_pool);
99+
100+
// Allocate some memory from the pool
101+
int *ptr = (int *)umfPoolMalloc(ze_disjoint_memory_pool, sizeof(int));
102+
if (res != UMF_RESULT_SUCCESS) {
103+
fprintf(stderr, "Failed to allocate memory from the memory pool!\n");
104+
ret = -1;
105+
goto memory_pool_destroy;
106+
}
107+
108+
// Use allocated memory
109+
*ptr = 1;
110+
111+
// Free allocated memory
112+
res = umfFree(ptr);
113+
if (res != UMF_RESULT_SUCCESS) {
114+
fprintf(stderr, "Failed to free memory to the pool!\n");
115+
ret = -1;
116+
goto memory_pool_destroy;
117+
}
118+
printf("Freed memory at %p\n", (void *)ptr);
119+
120+
// Cleanup
121+
memory_pool_destroy:
122+
umfPoolDestroy(ze_disjoint_memory_pool);
123+
124+
memory_provider_destroy:
125+
umfMemoryProviderDestroy(ze_memory_provider);
126+
127+
level_zero_destroy:
128+
ret = destroy_context(hContext);
129+
return ret;
130+
}

0 commit comments

Comments
 (0)