Skip to content

Commit 1b78fed

Browse files
committed
Add scalable (TBB) pool manager with tests
Signed-off-by: Lukasz Dorau <[email protected]>
1 parent 876b91e commit 1b78fed

File tree

11 files changed

+326
-5
lines changed

11 files changed

+326
-5
lines changed

.github/workflows/basic.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ jobs:
2828
- name: Install apt packages
2929
run: |
3030
sudo apt-get update
31-
sudo apt-get install -y clang cmake libnuma-dev libjemalloc-dev
31+
sudo apt-get install -y clang cmake libnuma-dev libjemalloc-dev libtbb-dev
3232
3333
- name: Install g++-7
3434
if: matrix.compiler.cxx == 'g++-7'
@@ -47,6 +47,7 @@ jobs:
4747
-DUMF_DEVELOPER_MODE=ON
4848
-DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON
4949
-DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON
50+
-DUMF_BUILD_LIBUMF_POOL_SCALABLE=ON
5051
5152
- name: Build UMF
5253
run: |

.github/workflows/benchmarks.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ jobs:
3535
-DUMF_DEVELOPER_MODE=OFF
3636
-DUMF_BUILD_LIBUMF_POOL_JEMALLOC=ON
3737
-DUMF_BUILD_LIBUMF_POOL_DISJOINT=ON
38+
-DUMF_BUILD_LIBUMF_POOL_SCALABLE=OFF
3839
-DUMF_ENABLE_POOL_TRACKING=OFF
3940
4041
- name: Build UMF

.github/workflows/codeql.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ jobs:
1818
include:
1919
- os: ubuntu-latest
2020
nproc: $(nproc)
21+
pool_scalable: 'ON'
2122
- os: windows-latest
2223
nproc: $Env:NUMBER_OF_PROCESSORS
24+
pool_scalable: 'OFF'
2325
runs-on: ${{matrix.os}}
2426

2527
steps:
@@ -35,7 +37,7 @@ jobs:
3537
if: matrix.os == 'ubuntu-latest'
3638
run: |
3739
sudo apt-get update
38-
sudo apt-get install -y cmake clang libnuma-dev libjemalloc-dev
40+
sudo apt-get install -y cmake clang libnuma-dev libjemalloc-dev libtbb-dev
3941
4042
- name: Install pip packages
4143
run: python3 -m pip install -r third_party/requirements.txt
@@ -48,6 +50,7 @@ jobs:
4850
-DUMF_FORMAT_CODE_STYLE=ON
4951
-DUMF_DEVELOPER_MODE=ON
5052
-DUMF_ENABLE_POOL_TRACKING=ON
53+
-DUMF_BUILD_LIBUMF_POOL_SCALABLE=${{matrix.pool_scalable}}
5154
5255
- name: Build
5356
run: >

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ include(helpers)
1919
option(UMF_BUILD_SHARED_LIBRARY "Build UMF as shared library" OFF)
2020
option(UMF_BUILD_LIBUMF_POOL_DISJOINT "Build the libumf_pool_disjoint static library" OFF)
2121
option(UMF_BUILD_LIBUMF_POOL_JEMALLOC "Build the libumf_pool_jemalloc static library" OFF)
22+
option(UMF_BUILD_LIBUMF_POOL_SCALABLE "Build the libumf_pool_scalable static library" OFF)
2223
option(UMF_BUILD_TESTS "Build UMF tests" ON)
2324
option(UMF_BUILD_BENCHMARKS "Build UMF benchmarks" OFF)
2425
option(UMF_ENABLE_POOL_TRACKING "Build UMF with pool tracking" ON)

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,17 @@ The `UMF_BUILD_LIBUMF_POOL_JEMALLOC` option has to be turned `ON` to build this
3939
2) Required packages:
4040
- libjemalloc-dev
4141

42+
### libumf_pool_scalable (Linux-only)
43+
44+
libumf_pool_scalable is a [oneTBB](https://github.com/oneapi-src/oneTBB)-based memory pool manager built as a separate static library.
45+
The `UMF_BUILD_LIBUMF_POOL_SCALABLE` option has to be turned `ON` to build this library.
46+
47+
#### Requirements
48+
49+
1) The `UMF_BUILD_LIBUMF_POOL_SCALABLE` option turned `ON`
50+
2) Required packages:
51+
- libtbb-dev (libraries: libtbbmalloc.so.2)
52+
4253
## Building
4354

4455
### Requirements
@@ -102,6 +113,7 @@ List of options provided by CMake:
102113
| UMF_BUILD_SHARED_LIBRARY | Build UMF as shared library | ON/OFF | OFF |
103114
| UMF_BUILD_LIBUMF_POOL_DISJOINT | Build the libumf_pool_disjoint static library | ON/OFF | OFF |
104115
| UMF_BUILD_LIBUMF_POOL_JEMALLOC | Build the libumf_pool_jemalloc static library | ON/OFF | OFF |
116+
| UMF_BUILD_LIBUMF_POOL_SCALABLE | Build the libumf_pool_scalable static library | ON/OFF | OFF |
105117
| UMF_BUILD_TESTS | Build UMF tests | ON/OFF | ON |
106118
| UMF_BUILD_BENCHMARKS | Build UMF benchmarks | ON/OFF | OFF |
107119
| UMF_ENABLE_POOL_TRACKING | Build UMF with pool tracking | ON/OFF | ON |

benchmark/ubench.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ static void w_umfPoolFree(void *provider, void *ptr, size_t size) {
169169
exit(-1);
170170
}
171171
}
172-
#endif /* (defined UMF_BUILD_LIBUMF_POOL_TBB) || (defined UMF_BUILD_LIBUMF_POOL_JEMALLOC) */
172+
#endif /* (defined UMF_BUILD_LIBUMF_POOL_DISJOINT) || (defined UMF_BUILD_LIBUMF_POOL_JEMALLOC) */
173173

174174
#ifdef UMF_BUILD_LIBUMF_POOL_DISJOINT
175175
////////////////// DISJOINT POOL WITH OS MEMORY PROVIDER

include/umf/pools/pool_scalable.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
*
3+
* Copyright (C) 2023 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+
#ifndef UMF_SCALABLE_MEMORY_POOL_H
11+
#define UMF_SCALABLE_MEMORY_POOL_H 1
12+
13+
#ifdef __cplusplus
14+
extern "C" {
15+
#endif
16+
17+
#include <umf/memory_pool.h>
18+
#include <umf/memory_provider.h>
19+
20+
extern umf_memory_pool_ops_t UMF_SCALABLE_POOL_OPS;
21+
22+
#ifdef __cplusplus
23+
}
24+
#endif
25+
26+
#endif /* UMF_SCALABLE_MEMORY_POOL_H */

src/pool/CMakeLists.txt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,19 @@ if(UMF_BUILD_LIBUMF_POOL_JEMALLOC)
4141
message(FATAL_ERROR "libumf_pool_jemalloc is supported on Linux only")
4242
endif()
4343
endif()
44+
45+
# libumf_pool_scalable
46+
if(UMF_BUILD_LIBUMF_POOL_SCALABLE)
47+
if(LINUX)
48+
add_umf_library(NAME scalable_pool
49+
TYPE STATIC
50+
SRCS pool_scalable.c
51+
LIBS dl)
52+
add_library(${PROJECT_NAME}::scalable_pool ALIAS scalable_pool)
53+
install(TARGETS scalable_pool
54+
EXPORT ${PROJECT_NAME}-targets
55+
)
56+
else()
57+
message(FATAL_ERROR "libumf_pool_scalable is supported on Linux only")
58+
endif()
59+
endif()

src/pool/pool_scalable.c

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
/*
2+
*
3+
* Copyright (C) 2023 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 <assert.h>
11+
#include <dlfcn.h>
12+
#include <pthread.h>
13+
#include <stdbool.h>
14+
#include <stdint.h>
15+
#include <stdio.h>
16+
#include <stdlib.h>
17+
#include <string.h>
18+
19+
#include "umf/pools/pool_scalable.h"
20+
#include <umf/memory_pool.h>
21+
#include <umf/memory_pool_ops.h>
22+
#include <umf/memory_provider.h>
23+
24+
#include "common.h"
25+
26+
typedef void *(*raw_alloc_tbb_type)(intptr_t, size_t *);
27+
typedef void (*raw_free_tbb_type)(intptr_t, void *, size_t);
28+
29+
static __TLS umf_result_t TLS_last_allocation_error;
30+
31+
struct mem_pool_policy_s {
32+
raw_alloc_tbb_type pAlloc;
33+
raw_free_tbb_type pFree;
34+
size_t granularity;
35+
int version;
36+
unsigned fixed_pool : 1, keep_all_memory : 1, reserved : 30;
37+
};
38+
39+
struct tbb_callbacks {
40+
void *(*pool_malloc)(void *, size_t);
41+
void *(*pool_realloc)(void *, void *, size_t);
42+
void *(*pool_aligned_malloc)(void *, size_t, size_t);
43+
bool (*pool_free)(void *, void *);
44+
int (*pool_create_v1)(intptr_t, const struct mem_pool_policy_s *, void **);
45+
bool (*pool_destroy)(void *);
46+
void *(*pool_identify)(void *object);
47+
size_t (*pool_msize)(void *, void *);
48+
};
49+
50+
struct tbb_memory_pool {
51+
umf_memory_provider_handle_t mem_provider;
52+
void *tbb_pool;
53+
};
54+
55+
static struct tbb_callbacks g_tbb_ops;
56+
static pthread_once_t tbb_is_initialized = PTHREAD_ONCE_INIT;
57+
58+
static void load_tbb_symbols(void) {
59+
const char so_name[] = "libtbbmalloc.so.2";
60+
void *tbb_handle = dlopen(so_name, RTLD_LAZY);
61+
if (!tbb_handle) {
62+
fprintf(stderr, "%s not found.\n", so_name);
63+
abort();
64+
}
65+
66+
struct tbb_callbacks tbb_ops;
67+
68+
*(void **)&tbb_ops.pool_malloc =
69+
dlsym(tbb_handle, "_ZN3rml11pool_mallocEPNS_10MemoryPoolEm");
70+
*(void **)&tbb_ops.pool_realloc =
71+
dlsym(tbb_handle, "_ZN3rml12pool_reallocEPNS_10MemoryPoolEPvm");
72+
*(void **)&tbb_ops.pool_aligned_malloc =
73+
dlsym(tbb_handle, "_ZN3rml19pool_aligned_mallocEPNS_10MemoryPoolEmm");
74+
*(void **)&tbb_ops.pool_free =
75+
dlsym(tbb_handle, "_ZN3rml9pool_freeEPNS_10MemoryPoolEPv");
76+
*(void **)&tbb_ops.pool_create_v1 = dlsym(
77+
tbb_handle,
78+
"_ZN3rml14pool_create_v1ElPKNS_13MemPoolPolicyEPPNS_10MemoryPoolE");
79+
*(void **)&tbb_ops.pool_destroy =
80+
dlsym(tbb_handle, "_ZN3rml12pool_destroyEPNS_10MemoryPoolE");
81+
*(void **)&tbb_ops.pool_identify =
82+
dlsym(tbb_handle, "_ZN3rml13pool_identifyEPv");
83+
*(void **)&tbb_ops.pool_msize =
84+
dlsym(tbb_handle, "_ZN3rml10pool_msizeEPNS_10MemoryPoolEPv");
85+
86+
if (!tbb_ops.pool_malloc || !tbb_ops.pool_realloc ||
87+
!tbb_ops.pool_aligned_malloc || !tbb_ops.pool_free ||
88+
!tbb_ops.pool_create_v1 || !tbb_ops.pool_destroy ||
89+
!tbb_ops.pool_identify) {
90+
fprintf(stderr, "Could not find symbols in %s.\n", so_name);
91+
dlclose(tbb_handle);
92+
abort();
93+
}
94+
95+
g_tbb_ops = tbb_ops;
96+
}
97+
98+
static void *tbb_raw_alloc_wrapper(intptr_t pool_id, size_t *raw_bytes) {
99+
void *resPtr;
100+
struct tbb_memory_pool *pool = (struct tbb_memory_pool *)pool_id;
101+
umf_result_t ret =
102+
umfMemoryProviderAlloc(pool->mem_provider, *raw_bytes, 0, &resPtr);
103+
if (ret != UMF_RESULT_SUCCESS) {
104+
TLS_last_allocation_error = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
105+
return NULL;
106+
}
107+
108+
return resPtr;
109+
}
110+
111+
static void tbb_raw_free_wrapper(intptr_t pool_id, void *ptr, size_t bytes) {
112+
struct tbb_memory_pool *pool = (struct tbb_memory_pool *)pool_id;
113+
umf_result_t ret = umfMemoryProviderFree(pool->mem_provider, ptr, bytes);
114+
if (ret != UMF_RESULT_SUCCESS) {
115+
fprintf(
116+
stderr,
117+
"Memory provider failed to free memory, addr = %p, size = %lu\n",
118+
ptr, bytes);
119+
}
120+
}
121+
122+
static umf_result_t tbb_pool_initialize(umf_memory_provider_handle_t provider,
123+
void *params, void **pool) {
124+
(void)params; // unused
125+
126+
const size_t GRANULARITY = 2 * 1024 * 1024;
127+
struct mem_pool_policy_s policy = {.pAlloc = tbb_raw_alloc_wrapper,
128+
.pFree = tbb_raw_free_wrapper,
129+
.granularity = GRANULARITY,
130+
.version = 1,
131+
.fixed_pool = false,
132+
.keep_all_memory = false,
133+
.reserved = 0};
134+
135+
pthread_once(&tbb_is_initialized, load_tbb_symbols);
136+
137+
struct tbb_memory_pool *pool_data = malloc(sizeof(struct tbb_memory_pool));
138+
if (!pool_data) {
139+
fprintf(stderr, "cannot allocate memory for metadata\n");
140+
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
141+
}
142+
143+
pool_data->mem_provider = provider;
144+
g_tbb_ops.pool_create_v1((intptr_t)pool_data, &policy,
145+
&(pool_data->tbb_pool));
146+
*pool = (void *)pool_data;
147+
148+
return UMF_RESULT_SUCCESS;
149+
}
150+
151+
static void tbb_pool_finalize(void *pool) {
152+
pthread_once(&tbb_is_initialized, load_tbb_symbols);
153+
struct tbb_memory_pool *pool_data = (struct tbb_memory_pool *)pool;
154+
g_tbb_ops.pool_destroy(pool_data->tbb_pool);
155+
}
156+
157+
static void *tbb_malloc(void *pool, size_t size) {
158+
struct tbb_memory_pool *pool_data = (struct tbb_memory_pool *)pool;
159+
TLS_last_allocation_error = UMF_RESULT_SUCCESS;
160+
void *ptr = g_tbb_ops.pool_malloc(pool_data->tbb_pool, size);
161+
if (ptr == NULL) {
162+
if (TLS_last_allocation_error == UMF_RESULT_SUCCESS) {
163+
TLS_last_allocation_error = UMF_RESULT_ERROR_UNKNOWN;
164+
}
165+
return NULL;
166+
}
167+
return ptr;
168+
}
169+
170+
static void *tbb_calloc(void *pool, size_t num, size_t size) {
171+
assert(pool);
172+
size_t csize = num * size;
173+
void *ptr = tbb_malloc(pool, csize);
174+
if (ptr == NULL) {
175+
// TLS_last_allocation_error is set by tbb_malloc()
176+
return NULL;
177+
}
178+
179+
memset(ptr, 0, csize);
180+
return ptr;
181+
}
182+
183+
static void *tbb_realloc(void *pool, void *ptr, size_t size) {
184+
struct tbb_memory_pool *pool_data = (struct tbb_memory_pool *)pool;
185+
TLS_last_allocation_error = UMF_RESULT_SUCCESS;
186+
void *new_ptr = g_tbb_ops.pool_realloc(pool_data->tbb_pool, ptr, size);
187+
if (new_ptr == NULL) {
188+
if (TLS_last_allocation_error == UMF_RESULT_SUCCESS) {
189+
TLS_last_allocation_error = UMF_RESULT_ERROR_UNKNOWN;
190+
}
191+
return NULL;
192+
}
193+
return new_ptr;
194+
}
195+
196+
static void *tbb_aligned_malloc(void *pool, size_t size, size_t alignment) {
197+
struct tbb_memory_pool *pool_data = (struct tbb_memory_pool *)pool;
198+
TLS_last_allocation_error = UMF_RESULT_SUCCESS;
199+
void *ptr =
200+
g_tbb_ops.pool_aligned_malloc(pool_data->tbb_pool, size, alignment);
201+
if (ptr == NULL) {
202+
if (TLS_last_allocation_error == UMF_RESULT_SUCCESS) {
203+
TLS_last_allocation_error = UMF_RESULT_ERROR_UNKNOWN;
204+
}
205+
return NULL;
206+
}
207+
return ptr;
208+
}
209+
210+
static umf_result_t tbb_free(void *pool, void *ptr) {
211+
struct tbb_memory_pool *pool_data = (struct tbb_memory_pool *)pool;
212+
g_tbb_ops.pool_free(pool_data->tbb_pool, ptr);
213+
return UMF_RESULT_SUCCESS;
214+
}
215+
216+
static size_t tbb_malloc_usable_size(void *pool, void *ptr) {
217+
struct tbb_memory_pool *pool_data = (struct tbb_memory_pool *)pool;
218+
return g_tbb_ops.pool_msize(pool_data->tbb_pool, ptr);
219+
}
220+
221+
static umf_result_t tbb_get_last_allocation_error(void *pool) {
222+
(void)pool; // not used
223+
return TLS_last_allocation_error;
224+
}
225+
226+
umf_memory_pool_ops_t UMF_SCALABLE_POOL_OPS = {
227+
.version = UMF_VERSION_CURRENT,
228+
.initialize = tbb_pool_initialize,
229+
.finalize = tbb_pool_finalize,
230+
.malloc = tbb_malloc,
231+
.calloc = tbb_calloc,
232+
.realloc = tbb_realloc,
233+
.aligned_malloc = tbb_aligned_malloc,
234+
.malloc_usable_size = tbb_malloc_usable_size,
235+
.free = tbb_free,
236+
.get_last_allocation_error = tbb_get_last_allocation_error};

test/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ function(add_umf_test)
3737
if(UMF_BUILD_LIBUMF_POOL_JEMALLOC)
3838
set(TEST_LIBS ${TEST_LIBS} jemalloc_pool)
3939
endif()
40+
if(UMF_BUILD_LIBUMF_POOL_SCALABLE)
41+
set(TEST_LIBS ${TEST_LIBS} scalable_pool)
42+
endif()
4043
add_umf_executable(NAME ${TEST_TARGET_NAME} SRCS ${ARG_SRCS} LIBS ${TEST_LIBS})
4144

4245
target_include_directories(${TEST_TARGET_NAME} PRIVATE
@@ -55,6 +58,9 @@ function(add_umf_test)
5558
if (UMF_BUILD_LIBUMF_POOL_JEMALLOC)
5659
target_compile_definitions(${TEST_TARGET_NAME} PRIVATE UMF_BUILD_LIBUMF_POOL_JEMALLOC=1)
5760
endif()
61+
if (UMF_BUILD_LIBUMF_POOL_SCALABLE)
62+
target_compile_definitions(${TEST_TARGET_NAME} PRIVATE UMF_BUILD_LIBUMF_POOL_SCALABLE=1)
63+
endif()
5864
endfunction()
5965

6066
add_subdirectory(common)

0 commit comments

Comments
 (0)