Skip to content

Commit 5fa5210

Browse files
committed
Load jemalloc library dynamically
Do not link with the jemalloc library explicitly, but load it dynamically (using dlopen()). Ref: #891 Ref: #894 Signed-off-by: Lukasz Dorau <lukasz.dorau@intel.com>
1 parent 0dd3648 commit 5fa5210

File tree

4 files changed

+101
-16
lines changed

4 files changed

+101
-16
lines changed

CMakeLists.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -396,9 +396,9 @@ if(NOT TBB_FOUND)
396396
find_package(TBB OPTIONAL_COMPONENTS tbb)
397397
endif()
398398
if(TBB_FOUND OR TBB_LIBRARY_DIRS)
399+
set(UMF_POOL_SCALABLE_ENABLED TRUE)
399400
# add PATH to DLL on Windows
400401
set(DLL_PATH_LIST "${DLL_PATH_LIST};PATH=path_list_append:${TBB_DLL_DIRS}")
401-
set(UMF_POOL_SCALABLE_ENABLED TRUE)
402402
else()
403403
message(
404404
STATUS
@@ -417,6 +417,10 @@ if(UMF_BUILD_LIBUMF_POOL_JEMALLOC)
417417
# add PATH to DLL on Windows
418418
set(DLL_PATH_LIST
419419
"${DLL_PATH_LIST};PATH=path_list_append:${JEMALLOC_DLL_DIRS}")
420+
# add LD_LIBRARY_PATH to libs on Linux
421+
set(LIST_LD_LIBRARY
422+
"${LIST_LD_LIBRARY};LD_LIBRARY_PATH=path_list_append:${JEMALLOC_LIBRARY_DIRS}"
423+
)
420424
endif()
421425
endif()
422426

src/pool/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ if(UMF_BUILD_LIBUMF_POOL_JEMALLOC)
4545
NAME jemalloc_pool
4646
TYPE STATIC
4747
SRCS pool_jemalloc.c ${POOL_EXTRA_SRCS}
48-
LIBS jemalloc ${POOL_EXTRA_LIBS})
48+
LIBS ${POOL_EXTRA_LIBS})
4949
target_include_directories(jemalloc_pool PRIVATE ${JEMALLOC_INCLUDE_DIRS})
5050
target_compile_definitions(jemalloc_pool
5151
PRIVATE ${POOL_COMPILE_DEFINITIONS})

src/pool/pool_jemalloc.c

Lines changed: 88 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "base_alloc_global.h"
1414
#include "utils_common.h"
1515
#include "utils_concurrency.h"
16+
#include "utils_load_library.h"
1617
#include "utils_log.h"
1718
#include "utils_sanitizers.h"
1819

@@ -34,7 +35,21 @@
3435

3536
#define MALLOCX_ARENA_MAX (MALLCTL_ARENAS_ALL - 1)
3637

38+
typedef struct je_callbacks_t {
39+
void *(*pool_mallocx)(size_t size, int flags);
40+
void *(*pool_rallocx)(void *ptr, size_t size, int flags);
41+
void (*pool_dallocx)(void *ptr, int flags);
42+
int (*pool_mallctl)(const char *name, void *oldp, size_t *oldlenp,
43+
void *newp, size_t newlen);
44+
#ifdef _WIN32
45+
HMODULE lib_handle;
46+
#else
47+
void *lib_handle;
48+
#endif
49+
} je_callbacks_t;
50+
3751
typedef struct jemalloc_memory_pool_t {
52+
je_callbacks_t je_callbacks; // jemalloc callbacks
3853
umf_memory_provider_handle_t provider;
3954
unsigned int arena_index; // index of jemalloc arena
4055
// set to true if umfMemoryProviderFree() should never be called
@@ -51,6 +66,55 @@ static __TLS umf_result_t TLS_last_allocation_error;
5166

5267
static jemalloc_memory_pool_t *pool_by_arena_index[MALLCTL_ARENAS_ALL];
5368

69+
typedef enum je_enums_t {
70+
JE_LIB_NAME = 0,
71+
JE_MALLOCX,
72+
JE_RALLOCX,
73+
JE_DALLOCX,
74+
JE_MALLCTL,
75+
JE_SYMBOLS_MAX // it has to be the last one
76+
} je_enums_t;
77+
78+
static const char *je_symbol[JE_SYMBOLS_MAX] = {
79+
#ifdef _WIN32
80+
"libjemalloc.dll", "je_mallocx", "je_rallocx", "je_dallocx", "je_mallctl",
81+
#else
82+
"libjemalloc.so.2", "mallocx", "rallocx", "dallocx", "mallctl",
83+
#endif
84+
};
85+
86+
static int init_je_callbacks(je_callbacks_t *je_callbacks) {
87+
assert(je_callbacks);
88+
89+
const char *lib_name = je_symbol[JE_LIB_NAME];
90+
je_callbacks->lib_handle = utils_open_library(lib_name, 0);
91+
if (!je_callbacks->lib_handle) {
92+
LOG_FATAL(
93+
"opening the %s library (required by jemalloc pool) failed - make "
94+
"sure jemalloc is installed and it is in the default search paths",
95+
lib_name);
96+
return -1;
97+
}
98+
99+
*(void **)&je_callbacks->pool_mallocx = utils_get_symbol_addr(
100+
je_callbacks->lib_handle, je_symbol[JE_MALLOCX], lib_name);
101+
*(void **)&je_callbacks->pool_rallocx = utils_get_symbol_addr(
102+
je_callbacks->lib_handle, je_symbol[JE_RALLOCX], lib_name);
103+
*(void **)&je_callbacks->pool_dallocx = utils_get_symbol_addr(
104+
je_callbacks->lib_handle, je_symbol[JE_DALLOCX], lib_name);
105+
*(void **)&je_callbacks->pool_mallctl = utils_get_symbol_addr(
106+
je_callbacks->lib_handle, je_symbol[JE_MALLCTL], lib_name);
107+
108+
if (!je_callbacks->pool_mallocx || !je_callbacks->pool_rallocx ||
109+
!je_callbacks->pool_dallocx || !je_callbacks->pool_mallctl) {
110+
LOG_ERR("cannot find symbols in %s", lib_name);
111+
utils_close_library(je_callbacks->lib_handle);
112+
return -1;
113+
}
114+
115+
return 0;
116+
}
117+
54118
static jemalloc_memory_pool_t *get_pool_by_arena_index(unsigned arena_ind) {
55119
// there is no way to obtain MALLOCX_ARENA_MAX from jemalloc
56120
// so this checks if arena_ind does not exceed assumed range
@@ -359,7 +423,7 @@ static void *op_malloc(void *pool, size_t size) {
359423
// MALLOCX_TCACHE_NONE is set, because jemalloc can mix objects from different arenas inside
360424
// the tcache, so we wouldn't be able to guarantee isolation of different providers.
361425
int flags = MALLOCX_ARENA(je_pool->arena_index) | MALLOCX_TCACHE_NONE;
362-
void *ptr = je_mallocx(size, flags);
426+
void *ptr = (*je_pool->je_callbacks.pool_mallocx)(size, flags);
363427
if (ptr == NULL) {
364428
TLS_last_allocation_error = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
365429
return NULL;
@@ -371,12 +435,12 @@ static void *op_malloc(void *pool, size_t size) {
371435
}
372436

373437
static umf_result_t op_free(void *pool, void *ptr) {
374-
(void)pool; // unused
375438
assert(pool);
439+
jemalloc_memory_pool_t *je_pool = (jemalloc_memory_pool_t *)pool;
376440

377441
if (ptr != NULL) {
378442
VALGRIND_DO_MEMPOOL_FREE(pool, ptr);
379-
je_dallocx(ptr, MALLOCX_TCACHE_NONE);
443+
(*je_pool->je_callbacks.pool_dallocx)(ptr, MALLOCX_TCACHE_NONE);
380444
}
381445

382446
return UMF_RESULT_SUCCESS;
@@ -399,20 +463,21 @@ static void *op_calloc(void *pool, size_t num, size_t size) {
399463

400464
static void *op_realloc(void *pool, void *ptr, size_t size) {
401465
assert(pool);
466+
jemalloc_memory_pool_t *je_pool = (jemalloc_memory_pool_t *)pool;
467+
402468
if (size == 0 && ptr != NULL) {
403-
je_dallocx(ptr, MALLOCX_TCACHE_NONE);
469+
(*je_pool->je_callbacks.pool_dallocx)(ptr, MALLOCX_TCACHE_NONE);
404470
TLS_last_allocation_error = UMF_RESULT_SUCCESS;
405471
VALGRIND_DO_MEMPOOL_FREE(pool, ptr);
406472
return NULL;
407473
} else if (ptr == NULL) {
408474
return op_malloc(pool, size);
409475
}
410476

411-
jemalloc_memory_pool_t *je_pool = (jemalloc_memory_pool_t *)pool;
412477
// MALLOCX_TCACHE_NONE is set, because jemalloc can mix objects from different arenas inside
413478
// the tcache, so we wouldn't be able to guarantee isolation of different providers.
414479
int flags = MALLOCX_ARENA(je_pool->arena_index) | MALLOCX_TCACHE_NONE;
415-
void *new_ptr = je_rallocx(ptr, size, flags);
480+
void *new_ptr = (*je_pool->je_callbacks.pool_rallocx)(ptr, size, flags);
416481
if (new_ptr == NULL) {
417482
TLS_last_allocation_error = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
418483
return NULL;
@@ -437,7 +502,7 @@ static void *op_aligned_alloc(void *pool, size_t size, size_t alignment) {
437502
// the tcache, so we wouldn't be able to guarantee isolation of different providers.
438503
int flags =
439504
MALLOCX_ALIGN(alignment) | MALLOCX_ARENA(arena) | MALLOCX_TCACHE_NONE;
440-
void *ptr = je_mallocx(size, flags);
505+
void *ptr = (*je_pool->je_callbacks.pool_mallocx)(size, flags);
441506
if (ptr == NULL) {
442507
TLS_last_allocation_error = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
443508
return NULL;
@@ -453,6 +518,8 @@ static umf_result_t op_initialize(umf_memory_provider_handle_t provider,
453518
assert(provider);
454519
assert(out_pool);
455520

521+
umf_result_t umf_result = UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC;
522+
456523
umf_jemalloc_pool_params_handle_t je_params =
457524
(umf_jemalloc_pool_params_handle_t)params;
458525

@@ -466,6 +533,13 @@ static umf_result_t op_initialize(umf_memory_provider_handle_t provider,
466533
return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
467534
}
468535

536+
int ret = init_je_callbacks(&pool->je_callbacks);
537+
if (ret != 0) {
538+
LOG_ERR("loading jemalloc symbols failed");
539+
umf_result = UMF_RESULT_ERROR_UNKNOWN;
540+
goto err_free_pool;
541+
}
542+
469543
pool->provider = provider;
470544

471545
if (je_params) {
@@ -475,8 +549,8 @@ static umf_result_t op_initialize(umf_memory_provider_handle_t provider,
475549
}
476550

477551
unsigned arena_index;
478-
err = je_mallctl("arenas.create", (void *)&arena_index, &unsigned_size,
479-
NULL, 0);
552+
err = (*pool->je_callbacks.pool_mallctl)(
553+
"arenas.create", (void *)&arena_index, &unsigned_size, NULL, 0);
480554
if (err) {
481555
LOG_ERR("Could not create arena.");
482556
goto err_free_pool;
@@ -485,10 +559,11 @@ static umf_result_t op_initialize(umf_memory_provider_handle_t provider,
485559
// setup extent_hooks for newly created arena
486560
char cmd[64];
487561
snprintf(cmd, sizeof(cmd), "arena.%u.extent_hooks", arena_index);
488-
err = je_mallctl(cmd, NULL, NULL, (void *)&pHooks, sizeof(void *));
562+
err = (*pool->je_callbacks.pool_mallctl)(cmd, NULL, NULL, (void *)&pHooks,
563+
sizeof(void *));
489564
if (err) {
490565
snprintf(cmd, sizeof(cmd), "arena.%u.destroy", arena_index);
491-
je_mallctl(cmd, NULL, 0, NULL, 0);
566+
(*pool->je_callbacks.pool_mallctl)(cmd, NULL, 0, NULL, 0);
492567
LOG_ERR("Could not setup extent_hooks for newly created arena.");
493568
goto err_free_pool;
494569
}
@@ -504,15 +579,15 @@ static umf_result_t op_initialize(umf_memory_provider_handle_t provider,
504579

505580
err_free_pool:
506581
umf_ba_global_free(pool);
507-
return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC;
582+
return umf_result;
508583
}
509584

510585
static void op_finalize(void *pool) {
511586
assert(pool);
512587
jemalloc_memory_pool_t *je_pool = (jemalloc_memory_pool_t *)pool;
513588
char cmd[64];
514589
snprintf(cmd, sizeof(cmd), "arena.%u.destroy", je_pool->arena_index);
515-
je_mallctl(cmd, NULL, 0, NULL, 0);
590+
(*je_pool->je_callbacks.pool_mallctl)(cmd, NULL, 0, NULL, 0);
516591
pool_by_arena_index[je_pool->arena_index] = NULL;
517592
umf_ba_global_free(je_pool);
518593

test/CMakeLists.txt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ function(build_umf_test)
3838
set(TEST_NAME umf-${ARG_NAME})
3939
set(TEST_TARGET_NAME umf_test-${ARG_NAME})
4040

41-
set(LIB_DIRS ${LIB_DIRS} ${LIBHWLOC_LIBRARY_DIRS})
41+
if(NOT UMF_DISABLE_HWLOC)
42+
set(LIB_DIRS ${LIB_DIRS} ${LIBHWLOC_LIBRARY_DIRS})
43+
endif()
4244

4345
if(UMF_BUILD_LIBUMF_POOL_JEMALLOC)
4446
set(LIB_DIRS ${LIB_DIRS} ${JEMALLOC_LIBRARY_DIRS})
@@ -126,6 +128,10 @@ function(add_umf_test)
126128
# append PATH to DLLs
127129
set_property(TEST ${TEST_NAME} PROPERTY ENVIRONMENT_MODIFICATION
128130
"${DLL_PATH_LIST}")
131+
else()
132+
# append LD_LIBRARY_PATH to libs
133+
set_property(TEST ${TEST_NAME} PROPERTY ENVIRONMENT_MODIFICATION
134+
"${LIST_LD_LIBRARY}")
129135
endif()
130136
endfunction()
131137

0 commit comments

Comments
 (0)