#if JEMALLOC_VERSION_MAJOR < 4
#define sdallocx(ptr, size, flags) dallocx(ptr, flags)
+#define MALLOCX_TCACHE_NONE (0)
#endif /* JEMALLOC_VERSION_MAJOR < 4 */
#else
unsigned int isc_mem_debugging = ISC_MEM_DEBUGGING;
unsigned int isc_mem_defaultflags = ISC_MEMFLAG_DEFAULT;
+#define ISC_MEM_ILLEGAL_ARENA (UINT_MAX)
+
/*
* Constants.
*/
struct isc_mem {
unsigned int magic;
unsigned int flags;
+ unsigned int jemalloc_flags;
+ unsigned int jemalloc_arena;
isc_mutex_t lock;
bool checkfree;
struct stats stats[STATS_BUCKETS + 1];
#endif
idx = hash % DEBUG_TABLE_COUNT;
- dl = mallocx(sizeof(debuglink_t), 0);
+ dl = mallocx(sizeof(*dl), mctx->jemalloc_flags);
INSIST(dl != NULL);
- increment_malloced(mctx, sizeof(debuglink_t));
+ increment_malloced(mctx, sizeof(*dl));
ISC_LINK_INIT(dl, link);
dl->ptr = ptr;
if (dl->ptr == ptr) {
ISC_LIST_UNLINK(mctx->debuglist[idx], dl, link);
decrement_malloced(mctx, sizeof(*dl));
- sdallocx(dl, sizeof(*dl), 0);
+ sdallocx(dl, sizeof(*dl), mctx->jemalloc_flags);
goto unlock;
}
dl = ISC_LIST_NEXT(dl, link);
ADJUST_ZERO_ALLOCATION_SIZE(size);
- ret = mallocx(size, flags);
+ ret = mallocx(size, flags | ctx->jemalloc_flags);
INSIST(ret != NULL);
if ((ctx->flags & ISC_MEMFLAG_FILL) != 0) {
if ((ctx->flags & ISC_MEMFLAG_FILL) != 0) {
memset(mem, 0xde, size); /* Mnemonic for "dead". */
}
- sdallocx(mem, size, flags);
+ sdallocx(mem, size, flags | ctx->jemalloc_flags);
}
static void *
ADJUST_ZERO_ALLOCATION_SIZE(new_size);
- new_ptr = rallocx(old_ptr, new_size, flags);
+ new_ptr = rallocx(old_ptr, new_size, flags | ctx->jemalloc_flags);
INSIST(new_ptr != NULL);
if ((ctx->flags & ISC_MEMFLAG_FILL) != 0) {
* Private.
*/
+static bool
+mem_jemalloc_arena_create(unsigned int *pnew_arenano) {
+ REQUIRE(pnew_arenano != NULL);
+
+#if defined(JEMALLOC_API_SUPPORTED) && JEMALLOC_VERSION_MAJOR >= 4
+ unsigned int arenano = 0;
+ size_t len = sizeof(arenano);
+ int res = 0;
+
+ res = mallctl("arenas.create", &arenano, &len, NULL, 0);
+ if (res != 0) {
+ return (false);
+ }
+
+ *pnew_arenano = arenano;
+
+ return (true);
+#else
+ *pnew_arenano = ISC_MEM_ILLEGAL_ARENA;
+ return (true);
+#endif /* defined(JEMALLOC_API_SUPPORTED) && JEMALLOC_VERSION_MAJOR >= 4 */
+}
+
+static bool
+mem_jemalloc_arena_destroy(unsigned int arenano) {
+#if defined(JEMALLOC_API_SUPPORTED) && JEMALLOC_VERSION_MAJOR >= 4
+ int res = 0;
+ char buf[256] = { 0 };
+
+ (void)snprintf(buf, sizeof(buf), "arena.%u.destroy", arenano);
+ res = mallctl(buf, NULL, NULL, NULL, 0);
+ if (res != 0) {
+ return (false);
+ }
+
+ return (true);
+#else
+ UNUSED(arenano);
+ return (true);
+#endif /* defined(JEMALLOC_API_SUPPORTED) && JEMALLOC_VERSION_MAJOR >= 4 */
+}
+
static void
mem_initialize(void) {
isc_mutex_init(&contextslock);
}
static void
-mem_create(isc_mem_t **ctxp, unsigned int flags) {
+mem_create(isc_mem_t **ctxp, unsigned int flags, unsigned int jemalloc_flags) {
isc_mem_t *ctx = NULL;
REQUIRE(ctxp != NULL && *ctxp == NULL);
- ctx = mallocx(sizeof(*ctx), MALLOCX_ALIGN(isc_os_cacheline()));
+ ctx = mallocx(sizeof(*ctx),
+ MALLOCX_ALIGN(isc_os_cacheline()) | jemalloc_flags);
INSIST(ctx != NULL);
*ctx = (isc_mem_t){
.magic = MEM_MAGIC,
.flags = flags,
+ .jemalloc_flags = jemalloc_flags,
+ .jemalloc_arena = ISC_MEM_ILLEGAL_ARENA,
.checkfree = true,
};
unsigned int i;
ctx->debuglist =
- mallocx((DEBUG_TABLE_COUNT * sizeof(debuglist_t)), 0);
+ mallocx((DEBUG_TABLE_COUNT * sizeof(debuglist_t)),
+ ctx->jemalloc_flags);
INSIST(ctx->debuglist != NULL);
for (i = 0; i < DEBUG_TABLE_COUNT; i++) {
destroy(isc_mem_t *ctx) {
unsigned int i;
size_t malloced;
+ unsigned int arena_no;
LOCK(&contextslock);
ISC_LIST_UNLINK(contexts, ctx, link);
ctx->magic = 0;
+ arena_no = ctx->jemalloc_arena;
+
INSIST(ISC_LIST_EMPTY(ctx->pools));
#if ISC_MEM_TRACKLINES
INSIST(!ctx->checkfree || dl->ptr == NULL);
ISC_LIST_UNLINK(ctx->debuglist[i], dl, link);
- sdallocx(dl, sizeof(*dl), 0);
+ sdallocx(dl, sizeof(*dl), ctx->jemalloc_flags);
decrement_malloced(ctx, sizeof(*dl));
}
}
sdallocx(ctx->debuglist,
- (DEBUG_TABLE_COUNT * sizeof(debuglist_t)), 0);
+ (DEBUG_TABLE_COUNT * sizeof(debuglist_t)),
+ ctx->jemalloc_flags);
decrement_malloced(ctx,
DEBUG_TABLE_COUNT * sizeof(debuglist_t));
}
if (ctx->checkfree) {
INSIST(malloced == 0);
}
- sdallocx(ctx, sizeof(*ctx), MALLOCX_ALIGN(isc_os_cacheline()));
+ sdallocx(ctx, sizeof(*ctx),
+ MALLOCX_ALIGN(isc_os_cacheline()) | ctx->jemalloc_flags);
+
+ if (arena_no != ISC_MEM_ILLEGAL_ARENA) {
+ RUNTIME_CHECK(mem_jemalloc_arena_destroy(arena_no) == true);
+ }
}
void
ptr = mem_get(ctx, size, 0);
/* Recalculate the real allocated size */
- size = sallocx(ptr, 0);
+ size = sallocx(ptr, ctx->jemalloc_flags);
mem_getstats(ctx, size);
ADD_TRACE(ctx, ptr, size, file, line);
} else if (new_size == 0) {
isc__mem_free(ctx, old_ptr FLARG_PASS);
} else {
- size_t old_size = sallocx(old_ptr, 0);
+ size_t old_size = sallocx(old_ptr, ctx->jemalloc_flags);
DELETE_TRACE(ctx, old_ptr, old_size, file, line);
mem_putstats(ctx, old_ptr, old_size);
new_ptr = mem_realloc(ctx, old_ptr, old_size, new_size, 0);
/* Recalculate the real allocated size */
- new_size = sallocx(new_ptr, 0);
+ new_size = sallocx(new_ptr, ctx->jemalloc_flags);
mem_getstats(ctx, new_size);
ADD_TRACE(ctx, new_ptr, new_size, file, line);
REQUIRE(VALID_CONTEXT(ctx));
- size = sallocx(ptr, 0);
+ size = sallocx(ptr, ctx->jemalloc_flags);
DELETE_TRACE(ctx, ptr, size, file, line);
void
isc__mem_create(isc_mem_t **mctxp FLARG) {
- mem_create(mctxp, isc_mem_defaultflags);
+ mem_create(mctxp, isc_mem_defaultflags, 0);
#if ISC_MEM_TRACKLINES
if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0) {
fprintf(stderr, "create mctx %p file %s line %u\n", *mctxp,
#endif /* ISC_MEM_TRACKLINES */
}
+void
+isc__mem_create_arena(isc_mem_t **mctxp FLARG) {
+ unsigned int arena_no = ISC_MEM_ILLEGAL_ARENA;
+
+ RUNTIME_CHECK(mem_jemalloc_arena_create(&arena_no));
+
+ /*
+ * We use MALLOCX_TCACHE_NONE to bypass the tcache and route
+ * allocations directly to the arena. That is a recommendation
+ * from jemalloc developers:
+ *
+ * https://github.com/jemalloc/jemalloc/issues/2483#issuecomment-1698173849
+ */
+ mem_create(mctxp, isc_mem_defaultflags,
+ arena_no == ISC_MEM_ILLEGAL_ARENA
+ ? 0
+ : MALLOCX_ARENA(arena_no) | MALLOCX_TCACHE_NONE);
+ (*mctxp)->jemalloc_arena = arena_no;
+#if ISC_MEM_TRACKLINES
+ if ((isc_mem_debugging & ISC_MEM_DEBUGTRACE) != 0) {
+ fprintf(stderr,
+ "create mctx %p file %s line %u for jemalloc arena "
+ "%u\n",
+ *mctxp, file, line, arena_no);
+ }
+#endif /* ISC_MEM_TRACKLINES */
+}
+
void
isc__mem_printactive(isc_mem_t *ctx, FILE *file) {
#if ISC_MEM_TRACKLINES