1*7bdf38e5Schristos #include "test/jemalloc_test.h" 2*7bdf38e5Schristos 3*7bdf38e5Schristos /* Config -- "narenas:1,bin_shards:1-160:16|129-512:4|256-256:8" */ 4*7bdf38e5Schristos 5*7bdf38e5Schristos #define NTHREADS 16 6*7bdf38e5Schristos #define REMOTE_NALLOC 256 7*7bdf38e5Schristos 8*7bdf38e5Schristos static void * 9*7bdf38e5Schristos thd_producer(void *varg) { 10*7bdf38e5Schristos void **mem = varg; 11*7bdf38e5Schristos unsigned arena, i; 12*7bdf38e5Schristos size_t sz; 13*7bdf38e5Schristos 14*7bdf38e5Schristos sz = sizeof(arena); 15*7bdf38e5Schristos /* Remote arena. */ 16*7bdf38e5Schristos expect_d_eq(mallctl("arenas.create", (void *)&arena, &sz, NULL, 0), 0, 17*7bdf38e5Schristos "Unexpected mallctl() failure"); 18*7bdf38e5Schristos for (i = 0; i < REMOTE_NALLOC / 2; i++) { 19*7bdf38e5Schristos mem[i] = mallocx(1, MALLOCX_TCACHE_NONE | MALLOCX_ARENA(arena)); 20*7bdf38e5Schristos } 21*7bdf38e5Schristos 22*7bdf38e5Schristos /* Remote bin. */ 23*7bdf38e5Schristos for (; i < REMOTE_NALLOC; i++) { 24*7bdf38e5Schristos mem[i] = mallocx(1, MALLOCX_TCACHE_NONE | MALLOCX_ARENA(0)); 25*7bdf38e5Schristos } 26*7bdf38e5Schristos 27*7bdf38e5Schristos return NULL; 28*7bdf38e5Schristos } 29*7bdf38e5Schristos 30*7bdf38e5Schristos TEST_BEGIN(test_producer_consumer) { 31*7bdf38e5Schristos thd_t thds[NTHREADS]; 32*7bdf38e5Schristos void *mem[NTHREADS][REMOTE_NALLOC]; 33*7bdf38e5Schristos unsigned i; 34*7bdf38e5Schristos 35*7bdf38e5Schristos /* Create producer threads to allocate. */ 36*7bdf38e5Schristos for (i = 0; i < NTHREADS; i++) { 37*7bdf38e5Schristos thd_create(&thds[i], thd_producer, mem[i]); 38*7bdf38e5Schristos } 39*7bdf38e5Schristos for (i = 0; i < NTHREADS; i++) { 40*7bdf38e5Schristos thd_join(thds[i], NULL); 41*7bdf38e5Schristos } 42*7bdf38e5Schristos /* Remote deallocation by the current thread. */ 43*7bdf38e5Schristos for (i = 0; i < NTHREADS; i++) { 44*7bdf38e5Schristos for (unsigned j = 0; j < REMOTE_NALLOC; j++) { 45*7bdf38e5Schristos expect_ptr_not_null(mem[i][j], 46*7bdf38e5Schristos "Unexpected remote allocation failure"); 47*7bdf38e5Schristos dallocx(mem[i][j], 0); 48*7bdf38e5Schristos } 49*7bdf38e5Schristos } 50*7bdf38e5Schristos } 51*7bdf38e5Schristos TEST_END 52*7bdf38e5Schristos 53*7bdf38e5Schristos static void * 54*7bdf38e5Schristos thd_start(void *varg) { 55*7bdf38e5Schristos void *ptr, *ptr2; 56*7bdf38e5Schristos edata_t *edata; 57*7bdf38e5Schristos unsigned shard1, shard2; 58*7bdf38e5Schristos 59*7bdf38e5Schristos tsdn_t *tsdn = tsdn_fetch(); 60*7bdf38e5Schristos /* Try triggering allocations from sharded bins. */ 61*7bdf38e5Schristos for (unsigned i = 0; i < 1024; i++) { 62*7bdf38e5Schristos ptr = mallocx(1, MALLOCX_TCACHE_NONE); 63*7bdf38e5Schristos ptr2 = mallocx(129, MALLOCX_TCACHE_NONE); 64*7bdf38e5Schristos 65*7bdf38e5Schristos edata = emap_edata_lookup(tsdn, &arena_emap_global, ptr); 66*7bdf38e5Schristos shard1 = edata_binshard_get(edata); 67*7bdf38e5Schristos dallocx(ptr, 0); 68*7bdf38e5Schristos expect_u_lt(shard1, 16, "Unexpected bin shard used"); 69*7bdf38e5Schristos 70*7bdf38e5Schristos edata = emap_edata_lookup(tsdn, &arena_emap_global, ptr2); 71*7bdf38e5Schristos shard2 = edata_binshard_get(edata); 72*7bdf38e5Schristos dallocx(ptr2, 0); 73*7bdf38e5Schristos expect_u_lt(shard2, 4, "Unexpected bin shard used"); 74*7bdf38e5Schristos 75*7bdf38e5Schristos if (shard1 > 0 || shard2 > 0) { 76*7bdf38e5Schristos /* Triggered sharded bin usage. */ 77*7bdf38e5Schristos return (void *)(uintptr_t)shard1; 78*7bdf38e5Schristos } 79*7bdf38e5Schristos } 80*7bdf38e5Schristos 81*7bdf38e5Schristos return NULL; 82*7bdf38e5Schristos } 83*7bdf38e5Schristos 84*7bdf38e5Schristos TEST_BEGIN(test_bin_shard_mt) { 85*7bdf38e5Schristos test_skip_if(have_percpu_arena && 86*7bdf38e5Schristos PERCPU_ARENA_ENABLED(opt_percpu_arena)); 87*7bdf38e5Schristos 88*7bdf38e5Schristos thd_t thds[NTHREADS]; 89*7bdf38e5Schristos unsigned i; 90*7bdf38e5Schristos for (i = 0; i < NTHREADS; i++) { 91*7bdf38e5Schristos thd_create(&thds[i], thd_start, NULL); 92*7bdf38e5Schristos } 93*7bdf38e5Schristos bool sharded = false; 94*7bdf38e5Schristos for (i = 0; i < NTHREADS; i++) { 95*7bdf38e5Schristos void *ret; 96*7bdf38e5Schristos thd_join(thds[i], &ret); 97*7bdf38e5Schristos if (ret != NULL) { 98*7bdf38e5Schristos sharded = true; 99*7bdf38e5Schristos } 100*7bdf38e5Schristos } 101*7bdf38e5Schristos expect_b_eq(sharded, true, "Did not find sharded bins"); 102*7bdf38e5Schristos } 103*7bdf38e5Schristos TEST_END 104*7bdf38e5Schristos 105*7bdf38e5Schristos TEST_BEGIN(test_bin_shard) { 106*7bdf38e5Schristos unsigned nbins, i; 107*7bdf38e5Schristos size_t mib[4], mib2[4]; 108*7bdf38e5Schristos size_t miblen, miblen2, len; 109*7bdf38e5Schristos 110*7bdf38e5Schristos len = sizeof(nbins); 111*7bdf38e5Schristos expect_d_eq(mallctl("arenas.nbins", (void *)&nbins, &len, NULL, 0), 0, 112*7bdf38e5Schristos "Unexpected mallctl() failure"); 113*7bdf38e5Schristos 114*7bdf38e5Schristos miblen = 4; 115*7bdf38e5Schristos expect_d_eq(mallctlnametomib("arenas.bin.0.nshards", mib, &miblen), 0, 116*7bdf38e5Schristos "Unexpected mallctlnametomib() failure"); 117*7bdf38e5Schristos miblen2 = 4; 118*7bdf38e5Schristos expect_d_eq(mallctlnametomib("arenas.bin.0.size", mib2, &miblen2), 0, 119*7bdf38e5Schristos "Unexpected mallctlnametomib() failure"); 120*7bdf38e5Schristos 121*7bdf38e5Schristos for (i = 0; i < nbins; i++) { 122*7bdf38e5Schristos uint32_t nshards; 123*7bdf38e5Schristos size_t size, sz1, sz2; 124*7bdf38e5Schristos 125*7bdf38e5Schristos mib[2] = i; 126*7bdf38e5Schristos sz1 = sizeof(nshards); 127*7bdf38e5Schristos expect_d_eq(mallctlbymib(mib, miblen, (void *)&nshards, &sz1, 128*7bdf38e5Schristos NULL, 0), 0, "Unexpected mallctlbymib() failure"); 129*7bdf38e5Schristos 130*7bdf38e5Schristos mib2[2] = i; 131*7bdf38e5Schristos sz2 = sizeof(size); 132*7bdf38e5Schristos expect_d_eq(mallctlbymib(mib2, miblen2, (void *)&size, &sz2, 133*7bdf38e5Schristos NULL, 0), 0, "Unexpected mallctlbymib() failure"); 134*7bdf38e5Schristos 135*7bdf38e5Schristos if (size >= 1 && size <= 128) { 136*7bdf38e5Schristos expect_u_eq(nshards, 16, "Unexpected nshards"); 137*7bdf38e5Schristos } else if (size == 256) { 138*7bdf38e5Schristos expect_u_eq(nshards, 8, "Unexpected nshards"); 139*7bdf38e5Schristos } else if (size > 128 && size <= 512) { 140*7bdf38e5Schristos expect_u_eq(nshards, 4, "Unexpected nshards"); 141*7bdf38e5Schristos } else { 142*7bdf38e5Schristos expect_u_eq(nshards, 1, "Unexpected nshards"); 143*7bdf38e5Schristos } 144*7bdf38e5Schristos } 145*7bdf38e5Schristos } 146*7bdf38e5Schristos TEST_END 147*7bdf38e5Schristos 148*7bdf38e5Schristos int 149*7bdf38e5Schristos main(void) { 150*7bdf38e5Schristos return test_no_reentrancy( 151*7bdf38e5Schristos test_bin_shard, 152*7bdf38e5Schristos test_bin_shard_mt, 153*7bdf38e5Schristos test_producer_consumer); 154*7bdf38e5Schristos } 155