Skip to content

Commit 0e184bc

Browse files
committed
Enable jemalloc pool on Windows
Signed-off-by: Lukasz Dorau <[email protected]>
1 parent 0d15548 commit 0e184bc

File tree

8 files changed

+127
-67
lines changed

8 files changed

+127
-67
lines changed

CMakeLists.txt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,18 +113,36 @@ install(
113113
TARGETS umf_headers
114114
EXPORT ${PROJECT_NAME}-targets)
115115

116+
if(WINDOWS)
117+
# set PATH to DLLs on Windows
118+
set(DLL_PATH_LIST "PATH=path_list_append:../bin/$<CONFIG>")
119+
endif()
120+
116121
if(UMF_BUILD_OS_MEMORY_PROVIDER AND (LINUX OR WINDOWS))
117122
pkg_check_modules(LIBHWLOC hwloc)
118123
if(NOT LIBHWLOC_FOUND)
119124
find_package(LIBHWLOC REQUIRED hwloc)
120125
endif()
126+
# add PATH to DLL on Windows
127+
set(DLL_PATH_LIST "${DLL_PATH_LIST};PATH=path_list_append:${LIBHWLOC_LIBRARY_DIRS}/../bin")
121128
endif()
122129

123130
if(UMF_BUILD_LIBUMF_POOL_SCALABLE AND (LINUX OR WINDOWS))
124131
pkg_check_modules(TBB tbb)
125132
if(NOT TBB_FOUND)
126133
find_package(TBB REQUIRED tbb)
127134
endif()
135+
# add PATH to DLL on Windows
136+
set(DLL_PATH_LIST "${DLL_PATH_LIST};PATH=path_list_append:${TBB_LIBRARY_DIRS}/../bin")
137+
endif()
138+
139+
if(UMF_BUILD_LIBUMF_POOL_JEMALLOC AND (LINUX OR WINDOWS))
140+
pkg_check_modules(JEMALLOC jemalloc)
141+
if(NOT JEMALLOC_FOUND)
142+
find_package(JEMALLOC REQUIRED jemalloc)
143+
endif()
144+
# add PATH to DLL on Windows
145+
set(DLL_PATH_LIST "${DLL_PATH_LIST};PATH=path_list_append:${JEMALLOC_LIBRARY_DIRS}/../bin")
128146
endif()
129147

130148
add_subdirectory(src)

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ TODO: Add a description
159159

160160
To enable this feature, the `UMF_BUILD_LIBUMF_POOL_DISJOINT` option needs to be turned `ON`.
161161

162-
#### libumf_pool_jemalloc (Linux-only)
162+
#### libumf_pool_jemalloc
163163

164164
libumf_pool_jemalloc is a [jemalloc](https://github.com/jemalloc/jemalloc)-based memory pool manager built as a separate static library.
165165
The `UMF_BUILD_LIBUMF_POOL_JEMALLOC` option has to be turned `ON` to build this library.
@@ -168,7 +168,7 @@ The `UMF_BUILD_LIBUMF_POOL_JEMALLOC` option has to be turned `ON` to build this
168168

169169
1) The `UMF_BUILD_LIBUMF_POOL_JEMALLOC` option turned `ON`
170170
2) Required packages:
171-
- libjemalloc-dev
171+
- libjemalloc-dev (Linux) or jemalloc (Windows)
172172

173173
#### libumf_pool_scalable
174174

benchmark/CMakeLists.txt

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,6 @@ function(add_umf_benchmark)
4444

4545
if(WINDOWS)
4646
# append PATH to DLLs
47-
set(DLL_PATH_LIST "PATH=path_list_append:../bin/$<CONFIG>")
48-
if(LIBHWLOC_LIBRARY_DIRS)
49-
set(DLL_PATH_LIST "${DLL_PATH_LIST};PATH=path_list_append:${LIBHWLOC_LIBRARY_DIRS}/../bin")
50-
endif()
51-
if(TBB_LIBRARY_DIRS)
52-
set(DLL_PATH_LIST "${DLL_PATH_LIST};PATH=path_list_append:${TBB_LIBRARY_DIRS}/../bin")
53-
endif()
5447
set_property(TEST ${BENCH_NAME} PROPERTY ENVIRONMENT_MODIFICATION "${DLL_PATH_LIST}")
5548
endif()
5649

@@ -70,16 +63,17 @@ endfunction()
7063

7164
# optional libraries
7265
if(UMF_BUILD_LIBUMF_POOL_DISJOINT)
73-
set(LIBS_OPTIONAL ${LIBS_OPTIONAL} disjoint_pool)
66+
set(LIBS_OPTIONAL ${LIBS_OPTIONAL} disjoint_pool)
7467
endif()
7568
if(UMF_BUILD_LIBUMF_POOL_JEMALLOC)
76-
set(LIBS_OPTIONAL ${LIBS_OPTIONAL} jemalloc_pool)
69+
set(LIBS_OPTIONAL ${LIBS_OPTIONAL} jemalloc_pool ${JEMALLOC_LIBRARIES})
70+
set(LIB_DIRS_OPTIONAL ${LIB_DIRS_OPTIONAL} ${JEMALLOC_LIBRARY_DIRS})
7771
endif()
7872
if(UMF_BUILD_LIBUMF_POOL_SCALABLE)
79-
set(LIBS_OPTIONAL ${LIBS_OPTIONAL} scalable_pool)
73+
set(LIBS_OPTIONAL ${LIBS_OPTIONAL} scalable_pool)
8074
endif()
8175
if(LINUX)
82-
set(LIBS_OPTIONAL ${LIBS_OPTIONAL} m)
76+
set(LIBS_OPTIONAL ${LIBS_OPTIONAL} m)
8377
endif()
8478
if(UMF_BUILD_OS_MEMORY_PROVIDER)
8579
set(LIBS_OPTIONAL ${LIBS_OPTIONAL} ${LIBHWLOC_LIBRARIES})

cmake/FindJEMALLOC.cmake

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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+
message(STATUS "Checking for module 'jemalloc' using find_library()")
6+
7+
find_library(JEMALLOC_LIBRARY NAMES libjemalloc jemalloc)
8+
set(JEMALLOC_LIBRARIES ${JEMALLOC_LIBRARY})
9+
10+
get_filename_component(JEMALLOC_LIB_DIR ${JEMALLOC_LIBRARIES} DIRECTORY)
11+
set(JEMALLOC_LIBRARY_DIRS ${JEMALLOC_LIB_DIR})
12+
13+
find_file(JEMALLOC_HEADER NAMES "jemalloc/jemalloc.h")
14+
if(JEMALLOC_HEADER)
15+
get_filename_component(JEMALLOC_INCLUDE_DIR_TBB ${JEMALLOC_HEADER} DIRECTORY)
16+
get_filename_component(JEMALLOC_INCLUDE_DIR ${JEMALLOC_INCLUDE_DIR_TBB} DIRECTORY)
17+
set(JEMALLOC_INCLUDE_DIRS ${JEMALLOC_INCLUDE_DIR})
18+
else()
19+
set(MSG_NOT_FOUND "<jemalloc/jemalloc.h> header NOT found (set CMAKE_PREFIX_PATH to point the location)")
20+
if(JEMALLOC_FIND_REQUIRED)
21+
message(FATAL_ERROR ${MSG_NOT_FOUND})
22+
else()
23+
message(WARNING ${MSG_NOT_FOUND})
24+
endif()
25+
endif()
26+
27+
if(WINDOWS)
28+
find_file(JEMALLOC_DLL NAMES "bin/jemalloc.dll")
29+
get_filename_component(JEMALLOC_DLL_DIR ${JEMALLOC_DLL} DIRECTORY)
30+
set(JEMALLOC_DLL_DIRS ${JEMALLOC_DLL_DIR})
31+
endif()
32+
33+
if(JEMALLOC_LIBRARY)
34+
message(STATUS " Found jemalloc using find_library()")
35+
message(STATUS " JEMALLOC_LIBRARIES = ${JEMALLOC_LIBRARIES}")
36+
message(STATUS " JEMALLOC_INCLUDE_DIRS = ${JEMALLOC_INCLUDE_DIRS}")
37+
message(STATUS " JEMALLOC_LIBRARY_DIRS = ${JEMALLOC_LIBRARY_DIRS}")
38+
if(WINDOWS)
39+
message(STATUS " JEMALLOC_DLL_DIRS = ${JEMALLOC_DLL_DIRS}")
40+
endif()
41+
else()
42+
set(MSG_NOT_FOUND "jemalloc NOT found (set CMAKE_PREFIX_PATH to point the location)")
43+
if(JEMALLOC_FIND_REQUIRED)
44+
message(FATAL_ERROR ${MSG_NOT_FOUND})
45+
else()
46+
message(WARNING ${MSG_NOT_FOUND})
47+
endif()
48+
endif()

examples/CMakeLists.txt

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,6 @@ if(UMF_BUILD_OS_MEMORY_PROVIDER AND UMF_BUILD_LIBUMF_POOL_SCALABLE AND UMF_ENABL
2525

2626
if(WINDOWS)
2727
# append PATH to DLLs
28-
set(DLL_PATH_LIST "PATH=path_list_append:../bin/$<CONFIG>")
29-
if(LIBHWLOC_LIBRARY_DIRS)
30-
set(DLL_PATH_LIST "${DLL_PATH_LIST};PATH=path_list_append:${LIBHWLOC_LIBRARY_DIRS}/../bin")
31-
endif()
32-
if(TBB_LIBRARY_DIRS)
33-
set(DLL_PATH_LIST "${DLL_PATH_LIST};PATH=path_list_append:${TBB_LIBRARY_DIRS}/../bin")
34-
endif()
3528
set_property(TEST ${EXAMPLE_NAME} PROPERTY ENVIRONMENT_MODIFICATION "${DLL_PATH_LIST}")
3629
endif()
3730

src/pool/CMakeLists.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,19 @@ endif()
3535

3636
# libumf_pool_jemalloc
3737
if(UMF_BUILD_LIBUMF_POOL_JEMALLOC)
38-
if(LINUX)
38+
if(LINUX OR WINDOWS)
3939
add_umf_library(NAME jemalloc_pool
4040
TYPE STATIC
4141
SRCS pool_jemalloc.c ${POOL_EXTRA_SRCS}
4242
LIBS jemalloc umf_utils)
43+
target_include_directories(jemalloc_pool PRIVATE ${JEMALLOC_INCLUDE_DIRS})
4344
target_compile_definitions(jemalloc_pool PUBLIC ${POOL_COMPILE_DEFINITIONS})
4445
add_library(${PROJECT_NAME}::jemalloc_pool ALIAS jemalloc_pool)
4546
install(TARGETS jemalloc_pool
4647
EXPORT ${PROJECT_NAME}-targets
4748
)
4849
else()
49-
message(FATAL_ERROR "libumf_pool_jemalloc is supported on Linux only")
50+
message(FATAL_ERROR "libumf_pool_jemalloc is supported on Linux and Windows only")
5051
endif()
5152
endif()
5253

src/pool/pool_jemalloc.c

Lines changed: 44 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@
99
#include <stdio.h>
1010
#include <stdlib.h>
1111
#include <string.h>
12-
#include <sys/mman.h>
13-
14-
#include <jemalloc/jemalloc.h>
1512

1613
#include "base_alloc_global.h"
1714
#include "utils_common.h"
@@ -22,6 +19,18 @@
2219
#include <umf/memory_pool_ops.h>
2320
#include <umf/pools/pool_jemalloc.h>
2421

22+
#include <jemalloc/jemalloc.h>
23+
24+
// The Windows version of jemalloc uses API with je_ prefix,
25+
// while the Linux one does not.
26+
#ifndef _WIN32
27+
#define je_mallocx mallocx
28+
#define je_dallocx dallocx
29+
#define je_rallocx rallocx
30+
#define je_mallctl mallctl
31+
#define je_malloc_usable_size malloc_usable_size
32+
#endif
33+
2534
#define MALLOCX_ARENA_MAX (MALLCTL_ARENAS_ALL - 1)
2635

2736
typedef struct jemalloc_memory_pool_t {
@@ -279,13 +288,13 @@ static extent_hooks_t arena_extent_hooks = {
279288
.merge = arena_extent_merge,
280289
};
281290

282-
static void *je_malloc(void *pool, size_t size) {
291+
static void *op_malloc(void *pool, size_t size) {
283292
assert(pool);
284293
jemalloc_memory_pool_t *je_pool = (jemalloc_memory_pool_t *)pool;
285294
// MALLOCX_TCACHE_NONE is set, because jemalloc can mix objects from different arenas inside
286295
// the tcache, so we wouldn't be able to guarantee isolation of different providers.
287296
int flags = MALLOCX_ARENA(je_pool->arena_index) | MALLOCX_TCACHE_NONE;
288-
void *ptr = mallocx(size, flags);
297+
void *ptr = je_mallocx(size, flags);
289298
if (ptr == NULL) {
290299
TLS_last_allocation_error = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
291300
return NULL;
@@ -296,24 +305,24 @@ static void *je_malloc(void *pool, size_t size) {
296305
return ptr;
297306
}
298307

299-
static umf_result_t je_free(void *pool, void *ptr) {
308+
static umf_result_t op_free(void *pool, void *ptr) {
300309
(void)pool; // unused
301310
assert(pool);
302311

303312
if (ptr != NULL) {
304313
VALGRIND_DO_MEMPOOL_FREE(pool, ptr);
305-
dallocx(ptr, MALLOCX_TCACHE_NONE);
314+
je_dallocx(ptr, MALLOCX_TCACHE_NONE);
306315
}
307316

308317
return UMF_RESULT_SUCCESS;
309318
}
310319

311-
static void *je_calloc(void *pool, size_t num, size_t size) {
320+
static void *op_calloc(void *pool, size_t num, size_t size) {
312321
assert(pool);
313322
size_t csize = num * size;
314-
void *ptr = je_malloc(pool, csize);
323+
void *ptr = op_malloc(pool, csize);
315324
if (ptr == NULL) {
316-
// TLS_last_allocation_error is set by je_malloc()
325+
// TLS_last_allocation_error is set by op_malloc()
317326
return NULL;
318327
}
319328

@@ -323,22 +332,22 @@ static void *je_calloc(void *pool, size_t num, size_t size) {
323332
return ptr;
324333
}
325334

326-
static void *je_realloc(void *pool, void *ptr, size_t size) {
335+
static void *op_realloc(void *pool, void *ptr, size_t size) {
327336
assert(pool);
328337
if (size == 0 && ptr != NULL) {
329-
dallocx(ptr, MALLOCX_TCACHE_NONE);
338+
je_dallocx(ptr, MALLOCX_TCACHE_NONE);
330339
TLS_last_allocation_error = UMF_RESULT_SUCCESS;
331340
VALGRIND_DO_MEMPOOL_FREE(pool, ptr);
332341
return NULL;
333342
} else if (ptr == NULL) {
334-
return je_malloc(pool, size);
343+
return op_malloc(pool, size);
335344
}
336345

337346
jemalloc_memory_pool_t *je_pool = (jemalloc_memory_pool_t *)pool;
338347
// MALLOCX_TCACHE_NONE is set, because jemalloc can mix objects from different arenas inside
339348
// the tcache, so we wouldn't be able to guarantee isolation of different providers.
340349
int flags = MALLOCX_ARENA(je_pool->arena_index) | MALLOCX_TCACHE_NONE;
341-
void *new_ptr = rallocx(ptr, size, flags);
350+
void *new_ptr = je_rallocx(ptr, size, flags);
342351
if (new_ptr == NULL) {
343352
TLS_last_allocation_error = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
344353
return NULL;
@@ -355,15 +364,15 @@ static void *je_realloc(void *pool, void *ptr, size_t size) {
355364
return new_ptr;
356365
}
357366

358-
static void *je_aligned_alloc(void *pool, size_t size, size_t alignment) {
367+
static void *op_aligned_alloc(void *pool, size_t size, size_t alignment) {
359368
assert(pool);
360369
jemalloc_memory_pool_t *je_pool = (jemalloc_memory_pool_t *)pool;
361370
unsigned arena = je_pool->arena_index;
362371
// MALLOCX_TCACHE_NONE is set, because jemalloc can mix objects from different arenas inside
363372
// the tcache, so we wouldn't be able to guarantee isolation of different providers.
364373
int flags =
365374
MALLOCX_ALIGN(alignment) | MALLOCX_ARENA(arena) | MALLOCX_TCACHE_NONE;
366-
void *ptr = mallocx(size, flags);
375+
void *ptr = je_mallocx(size, flags);
367376
if (ptr == NULL) {
368377
TLS_last_allocation_error = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
369378
return NULL;
@@ -374,7 +383,7 @@ static void *je_aligned_alloc(void *pool, size_t size, size_t alignment) {
374383
return ptr;
375384
}
376385

377-
static umf_result_t je_initialize(umf_memory_provider_handle_t provider,
386+
static umf_result_t op_initialize(umf_memory_provider_handle_t provider,
378387
void *params, void **out_pool) {
379388
assert(provider);
380389
assert(out_pool);
@@ -393,8 +402,8 @@ static umf_result_t je_initialize(umf_memory_provider_handle_t provider,
393402
pool->provider = provider;
394403

395404
unsigned arena_index;
396-
err =
397-
mallctl("arenas.create", (void *)&arena_index, &unsigned_size, NULL, 0);
405+
err = je_mallctl("arenas.create", (void *)&arena_index, &unsigned_size,
406+
NULL, 0);
398407
if (err) {
399408
fprintf(stderr, "Could not create arena.\n");
400409
goto err_free_pool;
@@ -403,10 +412,10 @@ static umf_result_t je_initialize(umf_memory_provider_handle_t provider,
403412
// setup extent_hooks for newly created arena
404413
char cmd[64];
405414
snprintf(cmd, sizeof(cmd), "arena.%u.extent_hooks", arena_index);
406-
err = mallctl(cmd, NULL, NULL, (void *)&pHooks, sizeof(void *));
415+
err = je_mallctl(cmd, NULL, NULL, (void *)&pHooks, sizeof(void *));
407416
if (err) {
408417
snprintf(cmd, sizeof(cmd), "arena.%u.destroy", arena_index);
409-
mallctl(cmd, NULL, 0, NULL, 0);
418+
je_mallctl(cmd, NULL, 0, NULL, 0);
410419
fprintf(stderr,
411420
"Could not setup extent_hooks for newly created arena.\n");
412421
goto err_free_pool;
@@ -426,39 +435,39 @@ static umf_result_t je_initialize(umf_memory_provider_handle_t provider,
426435
return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC;
427436
}
428437

429-
static void je_finalize(void *pool) {
438+
static void op_finalize(void *pool) {
430439
assert(pool);
431440
jemalloc_memory_pool_t *je_pool = (jemalloc_memory_pool_t *)pool;
432441
char cmd[64];
433442
snprintf(cmd, sizeof(cmd), "arena.%u.destroy", je_pool->arena_index);
434-
mallctl(cmd, NULL, 0, NULL, 0);
443+
je_mallctl(cmd, NULL, 0, NULL, 0);
435444
pool_by_arena_index[je_pool->arena_index] = NULL;
436445
umf_ba_global_free(je_pool);
437446

438447
VALGRIND_DO_DESTROY_MEMPOOL(pool);
439448
}
440449

441-
static size_t je_malloc_usable_size(void *pool, void *ptr) {
450+
static size_t op_malloc_usable_size(void *pool, void *ptr) {
442451
(void)pool; // not used
443-
return malloc_usable_size(ptr);
452+
return je_malloc_usable_size(ptr);
444453
}
445454

446-
static umf_result_t je_get_last_allocation_error(void *pool) {
455+
static umf_result_t op_get_last_allocation_error(void *pool) {
447456
(void)pool; // not used
448457
return TLS_last_allocation_error;
449458
}
450459

451460
static umf_memory_pool_ops_t UMF_JEMALLOC_POOL_OPS = {
452461
.version = UMF_VERSION_CURRENT,
453-
.initialize = je_initialize,
454-
.finalize = je_finalize,
455-
.malloc = je_malloc,
456-
.calloc = je_calloc,
457-
.realloc = je_realloc,
458-
.aligned_malloc = je_aligned_alloc,
459-
.malloc_usable_size = je_malloc_usable_size,
460-
.free = je_free,
461-
.get_last_allocation_error = je_get_last_allocation_error,
462+
.initialize = op_initialize,
463+
.finalize = op_finalize,
464+
.malloc = op_malloc,
465+
.calloc = op_calloc,
466+
.realloc = op_realloc,
467+
.aligned_malloc = op_aligned_alloc,
468+
.malloc_usable_size = op_malloc_usable_size,
469+
.free = op_free,
470+
.get_last_allocation_error = op_get_last_allocation_error,
462471
};
463472

464473
umf_memory_pool_ops_t *umfJemallocPoolOps(void) {

0 commit comments

Comments
 (0)