Skip to content

Commit 647b388

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

File tree

11 files changed

+337
-5
lines changed

11 files changed

+337
-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: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
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+
static bool Load_tbb_symbols_failed;
58+
59+
static void load_tbb_symbols(void) {
60+
const char so_name[] = "libtbbmalloc.so.2";
61+
void *tbb_handle = dlopen(so_name, RTLD_LAZY);
62+
if (!tbb_handle) {
63+
fprintf(stderr, "%s not found.\n", so_name);
64+
Load_tbb_symbols_failed = true;
65+
return;
66+
}
67+
68+
struct tbb_callbacks tbb_ops;
69+
70+
*(void **)&tbb_ops.pool_malloc =
71+
dlsym(tbb_handle, "_ZN3rml11pool_mallocEPNS_10MemoryPoolEm");
72+
*(void **)&tbb_ops.pool_realloc =
73+
dlsym(tbb_handle, "_ZN3rml12pool_reallocEPNS_10MemoryPoolEPvm");
74+
*(void **)&tbb_ops.pool_aligned_malloc =
75+
dlsym(tbb_handle, "_ZN3rml19pool_aligned_mallocEPNS_10MemoryPoolEmm");
76+
*(void **)&tbb_ops.pool_free =
77+
dlsym(tbb_handle, "_ZN3rml9pool_freeEPNS_10MemoryPoolEPv");
78+
*(void **)&tbb_ops.pool_create_v1 = dlsym(
79+
tbb_handle,
80+
"_ZN3rml14pool_create_v1ElPKNS_13MemPoolPolicyEPPNS_10MemoryPoolE");
81+
*(void **)&tbb_ops.pool_destroy =
82+
dlsym(tbb_handle, "_ZN3rml12pool_destroyEPNS_10MemoryPoolE");
83+
*(void **)&tbb_ops.pool_identify =
84+
dlsym(tbb_handle, "_ZN3rml13pool_identifyEPv");
85+
*(void **)&tbb_ops.pool_msize =
86+
dlsym(tbb_handle, "_ZN3rml10pool_msizeEPNS_10MemoryPoolEPv");
87+
88+
if (!tbb_ops.pool_malloc || !tbb_ops.pool_realloc ||
89+
!tbb_ops.pool_aligned_malloc || !tbb_ops.pool_free ||
90+
!tbb_ops.pool_create_v1 || !tbb_ops.pool_destroy ||
91+
!tbb_ops.pool_identify) {
92+
fprintf(stderr, "Could not find symbols in %s.\n", so_name);
93+
dlclose(tbb_handle);
94+
Load_tbb_symbols_failed = true;
95+
return;
96+
}
97+
98+
g_tbb_ops = tbb_ops;
99+
}
100+
101+
static void *tbb_raw_alloc_wrapper(intptr_t pool_id, size_t *raw_bytes) {
102+
void *resPtr;
103+
struct tbb_memory_pool *pool = (struct tbb_memory_pool *)pool_id;
104+
umf_result_t ret =
105+
umfMemoryProviderAlloc(pool->mem_provider, *raw_bytes, 0, &resPtr);
106+
if (ret != UMF_RESULT_SUCCESS) {
107+
TLS_last_allocation_error = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
108+
return NULL;
109+
}
110+
111+
return resPtr;
112+
}
113+
114+
static void tbb_raw_free_wrapper(intptr_t pool_id, void *ptr, size_t bytes) {
115+
struct tbb_memory_pool *pool = (struct tbb_memory_pool *)pool_id;
116+
umf_result_t ret = umfMemoryProviderFree(pool->mem_provider, ptr, bytes);
117+
if (ret != UMF_RESULT_SUCCESS) {
118+
fprintf(
119+
stderr,
120+
"Memory provider failed to free memory, addr = %p, size = %lu\n",
121+
ptr, bytes);
122+
}
123+
}
124+
125+
static umf_result_t tbb_pool_initialize(umf_memory_provider_handle_t provider,
126+
void *params, void **pool) {
127+
(void)params; // unused
128+
129+
const size_t GRANULARITY = 2 * 1024 * 1024;
130+
struct mem_pool_policy_s policy = {.pAlloc = tbb_raw_alloc_wrapper,
131+
.pFree = tbb_raw_free_wrapper,
132+
.granularity = GRANULARITY,
133+
.version = 1,
134+
.fixed_pool = false,
135+
.keep_all_memory = false,
136+
.reserved = 0};
137+
138+
pthread_once(&tbb_is_initialized, load_tbb_symbols);
139+
if (Load_tbb_symbols_failed) {
140+
fprintf(stderr, "loading TBB symbols failed\n");
141+
return UMF_RESULT_ERROR_UNKNOWN;
142+
}
143+
144+
struct tbb_memory_pool *pool_data = malloc(sizeof(struct tbb_memory_pool));
145+
if (!pool_data) {
146+
fprintf(stderr, "cannot allocate memory for metadata\n");
147+
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
148+
}
149+
150+
pool_data->mem_provider = provider;
151+
g_tbb_ops.pool_create_v1((intptr_t)pool_data, &policy,
152+
&(pool_data->tbb_pool));
153+
*pool = (void *)pool_data;
154+
155+
return UMF_RESULT_SUCCESS;
156+
}
157+
158+
static void tbb_pool_finalize(void *pool) {
159+
pthread_once(&tbb_is_initialized, load_tbb_symbols);
160+
struct tbb_memory_pool *pool_data = (struct tbb_memory_pool *)pool;
161+
g_tbb_ops.pool_destroy(pool_data->tbb_pool);
162+
}
163+
164+
static void *tbb_malloc(void *pool, size_t size) {
165+
struct tbb_memory_pool *pool_data = (struct tbb_memory_pool *)pool;
166+
TLS_last_allocation_error = UMF_RESULT_SUCCESS;
167+
void *ptr = g_tbb_ops.pool_malloc(pool_data->tbb_pool, size);
168+
if (ptr == NULL) {
169+
if (TLS_last_allocation_error == UMF_RESULT_SUCCESS) {
170+
TLS_last_allocation_error = UMF_RESULT_ERROR_UNKNOWN;
171+
}
172+
return NULL;
173+
}
174+
return ptr;
175+
}
176+
177+
static void *tbb_calloc(void *pool, size_t num, size_t size) {
178+
assert(pool);
179+
size_t csize = num * size;
180+
void *ptr = tbb_malloc(pool, csize);
181+
if (ptr == NULL) {
182+
// TLS_last_allocation_error is set by tbb_malloc()
183+
return NULL;
184+
}
185+
186+
memset(ptr, 0, csize);
187+
return ptr;
188+
}
189+
190+
static void *tbb_realloc(void *pool, void *ptr, size_t size) {
191+
struct tbb_memory_pool *pool_data = (struct tbb_memory_pool *)pool;
192+
TLS_last_allocation_error = UMF_RESULT_SUCCESS;
193+
void *new_ptr = g_tbb_ops.pool_realloc(pool_data->tbb_pool, ptr, size);
194+
if (new_ptr == NULL) {
195+
if (TLS_last_allocation_error == UMF_RESULT_SUCCESS) {
196+
TLS_last_allocation_error = UMF_RESULT_ERROR_UNKNOWN;
197+
}
198+
return NULL;
199+
}
200+
return new_ptr;
201+
}
202+
203+
static void *tbb_aligned_malloc(void *pool, size_t size, size_t alignment) {
204+
struct tbb_memory_pool *pool_data = (struct tbb_memory_pool *)pool;
205+
TLS_last_allocation_error = UMF_RESULT_SUCCESS;
206+
void *ptr =
207+
g_tbb_ops.pool_aligned_malloc(pool_data->tbb_pool, size, alignment);
208+
if (ptr == NULL) {
209+
if (TLS_last_allocation_error == UMF_RESULT_SUCCESS) {
210+
TLS_last_allocation_error = UMF_RESULT_ERROR_UNKNOWN;
211+
}
212+
return NULL;
213+
}
214+
return ptr;
215+
}
216+
217+
static umf_result_t tbb_free(void *pool, void *ptr) {
218+
if (ptr == NULL) {
219+
return UMF_RESULT_SUCCESS;
220+
}
221+
struct tbb_memory_pool *pool_data = (struct tbb_memory_pool *)pool;
222+
return g_tbb_ops.pool_free(pool_data->tbb_pool, ptr)
223+
? UMF_RESULT_SUCCESS
224+
: UMF_RESULT_ERROR_UNKNOWN;
225+
}
226+
227+
static size_t tbb_malloc_usable_size(void *pool, void *ptr) {
228+
struct tbb_memory_pool *pool_data = (struct tbb_memory_pool *)pool;
229+
return g_tbb_ops.pool_msize(pool_data->tbb_pool, ptr);
230+
}
231+
232+
static umf_result_t tbb_get_last_allocation_error(void *pool) {
233+
(void)pool; // not used
234+
return TLS_last_allocation_error;
235+
}
236+
237+
umf_memory_pool_ops_t UMF_SCALABLE_POOL_OPS = {
238+
.version = UMF_VERSION_CURRENT,
239+
.initialize = tbb_pool_initialize,
240+
.finalize = tbb_pool_finalize,
241+
.malloc = tbb_malloc,
242+
.calloc = tbb_calloc,
243+
.realloc = tbb_realloc,
244+
.aligned_malloc = tbb_aligned_malloc,
245+
.malloc_usable_size = tbb_malloc_usable_size,
246+
.free = tbb_free,
247+
.get_last_allocation_error = tbb_get_last_allocation_error};

0 commit comments

Comments
 (0)