Skip to content

add an example for combination of Disjoint Pool and L0 #384

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
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
6 changes: 6 additions & 0 deletions .github/workflows/gpu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ jobs:
-DUMF_BUILD_BENCHMARKS=ON
-DUMF_BUILD_TESTS=ON
-DUMF_BUILD_GPU_TESTS=ON
-DUMF_BUILD_GPU_EXAMPLES=ON
-DUMF_FORMAT_CODE_STYLE=ON
-DUMF_DEVELOPER_MODE=ON
-DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON
Expand All @@ -52,3 +53,8 @@ jobs:
- name: Run tests
working-directory: ${{github.workspace}}/build
run: ctest --output-on-failure --test-dir test

- name: Run examples
working-directory: ${{github.workspace}}/build
run: ctest --output-on-failure --test-dir examples -C ${{matrix.build_type}}

4 changes: 3 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ option(UMF_BUILD_GPU_TESTS "Build UMF GPU tests" OFF)
option(UMF_BUILD_BENCHMARKS "Build UMF benchmarks" OFF)
option(UMF_BUILD_BENCHMARKS_MT "Build UMF multithreaded benchmarks" OFF)
option(UMF_BUILD_EXAMPLES "Build UMF examples" ON)
option(UMF_BUILD_GPU_EXAMPLES "Build UMF GPU examples" OFF)
option(UMF_ENABLE_POOL_TRACKING "Build UMF with pool tracking" ON)
option(UMF_DEVELOPER_MODE "Enable developer checks, treats warnings as errors"
OFF)
Expand Down Expand Up @@ -435,7 +436,8 @@ endif()
install(FILES ${CMAKE_SOURCE_DIR}/LICENSE.TXT
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME}/")

install(FILES examples/basic/basic.c
install(FILES examples/basic/gpu_shared_memory.c
examples/basic/utils_level_zero.h examples/basic/basic.c
DESTINATION "${CMAKE_INSTALL_DOCDIR}/examples")

# Add the include directory and the headers target to the install.
Expand Down
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,13 @@ The Unified Memory Framework (UMF) is a library for constructing allocators and

## Usage

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

## Build

Expand Down Expand Up @@ -100,6 +105,7 @@ List of options provided by CMake:
| UMF_BUILD_GPU_TESTS | Build UMF GPU tests | ON/OFF | OFF |
| UMF_BUILD_BENCHMARKS | Build UMF benchmarks | ON/OFF | OFF |
| UMF_BUILD_EXAMPLES | Build UMF examples | ON/OFF | ON |
| UMF_BUILD_GPU_EXAMPLES | Build UMF GPU examples | ON/OFF | OFF |
| UMF_ENABLE_POOL_TRACKING | Build UMF with pool tracking | ON/OFF | ON |
| UMF_DEVELOPER_MODE | Treat warnings as errors and enables additional checks | ON/OFF | OFF |
| UMF_FORMAT_CODE_STYLE | Add clang, cmake, and black -format-check and -format-apply targets to make | ON/OFF | OFF |
Expand Down
40 changes: 38 additions & 2 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,41 @@ if(UMF_BUILD_LIBUMF_POOL_SCALABLE AND UMF_ENABLE_POOL_TRACKING)

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

if(WINDOWS)
# append PATH to DLLs
set_property(TEST ${EXAMPLE_NAME} PROPERTY ENVIRONMENT_MODIFICATION
"${DLL_PATH_LIST}")
endif()
else()
message(STATUS "Basic example requires UMF_BUILD_LIBUMF_POOL_SCALABLE and "
"UMF_ENABLE_POOL_TRACKING to be turned ON - skipping")
endif()

if(UMF_BUILD_GPU_EXAMPLES
AND UMF_BUILD_LIBUMF_POOL_DISJOINT
AND UMF_BUILD_LEVEL_ZERO_PROVIDER
AND LINUX)
set(EXAMPLE_NAME umf_example_gpu_shared_memory)

add_umf_executable(
NAME ${EXAMPLE_NAME}
SRCS basic/gpu_shared_memory.c
LIBS umf disjoint_pool ze_loader)

target_include_directories(
${EXAMPLE_NAME}
PRIVATE ${LEVEL_ZERO_INCLUDE_DIRS} ${UMF_CMAKE_SOURCE_DIR}/src/utils
${UMF_CMAKE_SOURCE_DIR}/include)

target_link_directories(${EXAMPLE_NAME} PRIVATE ${LIBHWLOC_LIBRARY_DIRS})

add_test(
NAME ${EXAMPLE_NAME}
COMMAND ${EXAMPLE_NAME}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})

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

if(WINDOWS)
# append PATH to DLLs
set_property(TEST ${EXAMPLE_NAME} PROPERTY ENVIRONMENT_MODIFICATION
Expand All @@ -31,6 +66,7 @@ if(UMF_BUILD_LIBUMF_POOL_SCALABLE AND UMF_ENABLE_POOL_TRACKING)
else()
message(
STATUS
"Basic example requires UMF_BUILD_LIBUMF_POOL_SCALABLE and UMF_ENABLE_POOL_TRACKING
to be turned ON - skipping")
"GPU shared memory example requires UMF_BUILD_GPU_EXAMPLES, "
"UMF_BUILD_LEVEL_ZERO_PROVIDER and UMF_BUILD_LIBUMF_POOL_DISJOINT "
Copy link
Contributor

Choose a reason for hiding this comment

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

This message is incorrect. Please fix it to include build GPU examples variable.

(BTW do we really need "UMF_BUILD_GPU_EXAMPLES" variable - imho if all dependencies are ON, we should build it by default)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

Copy link
Contributor

Choose a reason for hiding this comment

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

I second the question - do we need extra UMF_BUILD_GPU_EXAMPLES option? We could enable testing this example if UMF_BUILD_GPU_TESTS is ON.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Testing (what we actually run) has nothing to do with the build options. UMF_BUILD_GPU_TESTS is used for building, not testing. If you want to extend this flag, rename it UMF_BUILD_GPU_TESTS_AND_EXAMPLES or UMG_BUILD_GPU_CODE etc. I agree that we could do some cleanup in build flags - could we address this in additional PR?

Copy link
Contributor

Choose a reason for hiding this comment

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

What I'm saying, is we could (as Łukasz stated above) build it all the time, as long as L0_PROVIDER is ON. We don't need this new flag just for building.

Nontheless, I guess, we could clean flags separately later on...

Copy link
Contributor

Choose a reason for hiding this comment

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

I believe we need a dedicated cmake option for GPU examples (UMF_BUILD_GPU_EXAMPLES). After the #427 is implemented we will have examples that will be installed with a pre-built version of UMF. So customer needs an option to disable/enable GPU examples.

Copy link
Contributor

@PatKamin PatKamin Apr 10, 2024

Choose a reason for hiding this comment

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

I think that this extra flag is not needed as when it is turned ON but the two other flags are not, nothing happens. I think that existing flag UMF_BUILD_EXAMPLES suffices. If the user wants to have examples build, then all examples for a given config options set will be built.

As it is now, the user would have to set both UMF_BUILD_EXAMPLES and UMF_BUILD_GPU_EXAMPLES flags to build this example. Seeing these two options in CMake I would expect that only the second one is needed for building the GPU examples.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think that all changes around cmake files, flags and folders could be done as a part of #427

"to be turned ON - skipping")
endif()
28 changes: 23 additions & 5 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,29 @@
# Examples

This directory contains examples of UMF usage. Each example has a brief description below.
This directory contains examples of UMF usage. Each example has a brief
description below.

## Basic

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.
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.

### Required CMake configuration flags
* UMF_BUILD_LIBUMF_POOL_SCALABLE=ON
* UMF_ENABLE_POOL_TRACKING=ON
### Requirements
* libtbb-dev needed for Scalable Pool
* set UMF_BUILD_LIBUMF_POOL_SCALABLE and UMF_ENABLE_POOL_TRACKING CMake
configuration flags to ON

## GPU shared memory

This example demonstrates the usage of Intel's Level Zero API for accessing GPU
memory. It initializes the Level Zero driver, discovers all the driver
instances, and creates GPU context for the first found GPU device. Next, it
sets up a combination of UMF Level Zero memory provider and a Disjoint Pool
memory pool to allocate from shared memory. If any step fails, the program
cleans up and exits with an error status.

### Requirements
* Level Zero headers and libraries
* compatible GPU with installed driver
* set UMF_BUILD_GPU_EXAMPLES, UMF_BUILD_LIBUMF_POOL_DISJOINT and UMF_BUILD_LEVEL_ZERO_PROVIDER CMake configuration flags to ON
130 changes: 130 additions & 0 deletions examples/basic/gpu_shared_memory.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*
*
* Copyright (C) 2024 Intel Corporation
*
* Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*
*/

#include <umf/memory_pool.h>
#include <umf/pools/pool_disjoint.h>
#include <umf/providers/provider_level_zero.h>

#include "utils_level_zero.h"

int main(void) {
// A result object for storing UMF API result status
umf_result_t res;

uint32_t driverId = 0;
ze_driver_handle_t hDriver = NULL;
ze_device_handle_t hDevice = NULL;
ze_context_handle_t hContext = NULL;

// Initialize Level Zero
int ret = init_level_zero();
if (ret != 0) {
fprintf(stderr, "Failed to init Level 0!\n");
return ret;
}

ret = find_driver_with_gpu(&driverId, &hDriver);
if (ret || hDriver == NULL) {
fprintf(stderr, "Cannot find L0 driver with GPU device!\n");
return ret;
}

ret = find_gpu_device(hDriver, &hDevice);
if (ret || hDevice == NULL) {
fprintf(stderr, "Cannot find GPU device!\n");
return ret;
}

ret = create_context(hDriver, &hContext);
if (ret != 0) {
fprintf(stderr, "Failed to create L0 context!\n");
return ret;
}

// Setup parameters for the Level Zero memory provider. It will be used for
// allocating memory from Level Zero devices.
level_zero_memory_provider_params_t ze_memory_provider_params;
ze_memory_provider_params.level_zero_context_handle = hContext;
ze_memory_provider_params.level_zero_device_handle = hDevice;
// Set the memory type to shared to allow the memory to be accessed on both
// CPU and GPU.
ze_memory_provider_params.memory_type = UMF_MEMORY_TYPE_SHARED;

// Create Level Zero memory provider
umf_memory_provider_handle_t ze_memory_provider;
res = umfMemoryProviderCreate(umfLevelZeroMemoryProviderOps(),
&ze_memory_provider_params,
&ze_memory_provider);
if (res != UMF_RESULT_SUCCESS) {
fprintf(stderr, "Failed to create a memory provider!\n");
ret = -1;
goto level_zero_destroy;
}

printf("Level Zero memory provider created at %p\n",
(void *)ze_memory_provider);

// Setup parameters for the Disjoint Pool. It will be used for managing the
// memory allocated using memory provider.
umf_disjoint_pool_params_t disjoint_memory_pool_params =
umfDisjointPoolParamsDefault();
// Set the Slab Min Size to 64KB - the page size for GPU allocations
disjoint_memory_pool_params.SlabMinSize = 64 * 1024L;
// We would keep only single slab per each allocation bucket
disjoint_memory_pool_params.Capacity = 1;
// Set the maximum poolable size to 64KB - objects with size above this
// limit will not be stored/allocated from the pool.
disjoint_memory_pool_params.MaxPoolableSize = 64 * 1024L;
// Enable tracing
disjoint_memory_pool_params.PoolTrace = 1;

// Create Disjoint Pool memory pool.
umf_memory_pool_handle_t ze_disjoint_memory_pool;
res = umfPoolCreate(umfDisjointPoolOps(), ze_memory_provider,
&disjoint_memory_pool_params, UMF_POOL_CREATE_FLAG_NONE,
&ze_disjoint_memory_pool);
if (res != UMF_RESULT_SUCCESS) {
fprintf(stderr, "Failed to create a memory pool!\n");
ret = -1;
goto memory_provider_destroy;
}

printf("Disjoint Pool created at %p\n", (void *)ze_disjoint_memory_pool);

// Allocate some memory from the pool
int *ptr = umfPoolMalloc(ze_disjoint_memory_pool, sizeof(int));
if (res != UMF_RESULT_SUCCESS) {
fprintf(stderr, "Failed to allocate memory from the memory pool!\n");
ret = -1;
goto memory_pool_destroy;
}

// Use allocated memory
*ptr = 1;

// Free allocated memory
res = umfFree(ptr);
if (res != UMF_RESULT_SUCCESS) {
fprintf(stderr, "Failed to free memory to the pool!\n");
ret = -1;
goto memory_pool_destroy;
}
printf("Freed memory at %p\n", (void *)ptr);

// Cleanup
memory_pool_destroy:
umfPoolDestroy(ze_disjoint_memory_pool);

memory_provider_destroy:
umfMemoryProviderDestroy(ze_memory_provider);

level_zero_destroy:
ret = destroy_context(hContext);
return ret;
}
Loading