@@ -30,9 +30,14 @@ umf_memory_pool_ops_t *umfJemallocPoolOps(void) { return NULL; }
3030
3131#define MALLOCX_ARENA_MAX (MALLCTL_ARENAS_ALL - 1)
3232
33+ typedef struct umf_jemalloc_pool_params_t {
34+ size_t numArenas ;
35+ } umf_jemalloc_pool_params_t ;
36+
3337typedef struct jemalloc_memory_pool_t {
3438 umf_memory_provider_handle_t provider ;
35- unsigned int arena_index ; // index of jemalloc arena
39+ size_t n_arenas ;
40+ unsigned int arena_index [];
3641} jemalloc_memory_pool_t ;
3742
3843static __TLS umf_result_t TLS_last_allocation_error ;
@@ -47,6 +52,14 @@ static jemalloc_memory_pool_t *get_pool_by_arena_index(unsigned arena_ind) {
4752 return pool_by_arena_index [arena_ind ];
4853}
4954
55+ // SplitMix64 hash
56+ static uint64_t hash64 (uint64_t x ) {
57+ x += 0x9e3779b97f4a7c15 ;
58+ x = (x ^ (x >> 30 )) * 0xbf58476d1ce4e5b9 ;
59+ x = (x ^ (x >> 27 )) * 0x94d049bb133111eb ;
60+ return x ^ (x >> 31 );
61+ }
62+
5063// arena_extent_alloc - an extent allocation function conforms to the extent_alloc_t type and upon
5164// success returns a pointer to size bytes of mapped memory on behalf of arena arena_ind such that
5265// the extent's base address is a multiple of alignment, as well as setting *zero to indicate
@@ -285,12 +298,17 @@ static extent_hooks_t arena_extent_hooks = {
285298 .merge = arena_extent_merge ,
286299};
287300
301+ static unsigned get_arena_index (jemalloc_memory_pool_t * pool ) {
302+ unsigned pid = utils_getpid ();
303+ return pool -> arena_index [hash64 (pid ) % pool -> n_arenas ];
304+ }
305+
288306static void * op_malloc (void * pool , size_t size ) {
289307 assert (pool );
290308 jemalloc_memory_pool_t * je_pool = (jemalloc_memory_pool_t * )pool ;
291309 // MALLOCX_TCACHE_NONE is set, because jemalloc can mix objects from different arenas inside
292310 // the tcache, so we wouldn't be able to guarantee isolation of different providers.
293- int flags = MALLOCX_ARENA (je_pool -> arena_index ) | MALLOCX_TCACHE_NONE ;
311+ int flags = MALLOCX_ARENA (get_arena_index ( je_pool ) ) | MALLOCX_TCACHE_NONE ;
294312 void * ptr = je_mallocx (size , flags );
295313 if (ptr == NULL ) {
296314 TLS_last_allocation_error = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY ;
@@ -343,7 +361,7 @@ static void *op_realloc(void *pool, void *ptr, size_t size) {
343361 jemalloc_memory_pool_t * je_pool = (jemalloc_memory_pool_t * )pool ;
344362 // MALLOCX_TCACHE_NONE is set, because jemalloc can mix objects from different arenas inside
345363 // the tcache, so we wouldn't be able to guarantee isolation of different providers.
346- int flags = MALLOCX_ARENA (je_pool -> arena_index ) | MALLOCX_TCACHE_NONE ;
364+ int flags = MALLOCX_ARENA (get_arena_index ( je_pool ) ) | MALLOCX_TCACHE_NONE ;
347365 void * new_ptr = je_rallocx (ptr , size , flags );
348366 if (new_ptr == NULL ) {
349367 TLS_last_allocation_error = UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY ;
@@ -364,7 +382,8 @@ static void *op_realloc(void *pool, void *ptr, size_t size) {
364382static void * op_aligned_alloc (void * pool , size_t size , size_t alignment ) {
365383 assert (pool );
366384 jemalloc_memory_pool_t * je_pool = (jemalloc_memory_pool_t * )pool ;
367- unsigned arena = je_pool -> arena_index ;
385+
386+ unsigned arena = get_arena_index (je_pool );
368387 // MALLOCX_TCACHE_NONE is set, because jemalloc can mix objects from different arenas inside
369388 // the tcache, so we wouldn't be able to guarantee isolation of different providers.
370389 int flags =
@@ -382,62 +401,90 @@ static void *op_aligned_alloc(void *pool, size_t size, size_t alignment) {
382401
383402static umf_result_t op_initialize (umf_memory_provider_handle_t provider ,
384403 void * params , void * * out_pool ) {
385- (void )params ; // unused
386404 assert (provider );
387405 assert (out_pool );
388406
389407 extent_hooks_t * pHooks = & arena_extent_hooks ;
390408 size_t unsigned_size = sizeof (unsigned );
391409 int err ;
410+ umf_jemalloc_pool_params_t * jemalloc_params =
411+ (umf_jemalloc_pool_params_t * )params ;
392412
393- jemalloc_memory_pool_t * pool =
394- umf_ba_global_alloc (sizeof (jemalloc_memory_pool_t ));
395- if (!pool ) {
396- return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY ;
413+ size_t nArenas = 0 ;
414+ if (jemalloc_params ) {
415+ nArenas = jemalloc_params -> numArenas ;
397416 }
398417
399- pool -> provider = provider ;
400-
401- unsigned arena_index ;
402- err = je_mallctl ("arenas.create" , (void * )& arena_index , & unsigned_size ,
403- NULL , 0 );
404- if (err ) {
405- LOG_ERR ("Could not create arena." );
406- goto err_free_pool ;
418+ if (nArenas == 0 ) {
419+ nArenas = utils_get_num_cores () * 4 ;
407420 }
408421
409- // setup extent_hooks for newly created arena
410- char cmd [64 ];
411- snprintf (cmd , sizeof (cmd ), "arena.%u.extent_hooks" , arena_index );
412- err = je_mallctl (cmd , NULL , NULL , (void * )& pHooks , sizeof (void * ));
413- if (err ) {
414- snprintf (cmd , sizeof (cmd ), "arena.%u.destroy" , arena_index );
415- (void )je_mallctl (cmd , NULL , 0 , NULL , 0 );
416- LOG_ERR ("Could not setup extent_hooks for newly created arena." );
417- goto err_free_pool ;
422+ jemalloc_memory_pool_t * pool = umf_ba_global_alloc (
423+ sizeof (* pool ) + nArenas * sizeof (* pool -> arena_index ));
424+ if (!pool ) {
425+ return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY ;
418426 }
419427
420- pool -> arena_index = arena_index ;
421- pool_by_arena_index [arena_index ] = pool ;
422-
428+ pool -> provider = provider ;
429+ pool -> n_arenas = nArenas ;
430+
431+ size_t num_created = 0 ;
432+ for (size_t i = 0 ; i < nArenas ; i ++ ) {
433+ unsigned arena_index ;
434+ err = je_mallctl ("arenas.create" , (void * )& arena_index , & unsigned_size ,
435+ NULL , 0 );
436+ if (err ) {
437+ LOG_ERR ("Could not create arena." );
438+ goto err_cleanup ;
439+ }
440+
441+ pool -> arena_index [num_created ] = arena_index ;
442+ num_created ++ ;
443+ if (arena_index >= MALLOCX_ARENA_MAX ) {
444+ LOG_ERR ("Number of arenas exceeds the limit." );
445+ goto err_cleanup ;
446+ }
447+
448+ pool_by_arena_index [arena_index ] = pool ;
449+
450+ // Setup extent_hooks for the newly created arena.
451+ char cmd [64 ];
452+ snprintf (cmd , sizeof (cmd ), "arena.%u.extent_hooks" , arena_index );
453+ err = je_mallctl (cmd , NULL , NULL , (void * )& pHooks , sizeof (void * ));
454+ if (err ) {
455+ LOG_ERR ("Could not setup extent_hooks for newly created arena." );
456+ goto err_cleanup ;
457+ }
458+ }
423459 * out_pool = (umf_memory_pool_handle_t )pool ;
424460
425461 VALGRIND_DO_CREATE_MEMPOOL (pool , 0 , 0 );
426462
427463 return UMF_RESULT_SUCCESS ;
428464
429- err_free_pool :
465+ err_cleanup :
466+ // Destroy any arenas that were successfully created.
467+ for (size_t i = 0 ; i < num_created ; i ++ ) {
468+ char cmd [64 ];
469+ unsigned arena = pool -> arena_index [i ];
470+ pool_by_arena_index [arena ] = NULL ;
471+ snprintf (cmd , sizeof (cmd ), "arena.%u.destroy" , arena );
472+ (void )je_mallctl (cmd , NULL , 0 , NULL , 0 );
473+ }
430474 umf_ba_global_free (pool );
431475 return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC ;
432476}
433477
434478static void op_finalize (void * pool ) {
435479 assert (pool );
436480 jemalloc_memory_pool_t * je_pool = (jemalloc_memory_pool_t * )pool ;
437- char cmd [64 ];
438- snprintf (cmd , sizeof (cmd ), "arena.%u.destroy" , je_pool -> arena_index );
439- (void )je_mallctl (cmd , NULL , 0 , NULL , 0 );
440- pool_by_arena_index [je_pool -> arena_index ] = NULL ;
481+ for (size_t i = 0 ; i < je_pool -> n_arenas ; i ++ ) {
482+ char cmd [64 ];
483+ unsigned arena = je_pool -> arena_index [i ];
484+ pool_by_arena_index [arena ] = NULL ;
485+ snprintf (cmd , sizeof (cmd ), "arena.%u.destroy" , arena );
486+ (void )je_mallctl (cmd , NULL , 0 , NULL , 0 );
487+ }
441488 umf_ba_global_free (je_pool );
442489
443490 VALGRIND_DO_DESTROY_MEMPOOL (pool );
@@ -469,4 +516,32 @@ static umf_memory_pool_ops_t UMF_JEMALLOC_POOL_OPS = {
469516umf_memory_pool_ops_t * umfJemallocPoolOps (void ) {
470517 return & UMF_JEMALLOC_POOL_OPS ;
471518}
519+
520+ umf_result_t
521+ umfJemallocPoolParamsCreate (umf_jemalloc_pool_params_handle_t * hParams ) {
522+ umf_jemalloc_pool_params_t * params = umf_ba_global_alloc (sizeof (* params ));
523+ if (!params ) {
524+ return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY ;
525+ }
526+ * hParams = params ;
527+ return UMF_RESULT_SUCCESS ;
528+ }
529+
530+ umf_result_t
531+ umfJemallocPoolParamsDestroy (umf_jemalloc_pool_params_handle_t hParams ) {
532+ umf_ba_global_free (hParams );
533+ return UMF_RESULT_SUCCESS ;
534+ }
535+
536+ umf_result_t
537+ umfJemallocPoolParamsSetNumArenas (umf_jemalloc_pool_params_handle_t hParams ,
538+ size_t numArenas ) {
539+ if (!hParams ) {
540+ LOG_ERR ("jemalloc pool params handle is NULL" );
541+ return UMF_RESULT_ERROR_INVALID_ARGUMENT ;
542+ }
543+ hParams -> numArenas = numArenas ;
544+ return UMF_RESULT_SUCCESS ;
545+ }
546+
472547#endif /* UMF_POOL_JEMALLOC_ENABLED */
0 commit comments