Skip to content

Commit 4cdba02

Browse files
committed
Add size threshold to proxy lib to call system allocator
Add a size threshold to proxy lib to call system allocator when the size is less than the given threshold. Signed-off-by: Lukasz Dorau <lukasz.dorau@intel.com>
1 parent 93b8be2 commit 4cdba02

File tree

2 files changed

+144
-16
lines changed

2 files changed

+144
-16
lines changed

.github/workflows/reusable_proxy_lib.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,16 @@ jobs:
7777
working-directory: ${{env.BUILD_DIR}}
7878
run: UMF_PROXY="page.disposition=shared-shm" LD_PRELOAD=./lib/libumf_proxy.so /usr/bin/date
7979

80+
# TODO enable the provider_file_memory_ipc test when the IPC tests with the proxy library are fixed
81+
# see the issue: https://github.com/oneapi-src/unified-memory-framework/issues/864
82+
- name: Run "ctest --output-on-failure" with proxy library and size.threshold=128
83+
working-directory: ${{env.BUILD_DIR}}
84+
run: >
85+
UMF_PROXY="size.threshold=128"
86+
UMF_LOG="level:debug;flush:debug;output:stderr;pid:yes"
87+
LD_PRELOAD=./lib/libumf_proxy.so
88+
ctest --output-on-failure -E provider_file_memory_ipc
89+
8090
- name: Check coverage
8191
if: ${{ matrix.build_type == 'Debug' }}
8292
working-directory: ${{env.BUILD_DIR}}

src/proxy_lib/proxy_lib.c

Lines changed: 134 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@
2727
* - _aligned_offset_recalloc()
2828
*/
2929

30+
#ifndef _WIN32
31+
#define _GNU_SOURCE
32+
#include <dlfcn.h>
33+
#undef _GNU_SOURCE
34+
#endif /* _WIN32 */
35+
3036
#if (defined PROXY_LIB_USES_JEMALLOC_POOL)
3137
#include <umf/pools/pool_jemalloc.h>
3238
#define umfPoolManagerOps umfJemallocPoolOps
@@ -103,38 +109,112 @@ static umf_memory_pool_handle_t Proxy_pool = NULL;
103109
// it protects us from recursion in umfPool*()
104110
static __TLS int was_called_from_umfPool = 0;
105111

112+
typedef void *(*system_aligned_alloc_t)(size_t alignment, size_t size);
113+
typedef void *(*system_calloc_t)(size_t nmemb, size_t size);
114+
typedef void (*system_free_t)(void *ptr);
115+
typedef void *(*system_malloc_t)(size_t size);
116+
typedef size_t (*system_malloc_usable_size_t)(void *ptr);
117+
typedef void *(*system_realloc_t)(void *ptr, size_t size);
118+
119+
static system_aligned_alloc_t system_aligned_alloc;
120+
static system_calloc_t system_calloc;
121+
static system_free_t system_free;
122+
static system_malloc_t system_malloc;
123+
static system_malloc_usable_size_t system_malloc_usable_size;
124+
static system_realloc_t system_realloc;
125+
static size_t threshold_value = 0;
126+
106127
/*****************************************************************************/
107128
/*** The constructor and destructor of the proxy library *********************/
108129
/*****************************************************************************/
109130

131+
#ifndef _WIN32
132+
static size_t get_size_threshold(void) {
133+
char *str_threshold = utils_env_var_get_str("UMF_PROXY", "size.threshold=");
134+
if (!str_threshold) {
135+
return 0;
136+
}
137+
138+
// move to the beginning of the number
139+
str_threshold += strlen("size.threshold=");
140+
// find ';' at the end
141+
char *end = strstr(str_threshold, ";");
142+
if (end) {
143+
// replace ';' with '\0' to mark end of the string
144+
*end = '\0';
145+
}
146+
147+
size_t int_threshold = (size_t)atoi(str_threshold);
148+
LOG_DEBUG("threshold_value = (char *) %s, (int) %zu", str_threshold,
149+
int_threshold);
150+
151+
return int_threshold;
152+
}
153+
154+
static int dlsym_system_allocator(void) {
155+
*((void **)(&system_aligned_alloc)) = dlsym(RTLD_NEXT, "aligned_alloc");
156+
*((void **)(&system_calloc)) = dlsym(RTLD_NEXT, "calloc");
157+
*((void **)(&system_free)) = dlsym(RTLD_NEXT, "free");
158+
*((void **)(&system_malloc)) = dlsym(RTLD_NEXT, "malloc");
159+
*((void **)(&system_malloc_usable_size)) =
160+
dlsym(RTLD_NEXT, "malloc_usable_size");
161+
*((void **)(&system_realloc)) = dlsym(RTLD_NEXT, "realloc");
162+
163+
if (system_aligned_alloc && system_calloc && system_free && system_malloc &&
164+
system_malloc_usable_size && system_realloc) {
165+
return 0;
166+
}
167+
168+
*((void **)(&system_aligned_alloc)) = NULL;
169+
*((void **)(&system_calloc)) = NULL;
170+
*((void **)(&system_free)) = NULL;
171+
*((void **)(&system_malloc)) = NULL;
172+
*((void **)(&system_malloc_usable_size)) = NULL;
173+
*((void **)(&system_realloc)) = NULL;
174+
175+
return -1;
176+
}
177+
#endif /* _WIN32 */
178+
110179
void proxy_lib_create_common(void) {
111180
utils_log_init();
112181
umf_os_memory_provider_params_t os_params =
113182
umfOsMemoryProviderParamsDefault();
114183
umf_result_t umf_result;
115184

116185
#ifndef _WIN32
117-
char shm_name[NAME_MAX];
186+
size_t _threshold = get_size_threshold();
187+
if (_threshold > 0) {
188+
if (dlsym_system_allocator()) {
189+
LOG_ERR("initialization of the system allocator failed!");
190+
exit(-1);
191+
}
192+
193+
threshold_value = _threshold;
194+
LOG_INFO("system allocator initialized, size threshold value = %zu",
195+
threshold_value);
196+
}
118197

119198
if (utils_env_var_has_str("UMF_PROXY", "page.disposition=shared-fd")) {
120-
LOG_DEBUG("proxy_lib: using the MAP_SHARED visibility mode with the "
121-
"file descriptor duplication");
199+
LOG_INFO("proxy_lib: using the MAP_SHARED visibility mode with the "
200+
"file descriptor duplication");
122201
os_params.visibility = UMF_MEM_MAP_SHARED;
123202
os_params.shm_name = NULL;
124203

125204
} else if (utils_env_var_has_str("UMF_PROXY",
126205
"page.disposition=shared-shm")) {
127206
os_params.visibility = UMF_MEM_MAP_SHARED;
128207

208+
char shm_name[NAME_MAX];
129209
memset(shm_name, 0, NAME_MAX);
130210
sprintf(shm_name, "umf_proxy_lib_shm_pid_%i", utils_getpid());
131211
os_params.shm_name = shm_name;
132212

133-
LOG_DEBUG("proxy_lib: using the MAP_SHARED visibility mode with the "
134-
"named shared memory: %s",
135-
os_params.shm_name);
213+
LOG_INFO("proxy_lib: using the MAP_SHARED visibility mode with the "
214+
"named shared memory: %s",
215+
os_params.shm_name);
136216
}
137-
#endif
217+
#endif /* _WIN32 */
138218

139219
umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), &os_params,
140220
&OS_memory_provider);
@@ -149,16 +229,18 @@ void proxy_lib_create_common(void) {
149229
LOG_ERR("creating UMF pool manager failed");
150230
exit(-1);
151231
}
232+
152233
// The UMF pool has just been created (Proxy_pool != NULL). Stop using
153234
// the linear allocator and start using the UMF pool allocator from now on.
235+
LOG_DEBUG("proxy library initialized");
154236
}
155237

156238
void proxy_lib_destroy_common(void) {
157239
if (utils_is_running_in_proxy_lib()) {
158240
// We cannot destroy 'Base_alloc_leak' nor 'Proxy_pool' nor 'OS_memory_provider',
159241
// because it could lead to use-after-free in the program's unloader
160242
// (for example _dl_fini() on Linux).
161-
return;
243+
goto fini_proxy_lib_destroy_common;
162244
}
163245

164246
umf_memory_pool_handle_t pool = Proxy_pool;
@@ -168,6 +250,10 @@ void proxy_lib_destroy_common(void) {
168250
umf_memory_provider_handle_t provider = OS_memory_provider;
169251
OS_memory_provider = NULL;
170252
umfMemoryProviderDestroy(provider);
253+
LOG_DEBUG("proxy library destroyed");
254+
255+
fini_proxy_lib_destroy_common:
256+
LOG_DEBUG("proxy library finalized");
171257
}
172258

173259
/*****************************************************************************/
@@ -246,6 +332,10 @@ static inline size_t ba_leak_pool_contains_pointer(void *ptr) {
246332
/*****************************************************************************/
247333

248334
void *malloc(size_t size) {
335+
if (size < threshold_value) {
336+
return system_malloc(size);
337+
}
338+
249339
if (!was_called_from_umfPool && Proxy_pool) {
250340
was_called_from_umfPool = 1;
251341
void *ptr = umfPoolMalloc(Proxy_pool, size);
@@ -257,6 +347,10 @@ void *malloc(size_t size) {
257347
}
258348

259349
void *calloc(size_t nmemb, size_t size) {
350+
if ((nmemb * size) < threshold_value) {
351+
return system_calloc(nmemb, size);
352+
}
353+
260354
if (!was_called_from_umfPool && Proxy_pool) {
261355
was_called_from_umfPool = 1;
262356
void *ptr = umfPoolCalloc(Proxy_pool, nmemb, size);
@@ -276,15 +370,20 @@ void free(void *ptr) {
276370
return;
277371
}
278372

279-
if (Proxy_pool) {
373+
if (Proxy_pool && (umfPoolByPtr(ptr) == Proxy_pool)) {
280374
if (umfPoolFree(Proxy_pool, ptr) != UMF_RESULT_SUCCESS) {
281375
LOG_ERR("umfPoolFree() failed");
282-
assert(0);
283376
}
284377
return;
285378
}
286379

287-
assert(0);
380+
if (threshold_value) {
381+
system_free(ptr);
382+
return;
383+
}
384+
385+
LOG_ERR("free() failed: %p", ptr);
386+
288387
return;
289388
}
290389

@@ -303,18 +402,27 @@ void *realloc(void *ptr, size_t size) {
303402
return ba_leak_realloc(ptr, size, leak_pool_contains_pointer);
304403
}
305404

306-
if (Proxy_pool) {
405+
if (Proxy_pool && (umfPoolByPtr(ptr) == Proxy_pool)) {
307406
was_called_from_umfPool = 1;
308407
void *new_ptr = umfPoolRealloc(Proxy_pool, ptr, size);
309408
was_called_from_umfPool = 0;
310409
return new_ptr;
311410
}
312411

313-
assert(0);
412+
if (threshold_value) {
413+
return system_realloc(ptr, size);
414+
}
415+
416+
LOG_ERR("realloc() failed: %p", ptr);
417+
314418
return NULL;
315419
}
316420

317421
void *aligned_alloc(size_t alignment, size_t size) {
422+
if (size < threshold_value) {
423+
return system_aligned_alloc(alignment, size);
424+
}
425+
318426
if (!was_called_from_umfPool && Proxy_pool) {
319427
was_called_from_umfPool = 1;
320428
void *ptr = umfPoolAlignedMalloc(Proxy_pool, size, alignment);
@@ -330,19 +438,29 @@ size_t _msize(void *ptr) {
330438
#else
331439
size_t malloc_usable_size(void *ptr) {
332440
#endif
333-
334-
// a check to verify we are running the proxy library
441+
// a check to verify if we are running the proxy library
335442
if (ptr == (void *)0x01) {
336443
return 0xDEADBEEF;
337444
}
338445

339-
if (!was_called_from_umfPool && Proxy_pool) {
446+
if (ba_leak_pool_contains_pointer(ptr)) {
447+
return 0; // unsupported in case of the ba_leak allocator
448+
}
449+
450+
if (!was_called_from_umfPool && Proxy_pool &&
451+
(umfPoolByPtr(ptr) == Proxy_pool)) {
340452
was_called_from_umfPool = 1;
341453
size_t size = umfPoolMallocUsableSize(Proxy_pool, ptr);
342454
was_called_from_umfPool = 0;
343455
return size;
344456
}
345457

458+
if (threshold_value) {
459+
return system_malloc_usable_size(ptr);
460+
}
461+
462+
LOG_ERR("malloc_usable_size() failed: %p", ptr);
463+
346464
return 0; // unsupported in this case
347465
}
348466

0 commit comments

Comments
 (0)