@@ -30,9 +30,14 @@ umf_memory_pool_ops_t *umfJemallocPoolOps(void) { return NULL; }
30
30
31
31
#define MALLOCX_ARENA_MAX (MALLCTL_ARENAS_ALL - 1)
32
32
33
+ typedef struct umf_jemalloc_pool_params_t {
34
+ size_t numArenas ;
35
+ } umf_jemalloc_pool_params_t ;
36
+
33
37
typedef struct jemalloc_memory_pool_t {
34
38
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 [];
36
41
} jemalloc_memory_pool_t ;
37
42
38
43
static __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) {
47
52
return pool_by_arena_index [arena_ind ];
48
53
}
49
54
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
+
50
63
// arena_extent_alloc - an extent allocation function conforms to the extent_alloc_t type and upon
51
64
// success returns a pointer to size bytes of mapped memory on behalf of arena arena_ind such that
52
65
// 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 = {
285
298
.merge = arena_extent_merge ,
286
299
};
287
300
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
+
288
306
static void * op_malloc (void * pool , size_t size ) {
289
307
assert (pool );
290
308
jemalloc_memory_pool_t * je_pool = (jemalloc_memory_pool_t * )pool ;
291
309
// MALLOCX_TCACHE_NONE is set, because jemalloc can mix objects from different arenas inside
292
310
// 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 ;
294
312
void * ptr = je_mallocx (size , flags );
295
313
if (ptr == NULL ) {
296
314
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) {
343
361
jemalloc_memory_pool_t * je_pool = (jemalloc_memory_pool_t * )pool ;
344
362
// MALLOCX_TCACHE_NONE is set, because jemalloc can mix objects from different arenas inside
345
363
// 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 ;
347
365
void * new_ptr = je_rallocx (ptr , size , flags );
348
366
if (new_ptr == NULL ) {
349
367
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) {
364
382
static void * op_aligned_alloc (void * pool , size_t size , size_t alignment ) {
365
383
assert (pool );
366
384
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 );
368
387
// MALLOCX_TCACHE_NONE is set, because jemalloc can mix objects from different arenas inside
369
388
// the tcache, so we wouldn't be able to guarantee isolation of different providers.
370
389
int flags =
@@ -382,62 +401,89 @@ static void *op_aligned_alloc(void *pool, size_t size, size_t alignment) {
382
401
383
402
static umf_result_t op_initialize (umf_memory_provider_handle_t provider ,
384
403
void * params , void * * out_pool ) {
385
- (void )params ; // unused
386
404
assert (provider );
387
405
assert (out_pool );
388
406
389
407
extent_hooks_t * pHooks = & arena_extent_hooks ;
390
408
size_t unsigned_size = sizeof (unsigned );
391
409
int err ;
410
+ umf_jemalloc_pool_params_t * jemalloc_params =
411
+ (umf_jemalloc_pool_params_t * )params ;
392
412
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 ;
397
416
}
398
417
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 ;
407
420
}
408
421
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 ;
418
426
}
419
427
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
+ if (arena_index >= MALLOCX_ARENA_MAX ) {
443
+ LOG_ERR ("Number of arenas exceeds the limit." );
444
+ goto err_cleanup ;
445
+ }
446
+
447
+ pool_by_arena_index [arena_index ] = pool ;
448
+
449
+ // Setup extent_hooks for the newly created arena.
450
+ char cmd [64 ];
451
+ snprintf (cmd , sizeof (cmd ), "arena.%u.extent_hooks" , arena_index );
452
+ err = je_mallctl (cmd , NULL , NULL , (void * )& pHooks , sizeof (void * ));
453
+ if (err ) {
454
+ LOG_ERR ("Could not setup extent_hooks for newly created arena." );
455
+ goto err_cleanup ;
456
+ }
457
+ }
423
458
* out_pool = (umf_memory_pool_handle_t )pool ;
424
459
425
460
VALGRIND_DO_CREATE_MEMPOOL (pool , 0 , 0 );
426
461
427
462
return UMF_RESULT_SUCCESS ;
428
463
429
- err_free_pool :
464
+ err_cleanup :
465
+ // Destroy any arenas that were successfully created.
466
+ for (size_t i = 0 ; i < num_created ; i ++ ) {
467
+ char cmd [64 ];
468
+ unsigned arena = pool -> arena_index [i ];
469
+ snprintf (cmd , sizeof (cmd ), "arena.%u.destroy" , arena );
470
+ (void )je_mallctl (cmd , NULL , 0 , NULL , 0 );
471
+ pool_by_arena_index [arena ] = NULL ;
472
+ }
430
473
umf_ba_global_free (pool );
431
474
return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC ;
432
475
}
433
476
434
477
static void op_finalize (void * pool ) {
435
478
assert (pool );
436
479
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 ;
480
+ for (size_t i = 0 ; i < je_pool -> n_arenas ; i ++ ) {
481
+ char cmd [64 ];
482
+ unsigned arena = je_pool -> arena_index [i ];
483
+ snprintf (cmd , sizeof (cmd ), "arena.%u.destroy" , arena );
484
+ (void )je_mallctl (cmd , NULL , 0 , NULL , 0 );
485
+ pool_by_arena_index [arena ] = NULL ;
486
+ }
441
487
umf_ba_global_free (je_pool );
442
488
443
489
VALGRIND_DO_DESTROY_MEMPOOL (pool );
@@ -469,4 +515,32 @@ static umf_memory_pool_ops_t UMF_JEMALLOC_POOL_OPS = {
469
515
umf_memory_pool_ops_t * umfJemallocPoolOps (void ) {
470
516
return & UMF_JEMALLOC_POOL_OPS ;
471
517
}
518
+
519
+ umf_result_t
520
+ umfJemallocPoolParamsCreate (umf_jemalloc_pool_params_handle_t * hParams ) {
521
+ umf_jemalloc_pool_params_t * params = umf_ba_global_alloc (sizeof (* params ));
522
+ if (!params ) {
523
+ return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY ;
524
+ }
525
+ * hParams = params ;
526
+ return UMF_RESULT_SUCCESS ;
527
+ }
528
+
529
+ umf_result_t
530
+ umfJemallocPoolParamsDestroy (umf_jemalloc_pool_params_handle_t hParams ) {
531
+ umf_ba_global_free (hParams );
532
+ return UMF_RESULT_SUCCESS ;
533
+ }
534
+
535
+ umf_result_t
536
+ umfJemallocPoolParamsSetNumArenas (umf_jemalloc_pool_params_handle_t hParams ,
537
+ size_t numArenas ) {
538
+ if (!hParams ) {
539
+ LOG_ERR ("jemalloc pool params handle is NULL" );
540
+ return UMF_RESULT_ERROR_INVALID_ARGUMENT ;
541
+ }
542
+ hParams -> numArenas = numArenas ;
543
+ return UMF_RESULT_SUCCESS ;
544
+ }
545
+
472
546
#endif /* UMF_POOL_JEMALLOC_ENABLED */
0 commit comments