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;
unsigned int debugging;
isc_mutex_t lock;
bool checkfree;
#endif
idx = hash % DEBUG_TABLE_COUNT;
- dl = mallocx(sizeof(debuglink_t), 0);
+ dl = mallocx(sizeof(debuglink_t), mctx->jemalloc_flags);
INSIST(dl != NULL);
ISC_LINK_INIT(dl, link);
while (dl != NULL) {
if (dl->ptr == ptr) {
ISC_LIST_UNLINK(mctx->debuglist[idx], dl, link);
- 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 ((flags & ISC__MEM_ZERO) == 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 ((flags & ISC__MEM_ZERO) == 0 &&
* Private.
*/
+static bool
+mem_jemalloc_arena_create(unsigned int *pnew_arenano) {
+ REQUIRE(pnew_arenano != NULL);
+
+#ifdef JEMALLOC_API_SUPPORTED
+ 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 /* JEMALLOC_API_SUPPORTED */
+}
+
+static bool
+mem_jemalloc_arena_destroy(unsigned int arenano) {
+#ifdef JEMALLOC_API_SUPPORTED
+ 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 /* JEMALLOC_API_SUPPORTED */
+}
+
static void
mem_initialize(void) {
/*
}
static void
-mem_create(isc_mem_t **ctxp, unsigned int debugging, unsigned int flags) {
+mem_create(isc_mem_t **ctxp, unsigned int debugging, unsigned int flags,
+ unsigned int jemalloc_flags) {
isc_mem_t *ctx = NULL;
REQUIRE(ctxp != NULL && *ctxp == NULL);
- ctx = malloc(sizeof(*ctx));
+ ctx = mallocx(sizeof(*ctx), jemalloc_flags);
INSIST(ctx != NULL);
*ctx = (isc_mem_t){
.magic = MEM_MAGIC,
.debugging = debugging,
.flags = flags,
+ .jemalloc_flags = jemalloc_flags,
+ .jemalloc_arena = ISC_MEM_ILLEGAL_ARENA,
.checkfree = true,
};
if ((ctx->debugging & ISC_MEM_DEBUGRECORD) != 0) {
unsigned int i;
- ctx->debuglist = calloc(DEBUG_TABLE_COUNT, sizeof(debuglist_t));
+ ctx->debuglist = mallocx(
+ ISC_CHECKED_MUL(DEBUG_TABLE_COUNT, sizeof(debuglist_t)),
+ jemalloc_flags);
INSIST(ctx->debuglist != NULL);
for (i = 0; i < DEBUG_TABLE_COUNT; i++) {
static void
destroy(isc_mem_t *ctx) {
+ unsigned int arena_no;
LOCK(&contextslock);
ISC_LIST_UNLINK(contexts, ctx, link);
UNLOCK(&contextslock);
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);
}
}
- free(ctx->debuglist);
+ sdallocx(
+ ctx->debuglist,
+ ISC_CHECKED_MUL(DEBUG_TABLE_COUNT, sizeof(debuglist_t)),
+ ctx->jemalloc_flags);
}
#endif /* if ISC_MEM_TRACKLINES */
if (ctx->checkfree) {
INSIST(atomic_load(&ctx->inuse) == 0);
}
- free(ctx);
+ sdallocx(ctx, sizeof(*ctx), 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, flags);
/* Recalculate the real allocated size */
- size = sallocx(ptr, flags);
+ size = sallocx(ptr, flags | 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, flags FLARG_PASS);
} else {
- size_t old_size = sallocx(old_ptr, flags);
+ size_t old_size = sallocx(old_ptr, flags | ctx->jemalloc_flags);
DELETE_TRACE(ctx, old_ptr, old_size, file, line);
mem_putstats(ctx, old_size);
new_ptr = mem_realloc(ctx, old_ptr, old_size, new_size, flags);
/* Recalculate the real allocated size */
- new_size = sallocx(new_ptr, flags);
+ new_size = sallocx(new_ptr, flags | ctx->jemalloc_flags);
mem_getstats(ctx, new_size);
ADD_TRACE(ctx, new_ptr, new_size, file, line);
REQUIRE(VALID_CONTEXT(ctx));
REQUIRE(ptr != NULL);
- size = sallocx(ptr, flags);
+ size = sallocx(ptr, flags | ctx->jemalloc_flags);
DELETE_TRACE(ctx, ptr, size, file, line);
void
isc__mem_create(isc_mem_t **mctxp FLARG) {
- mem_create(mctxp, isc_mem_debugging, isc_mem_defaultflags);
+ mem_create(mctxp, isc_mem_debugging, 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_debugging, 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