Skip to content

Commit 7600f95

Browse files
committed
Add a basic example
Add an example with allocating memory with the usage of OS memory provider and Scalable pool.
1 parent 6a76bec commit 7600f95

File tree

14 files changed

+342
-2
lines changed

14 files changed

+342
-2
lines changed

.github/workflows/basic.yml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ jobs:
5555
-DUSE_ASAN=${{matrix.sanitizers.asan}}
5656
-DUSE_UBSAN=${{matrix.sanitizers.ubsan}}
5757
-DUSE_TSAN=${{matrix.sanitizers.tsan}}
58+
-DUMF_BUILD_EXAMPLES=ON
5859
5960
- name: Build UMF
6061
run: |
@@ -63,14 +64,18 @@ jobs:
6364
- name: Run tests
6465
working-directory: ${{github.workspace}}/build
6566
run: |
66-
ctest --output-on-failure
67+
ctest --output-on-failure --test-dir test
6768
6869
- name: Test make install
70+
# Run only when the example is built
71+
if: matrix.os_provider == 'ON' && matrix.pool_tracking == 'ON'
6972
working-directory: ${{env.BUILD_DIR}}
7073
run: ${{github.workspace}}/test/test_make_install.sh \
7174
${{github.workspace}} ${{env.BUILD_DIR}} ${{env.INSTL_DIR}} ${{matrix.build_type}} ${{matrix.shared_library}}
7275

7376
- name: Test make uninstall
77+
# Run only when the example is built
78+
if: matrix.os_provider == 'ON' && matrix.pool_tracking == 'ON'
7479
working-directory: ${{env.BUILD_DIR}}
7580
run: ${{github.workspace}}/test/test_make_uninstall.sh ${{github.workspace}} ${{env.BUILD_DIR}} ${{env.INSTL_DIR}}
7681

@@ -194,11 +199,17 @@ jobs:
194199
ctest --output-on-failure
195200
196201
- name: Test make install
202+
# Run only when the example is built
203+
# TODO: Modify installation test to accept output varying with build options
204+
if: matrix.os_provider == 'ON' && matrix.pool_tracking == 'ON'
197205
working-directory: ${{env.BUILD_DIR}}
198206
run: ${{github.workspace}}/test/test_make_install.sh \
199207
${{github.workspace}} ${{env.BUILD_DIR}} ${{env.INSTL_DIR}} ${{matrix.build_type}} ${{matrix.shared_library}}
200208

201209
- name: Test make uninstall
210+
# Run only when the example is built
211+
# TODO: Modify installation test to accept output varying with build options
212+
if: matrix.os_provider == 'ON' && matrix.pool_tracking == 'ON'
202213
working-directory: ${{env.BUILD_DIR}}
203214
run: ${{github.workspace}}/test/test_make_uninstall.sh ${{github.workspace}} ${{env.BUILD_DIR}} ${{env.INSTL_DIR}}
204215

.github/workflows/pr_push.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,17 @@ jobs:
4949
-DUMF_BUILD_LIBUMF_POOL_DISJOINT=${{matrix.disjoint}}
5050
-DUMF_BUILD_LIBUMF_POOL_JEMALLOC=${{matrix.jemalloc}}
5151
-DUMF_BUILD_TESTS=OFF
52+
-DUMF_BUILD_EXAMPLES=ON
5253
5354
- name: Build
5455
run: >
5556
cmake --build ${{github.workspace}}/build --config Release -j ${{matrix.nproc}}
5657
58+
- name: Run examples
59+
working-directory: ${{github.workspace}}/build
60+
run: |
61+
ctest --output-on-failure --test-dir examples
62+
5763
CodeStyle:
5864
name: Coding style
5965
runs-on: ubuntu-latest

CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ option(UMF_BUILD_LIBUMF_POOL_SCALABLE "Build the libumf_pool_scalable static lib
1414
option(UMF_BUILD_TESTS "Build UMF tests" ON)
1515
option(UMF_BUILD_BENCHMARKS "Build UMF benchmarks" OFF)
1616
option(UMF_BUILD_BENCHMARKS_MT "Build UMF multithreaded benchmarks" OFF)
17+
option(UMF_BUILD_EXAMPLES "Build UMF examples" ON)
1718
option(UMF_ENABLE_POOL_TRACKING "Build UMF with pool tracking" ON)
1819
option(UMF_DEVELOPER_MODE "Enable developer checks, treats warnings as errors" OFF)
1920
option(UMF_FORMAT_CODE_STYLE "Format UMF code with clang-format" OFF)
@@ -123,6 +124,10 @@ if(UMF_BUILD_BENCHMARKS)
123124
endif()
124125
endif()
125126

127+
if(UMF_BUILD_EXAMPLES)
128+
add_subdirectory(examples)
129+
endif()
130+
126131
# Check if clang-format (in correct version) is available for code formatting.
127132
if(UMF_FORMAT_CODE_STYLE)
128133
find_program(CLANG_FORMAT NAMES clang-format-15 clang-format-15.0 clang-format)

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ List of options provided by CMake:
8989
| UMF_BUILD_LIBUMF_POOL_SCALABLE | Build the libumf_pool_scalable static library | ON/OFF | OFF |
9090
| UMF_BUILD_TESTS | Build UMF tests | ON/OFF | ON |
9191
| UMF_BUILD_BENCHMARKS | Build UMF benchmarks | ON/OFF | OFF |
92+
| UMF_BUILD_EXAMPLES | Build UMF examples | ON/OFF | ON |
9293
| UMF_ENABLE_POOL_TRACKING | Build UMF with pool tracking | ON/OFF | ON |
9394
| UMF_DEVELOPER_MODE | Treat warnings as errors and enables additional checks | ON/OFF | OFF |
9495
| UMF_FORMAT_CODE_STYLE | Add clang-format-check and clang-format-apply targets to make | ON/OFF | OFF |

examples/CMakeLists.txt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
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_OS_MEMORY_PROVIDER
6+
AND UMF_BUILD_LIBUMF_POOL_SCALABLE
7+
AND UMF_ENABLE_POOL_TRACKING)
8+
set(EXAMPLE_NAME umf_example_basic)
9+
add_umf_executable(NAME ${EXAMPLE_NAME}
10+
SRCS basic/basic.c
11+
LIBS umf
12+
scalable_pool)
13+
target_include_directories(${EXAMPLE_NAME} PRIVATE
14+
${UMF_CMAKE_SOURCE_DIR}/include)
15+
16+
add_test(NAME ${EXAMPLE_NAME}
17+
COMMAND ${EXAMPLE_NAME}
18+
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
19+
20+
set_tests_properties(${EXAMPLE_NAME} PROPERTIES LABELS "example")
21+
22+
install(FILES basic/basic.c
23+
DESTINATION "${CMAKE_INSTALL_DOCDIR}/examples")
24+
25+
else()
26+
message(STATUS "Basic example requires UMF_BUILD_OS_MEMORY_PROVIDER,
27+
UMF_BUILD_LIBUMF_POOL_SCALABLE and UMF_ENABLE_POOL_TRACKING
28+
to be turned ON - skipping")
29+
endif()

examples/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Examples
2+
3+
This directory contains examples of UMF usage. Each example has a brief description below.
4+
5+
## Basic
6+
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+
9+
### Required CMake configuration flags
10+
* UMF_BUILD_OS_MEMORY_PROVIDER=ON
11+
* UMF_BUILD_LIBUMF_POOL_SCALABLE=ON
12+
* UMF_ENABLE_POOL_TRACKING=ON

examples/basic/basic.c

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
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/pools/pool_scalable.h"
11+
#include "umf/providers/provider_os_memory.h"
12+
13+
#include <stdio.h>
14+
#include <string.h>
15+
16+
int main(void) {
17+
// A result object for storing UMF API result status
18+
umf_result_t res;
19+
20+
// Create an OS memory provider. It is used for allocating memory from
21+
// NUMA nodes visible to the operating system.
22+
// Allocations are made with mmap. The default values of params result
23+
// in an mmap call like this:
24+
// mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)
25+
umf_memory_provider_ops_t *provider_ops = umfOsMemoryProviderOps();
26+
umf_os_memory_provider_params_t params = umfOsMemoryProviderParamsDefault();
27+
umf_memory_provider_handle_t provider;
28+
29+
res = umfMemoryProviderCreate(provider_ops, &params, &provider);
30+
if (res != UMF_RESULT_SUCCESS) {
31+
printf("Failed to create a memory provider!");
32+
return -1;
33+
}
34+
printf("OS memory provider created at %p\n", (void *)provider);
35+
36+
// Allocate memory from memory provider
37+
size_t alloc_size = 5000;
38+
size_t alignment = 0;
39+
void *ptr_provider = NULL;
40+
41+
res =
42+
umfMemoryProviderAlloc(provider, alloc_size, alignment, &ptr_provider);
43+
if (res != UMF_RESULT_SUCCESS) {
44+
printf("Failed to allocate memory from the memory provider!");
45+
goto memory_provider_destroy;
46+
}
47+
48+
// Write to the allocated memory
49+
memset(ptr_provider, '\0', alloc_size);
50+
strcpy(ptr_provider, "Allocated memory at");
51+
printf("%s %p with the memory provider at %p\n", (char *)ptr_provider,
52+
(void *)ptr_provider, (void *)provider);
53+
54+
// Free allocated memory
55+
res = umfMemoryProviderFree(provider, ptr_provider, alloc_size);
56+
if (res != UMF_RESULT_SUCCESS) {
57+
printf("Failed to free memory to the provider!");
58+
goto memory_provider_destroy;
59+
}
60+
printf("Freed memory at %p\n", ptr_provider);
61+
62+
// Create a memory pool
63+
umf_memory_pool_ops_t *pool_ops = umfScalablePoolOps();
64+
void *pool_params = NULL;
65+
umf_pool_create_flags_t flags = 0;
66+
umf_memory_pool_handle_t pool;
67+
68+
res = umfPoolCreate(pool_ops, provider, pool_params, flags, &pool);
69+
if (res != UMF_RESULT_SUCCESS) {
70+
printf("\nFailed to create a pool!");
71+
goto memory_provider_destroy;
72+
}
73+
printf("\nScalable memory pool created at %p\n", (void *)pool);
74+
75+
// Allocate some memory in the pool
76+
size_t num = 1;
77+
alloc_size = 128;
78+
79+
char *ptr = umfPoolCalloc(pool, num, alloc_size);
80+
if (!ptr) {
81+
printf("Failed to allocate memory in the pool!");
82+
goto memory_pool_destroy;
83+
}
84+
85+
// Write a string to allocated memory
86+
strcpy(ptr, "Allocated memory at");
87+
printf("%s %p\n", ptr, (void *)ptr);
88+
89+
// Retrieve a memory pool from a pointer, available with memory tracking
90+
umf_memory_pool_handle_t check_pool = umfPoolByPtr(ptr);
91+
printf("Memory at %p has been allocated from the pool at %p\n", (void *)ptr,
92+
(void *)check_pool);
93+
94+
// Retrieve a memory provider from a pool
95+
umf_memory_provider_handle_t check_provider;
96+
res = umfPoolGetMemoryProvider(pool, &check_provider);
97+
if (res != UMF_RESULT_SUCCESS) {
98+
printf("Failed to retrieve a memory provider for the pool!");
99+
goto memory_pool_destroy;
100+
}
101+
printf("Pool at %p has been allocated from the provider at %p\n",
102+
(void *)pool, (void *)check_provider);
103+
104+
// Clean up.
105+
// To free a pointer using the umfFree(ptr) function, ensure that memory tracking is enabled
106+
// by setting the UMF_ENABLE_POOL_TRACKING option in the CMake configuration.
107+
// If the memory tracking is disabled, you can call a different function:
108+
// umfPoolFree(pool, ptr);
109+
umfFree(ptr);
110+
umfPoolDestroy(pool);
111+
umfMemoryProviderDestroy(provider);
112+
return 0;
113+
114+
memory_pool_destroy:
115+
umfPoolDestroy(pool);
116+
memory_provider_destroy:
117+
umfMemoryProviderDestroy(provider);
118+
return -1;
119+
}

scripts/docs_config/conf.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
author = "Intel"
2323

2424
# The full version, including alpha/beta/rc tags
25-
release = "0.9"
25+
release = "0.1.0"
2626

2727

2828
# -- General configuration ---------------------------------------------------
@@ -37,6 +37,7 @@
3737
# This pattern also affects html_static_path and html_extra_path.
3838
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
3939

40+
primary_domain = "c"
4041

4142
# -- Options for HTML output -------------------------------------------------
4243

@@ -52,3 +53,4 @@
5253
breathe_default_project = project
5354
breathe_show_include = False
5455
breathe_default_members = ("members", "undoc-members")
56+
breathe_domain_by_extension = {"h": "c"}

scripts/docs_config/example-usage.rst

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
.. highlight:: c
2+
:linenothreshold: 10
3+
4+
==============================================================================
5+
Example usage
6+
==============================================================================
7+
8+
This section will walk you through a basic usage
9+
of :ref:`memory provider <glossary-memory-provider>`
10+
and :ref:`pool allocator <glossary-pool-allocator>`. OS Memory Provider
11+
and Scalable Pool will be used for this purpose.
12+
13+
There are also other memory pools available in the UMF. See `README`_ for
14+
more information.
15+
16+
There are some API functions that are supported only when the UMF is built
17+
with the memory tracking enabled (UMF_ENABLE_POOL_TRACKING=ON). These functions
18+
are explicitly described in this tutorial as requiring memory tracking.
19+
20+
You can find the full example code in the `examples/basic/basic.c`_ file
21+
in the UMF repository.
22+
23+
Memory provider usage
24+
------------------------------------------------------------------------------
25+
26+
First, let's create a memory provider object for coarse-grained allocations.
27+
You have to include the `provider_os_memory.h`_ header with
28+
the OS Memory Provider API::
29+
30+
#include "umf/providers/provider_os_memory.h"
31+
32+
Get a pointer to the OS memory provider operations struct and
33+
a copy of default parameters::
34+
35+
umf_memory_provider_ops_t *provider_ops = umfOsMemoryProviderOps();
36+
umf_os_memory_provider_params_t params = umfOsMemoryProviderParamsDefault();
37+
38+
The handle to created memory ``provider`` object is returned as the last argument
39+
of :any:`umfMemoryProviderCreate`::
40+
41+
umf_memory_provider_handle_t provider;
42+
umfMemoryProviderCreate(provider_ops, &params, &provider);
43+
44+
With this handle we can allocate a chunk of memory, call :any:`umfMemoryProviderAlloc`::
45+
46+
size_t alloc_size = 5000;
47+
size_t alignment = 0;
48+
void *ptr_provider = NULL;
49+
umfMemoryProviderAlloc(provider, alloc_size, alignment, &ptr_provider);
50+
51+
To free the memory allocated with a ``provider``, you have to pass the allocated
52+
size as the last parameter of :any:`umfMemoryProviderFree`::
53+
54+
umfMemoryProviderFree(provider, ptr_provider, alloc_size);
55+
56+
Memory pool usage
57+
------------------------------------------------------------------------------
58+
59+
Having created a memory ``provider``, you can create a Scalable Memory ``pool``
60+
to be used for fine-grained allocations. You have to include
61+
the `pool_scalable.h`_ header with the Scalable Memory Pool API::
62+
63+
#include "umf/pools/pool_scalable.h"
64+
65+
Use the default set of operations for the Scalable memory pool
66+
by retrieving an address of the default ops struct::
67+
68+
umf_memory_pool_ops_t *pool_ops = umfScalablePoolOps();
69+
70+
Argument ``pool_params`` is not used by the Scalable Pool, set it to ``NULL``::
71+
72+
void *pool_params = NULL;
73+
74+
Here we don't make use of additional ``flags``.
75+
See the :any:`documentation <umf_pool_create_flags_t>` for available flags::
76+
77+
umf_pool_create_flags_t flags = 0;
78+
79+
The ``pool`` handle is retrieved as the last argument of
80+
the :any:`umfPoolCreate` function::
81+
82+
umf_memory_pool_handle_t pool;
83+
umfPoolCreate(pool_ops, provider, pool_params, flags, &pool);
84+
85+
The ``pool`` has been created, we can allocate some memory now
86+
with ie. :any:`umfPoolCalloc`::
87+
88+
size_t num = 1;
89+
alloc_size = 128;
90+
char *ptr = umfPoolCalloc(pool, num, alloc_size);
91+
92+
With the memory tracking enabled, we can retrieve the pool handle used
93+
for allocating memory::
94+
95+
umf_memory_pool_handle_t check_pool = umfPoolByPtr(ptr);
96+
97+
For any pool, you can retrieve the memory provider's handle
98+
that was used to create the ``pool`` with :any:`umfPoolGetMemoryProvider`::
99+
100+
umf_memory_provider_handle_t check_provider;
101+
umfPoolGetMemoryProvider(pool, &check_provider);
102+
103+
Freeing memory is as easy as can be::
104+
105+
umfFree(ptr);
106+
umfPoolDestroy(pool);
107+
umfMemoryProviderDestroy(provider);
108+
109+
.. note::
110+
To free a pointer using the :any:`umfFree` function, ensure that memory tracking is enabled
111+
by setting the UMF_ENABLE_POOL_TRACKING option in the CMake configuration.
112+
If the memory tracking is disabled, you should call a different function:
113+
:any:`umfPoolFree`.
114+
115+
.. _examples/basic/basic.c: https://github.com/oneapi-src/unified-memory-framework/blob/main/examples/basic/basic.c
116+
.. _README: https://github.com/oneapi-src/unified-memory-framework/blob/main/README.md#memory-pool-managers
117+
.. _provider_os_memory.h: https://github.com/oneapi-src/unified-memory-framework/blob/main/include/umf/providers/provider_os_memory.h
118+
.. _pool_scalable.h: https://github.com/oneapi-src/unified-memory-framework/blob/main/include/umf/pools/pool_scalable.h

0 commit comments

Comments
 (0)