1*7bdf38e5Schristos #include "test/jemalloc_test.h" 2*7bdf38e5Schristos 3*7bdf38e5Schristos #include "jemalloc/internal/edata_cache.h" 4*7bdf38e5Schristos 5*7bdf38e5Schristos static void 6*7bdf38e5Schristos test_edata_cache_init(edata_cache_t *edata_cache) { 7*7bdf38e5Schristos base_t *base = base_new(TSDN_NULL, /* ind */ 1, 8*7bdf38e5Schristos &ehooks_default_extent_hooks, /* metadata_use_hooks */ true); 9*7bdf38e5Schristos assert_ptr_not_null(base, ""); 10*7bdf38e5Schristos bool err = edata_cache_init(edata_cache, base); 11*7bdf38e5Schristos assert_false(err, ""); 12*7bdf38e5Schristos } 13*7bdf38e5Schristos 14*7bdf38e5Schristos static void 15*7bdf38e5Schristos test_edata_cache_destroy(edata_cache_t *edata_cache) { 16*7bdf38e5Schristos base_delete(TSDN_NULL, edata_cache->base); 17*7bdf38e5Schristos } 18*7bdf38e5Schristos 19*7bdf38e5Schristos TEST_BEGIN(test_edata_cache) { 20*7bdf38e5Schristos edata_cache_t ec; 21*7bdf38e5Schristos test_edata_cache_init(&ec); 22*7bdf38e5Schristos 23*7bdf38e5Schristos /* Get one */ 24*7bdf38e5Schristos edata_t *ed1 = edata_cache_get(TSDN_NULL, &ec); 25*7bdf38e5Schristos assert_ptr_not_null(ed1, ""); 26*7bdf38e5Schristos 27*7bdf38e5Schristos /* Cache should be empty */ 28*7bdf38e5Schristos assert_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, ""); 29*7bdf38e5Schristos 30*7bdf38e5Schristos /* Get another */ 31*7bdf38e5Schristos edata_t *ed2 = edata_cache_get(TSDN_NULL, &ec); 32*7bdf38e5Schristos assert_ptr_not_null(ed2, ""); 33*7bdf38e5Schristos 34*7bdf38e5Schristos /* Still empty */ 35*7bdf38e5Schristos assert_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, ""); 36*7bdf38e5Schristos 37*7bdf38e5Schristos /* Put one back, and the cache should now have one item */ 38*7bdf38e5Schristos edata_cache_put(TSDN_NULL, &ec, ed1); 39*7bdf38e5Schristos assert_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 1, ""); 40*7bdf38e5Schristos 41*7bdf38e5Schristos /* Reallocating should reuse the item, and leave an empty cache. */ 42*7bdf38e5Schristos edata_t *ed1_again = edata_cache_get(TSDN_NULL, &ec); 43*7bdf38e5Schristos assert_ptr_eq(ed1, ed1_again, ""); 44*7bdf38e5Schristos assert_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, ""); 45*7bdf38e5Schristos 46*7bdf38e5Schristos test_edata_cache_destroy(&ec); 47*7bdf38e5Schristos } 48*7bdf38e5Schristos TEST_END 49*7bdf38e5Schristos 50*7bdf38e5Schristos static size_t 51*7bdf38e5Schristos ecf_count(edata_cache_fast_t *ecf) { 52*7bdf38e5Schristos size_t count = 0; 53*7bdf38e5Schristos edata_t *cur; 54*7bdf38e5Schristos ql_foreach(cur, &ecf->list.head, ql_link_inactive) { 55*7bdf38e5Schristos count++; 56*7bdf38e5Schristos } 57*7bdf38e5Schristos return count; 58*7bdf38e5Schristos } 59*7bdf38e5Schristos 60*7bdf38e5Schristos TEST_BEGIN(test_edata_cache_fast_simple) { 61*7bdf38e5Schristos edata_cache_t ec; 62*7bdf38e5Schristos edata_cache_fast_t ecf; 63*7bdf38e5Schristos 64*7bdf38e5Schristos test_edata_cache_init(&ec); 65*7bdf38e5Schristos edata_cache_fast_init(&ecf, &ec); 66*7bdf38e5Schristos 67*7bdf38e5Schristos edata_t *ed1 = edata_cache_fast_get(TSDN_NULL, &ecf); 68*7bdf38e5Schristos expect_ptr_not_null(ed1, ""); 69*7bdf38e5Schristos expect_zu_eq(ecf_count(&ecf), 0, ""); 70*7bdf38e5Schristos expect_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, ""); 71*7bdf38e5Schristos 72*7bdf38e5Schristos edata_t *ed2 = edata_cache_fast_get(TSDN_NULL, &ecf); 73*7bdf38e5Schristos expect_ptr_not_null(ed2, ""); 74*7bdf38e5Schristos expect_zu_eq(ecf_count(&ecf), 0, ""); 75*7bdf38e5Schristos expect_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, ""); 76*7bdf38e5Schristos 77*7bdf38e5Schristos edata_cache_fast_put(TSDN_NULL, &ecf, ed1); 78*7bdf38e5Schristos expect_zu_eq(ecf_count(&ecf), 1, ""); 79*7bdf38e5Schristos expect_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, ""); 80*7bdf38e5Schristos 81*7bdf38e5Schristos edata_cache_fast_put(TSDN_NULL, &ecf, ed2); 82*7bdf38e5Schristos expect_zu_eq(ecf_count(&ecf), 2, ""); 83*7bdf38e5Schristos expect_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, ""); 84*7bdf38e5Schristos 85*7bdf38e5Schristos /* LIFO ordering. */ 86*7bdf38e5Schristos expect_ptr_eq(ed2, edata_cache_fast_get(TSDN_NULL, &ecf), ""); 87*7bdf38e5Schristos expect_zu_eq(ecf_count(&ecf), 1, ""); 88*7bdf38e5Schristos expect_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, ""); 89*7bdf38e5Schristos 90*7bdf38e5Schristos expect_ptr_eq(ed1, edata_cache_fast_get(TSDN_NULL, &ecf), ""); 91*7bdf38e5Schristos expect_zu_eq(ecf_count(&ecf), 0, ""); 92*7bdf38e5Schristos expect_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, ""); 93*7bdf38e5Schristos 94*7bdf38e5Schristos test_edata_cache_destroy(&ec); 95*7bdf38e5Schristos } 96*7bdf38e5Schristos TEST_END 97*7bdf38e5Schristos 98*7bdf38e5Schristos TEST_BEGIN(test_edata_cache_fill) { 99*7bdf38e5Schristos edata_cache_t ec; 100*7bdf38e5Schristos edata_cache_fast_t ecf; 101*7bdf38e5Schristos 102*7bdf38e5Schristos test_edata_cache_init(&ec); 103*7bdf38e5Schristos edata_cache_fast_init(&ecf, &ec); 104*7bdf38e5Schristos 105*7bdf38e5Schristos edata_t *allocs[EDATA_CACHE_FAST_FILL * 2]; 106*7bdf38e5Schristos 107*7bdf38e5Schristos /* 108*7bdf38e5Schristos * If the fallback cache can't satisfy the request, we shouldn't do 109*7bdf38e5Schristos * extra allocations until compelled to. Put half the fill goal in the 110*7bdf38e5Schristos * fallback. 111*7bdf38e5Schristos */ 112*7bdf38e5Schristos for (int i = 0; i < EDATA_CACHE_FAST_FILL / 2; i++) { 113*7bdf38e5Schristos allocs[i] = edata_cache_get(TSDN_NULL, &ec); 114*7bdf38e5Schristos } 115*7bdf38e5Schristos for (int i = 0; i < EDATA_CACHE_FAST_FILL / 2; i++) { 116*7bdf38e5Schristos edata_cache_put(TSDN_NULL, &ec, allocs[i]); 117*7bdf38e5Schristos } 118*7bdf38e5Schristos expect_zu_eq(EDATA_CACHE_FAST_FILL / 2, 119*7bdf38e5Schristos atomic_load_zu(&ec.count, ATOMIC_RELAXED), ""); 120*7bdf38e5Schristos 121*7bdf38e5Schristos allocs[0] = edata_cache_fast_get(TSDN_NULL, &ecf); 122*7bdf38e5Schristos expect_zu_eq(EDATA_CACHE_FAST_FILL / 2 - 1, ecf_count(&ecf), 123*7bdf38e5Schristos "Should have grabbed all edatas available but no more."); 124*7bdf38e5Schristos 125*7bdf38e5Schristos for (int i = 1; i < EDATA_CACHE_FAST_FILL / 2; i++) { 126*7bdf38e5Schristos allocs[i] = edata_cache_fast_get(TSDN_NULL, &ecf); 127*7bdf38e5Schristos expect_ptr_not_null(allocs[i], ""); 128*7bdf38e5Schristos } 129*7bdf38e5Schristos expect_zu_eq(0, ecf_count(&ecf), ""); 130*7bdf38e5Schristos 131*7bdf38e5Schristos /* When forced, we should alloc from the base. */ 132*7bdf38e5Schristos edata_t *edata = edata_cache_fast_get(TSDN_NULL, &ecf); 133*7bdf38e5Schristos expect_ptr_not_null(edata, ""); 134*7bdf38e5Schristos expect_zu_eq(0, ecf_count(&ecf), "Allocated more than necessary"); 135*7bdf38e5Schristos expect_zu_eq(0, atomic_load_zu(&ec.count, ATOMIC_RELAXED), 136*7bdf38e5Schristos "Allocated more than necessary"); 137*7bdf38e5Schristos 138*7bdf38e5Schristos /* 139*7bdf38e5Schristos * We should correctly fill in the common case where the fallback isn't 140*7bdf38e5Schristos * exhausted, too. 141*7bdf38e5Schristos */ 142*7bdf38e5Schristos for (int i = 0; i < EDATA_CACHE_FAST_FILL * 2; i++) { 143*7bdf38e5Schristos allocs[i] = edata_cache_get(TSDN_NULL, &ec); 144*7bdf38e5Schristos expect_ptr_not_null(allocs[i], ""); 145*7bdf38e5Schristos } 146*7bdf38e5Schristos for (int i = 0; i < EDATA_CACHE_FAST_FILL * 2; i++) { 147*7bdf38e5Schristos edata_cache_put(TSDN_NULL, &ec, allocs[i]); 148*7bdf38e5Schristos } 149*7bdf38e5Schristos 150*7bdf38e5Schristos allocs[0] = edata_cache_fast_get(TSDN_NULL, &ecf); 151*7bdf38e5Schristos expect_zu_eq(EDATA_CACHE_FAST_FILL - 1, ecf_count(&ecf), ""); 152*7bdf38e5Schristos expect_zu_eq(EDATA_CACHE_FAST_FILL, 153*7bdf38e5Schristos atomic_load_zu(&ec.count, ATOMIC_RELAXED), ""); 154*7bdf38e5Schristos for (int i = 1; i < EDATA_CACHE_FAST_FILL; i++) { 155*7bdf38e5Schristos expect_zu_eq(EDATA_CACHE_FAST_FILL - i, ecf_count(&ecf), ""); 156*7bdf38e5Schristos expect_zu_eq(EDATA_CACHE_FAST_FILL, 157*7bdf38e5Schristos atomic_load_zu(&ec.count, ATOMIC_RELAXED), ""); 158*7bdf38e5Schristos allocs[i] = edata_cache_fast_get(TSDN_NULL, &ecf); 159*7bdf38e5Schristos expect_ptr_not_null(allocs[i], ""); 160*7bdf38e5Schristos } 161*7bdf38e5Schristos expect_zu_eq(0, ecf_count(&ecf), ""); 162*7bdf38e5Schristos expect_zu_eq(EDATA_CACHE_FAST_FILL, 163*7bdf38e5Schristos atomic_load_zu(&ec.count, ATOMIC_RELAXED), ""); 164*7bdf38e5Schristos 165*7bdf38e5Schristos allocs[0] = edata_cache_fast_get(TSDN_NULL, &ecf); 166*7bdf38e5Schristos expect_zu_eq(EDATA_CACHE_FAST_FILL - 1, ecf_count(&ecf), ""); 167*7bdf38e5Schristos expect_zu_eq(0, atomic_load_zu(&ec.count, ATOMIC_RELAXED), ""); 168*7bdf38e5Schristos for (int i = 1; i < EDATA_CACHE_FAST_FILL; i++) { 169*7bdf38e5Schristos expect_zu_eq(EDATA_CACHE_FAST_FILL - i, ecf_count(&ecf), ""); 170*7bdf38e5Schristos expect_zu_eq(0, atomic_load_zu(&ec.count, ATOMIC_RELAXED), ""); 171*7bdf38e5Schristos allocs[i] = edata_cache_fast_get(TSDN_NULL, &ecf); 172*7bdf38e5Schristos expect_ptr_not_null(allocs[i], ""); 173*7bdf38e5Schristos } 174*7bdf38e5Schristos expect_zu_eq(0, ecf_count(&ecf), ""); 175*7bdf38e5Schristos expect_zu_eq(0, atomic_load_zu(&ec.count, ATOMIC_RELAXED), ""); 176*7bdf38e5Schristos 177*7bdf38e5Schristos test_edata_cache_destroy(&ec); 178*7bdf38e5Schristos } 179*7bdf38e5Schristos TEST_END 180*7bdf38e5Schristos 181*7bdf38e5Schristos TEST_BEGIN(test_edata_cache_disable) { 182*7bdf38e5Schristos edata_cache_t ec; 183*7bdf38e5Schristos edata_cache_fast_t ecf; 184*7bdf38e5Schristos 185*7bdf38e5Schristos test_edata_cache_init(&ec); 186*7bdf38e5Schristos edata_cache_fast_init(&ecf, &ec); 187*7bdf38e5Schristos 188*7bdf38e5Schristos for (int i = 0; i < EDATA_CACHE_FAST_FILL; i++) { 189*7bdf38e5Schristos edata_t *edata = edata_cache_get(TSDN_NULL, &ec); 190*7bdf38e5Schristos expect_ptr_not_null(edata, ""); 191*7bdf38e5Schristos edata_cache_fast_put(TSDN_NULL, &ecf, edata); 192*7bdf38e5Schristos } 193*7bdf38e5Schristos 194*7bdf38e5Schristos expect_zu_eq(EDATA_CACHE_FAST_FILL, ecf_count(&ecf), ""); 195*7bdf38e5Schristos expect_zu_eq(0, atomic_load_zu(&ec.count, ATOMIC_RELAXED), ""); 196*7bdf38e5Schristos 197*7bdf38e5Schristos edata_cache_fast_disable(TSDN_NULL, &ecf); 198*7bdf38e5Schristos 199*7bdf38e5Schristos expect_zu_eq(0, ecf_count(&ecf), ""); 200*7bdf38e5Schristos expect_zu_eq(EDATA_CACHE_FAST_FILL, 201*7bdf38e5Schristos atomic_load_zu(&ec.count, ATOMIC_RELAXED), "Disabling should flush"); 202*7bdf38e5Schristos 203*7bdf38e5Schristos edata_t *edata = edata_cache_fast_get(TSDN_NULL, &ecf); 204*7bdf38e5Schristos expect_zu_eq(0, ecf_count(&ecf), ""); 205*7bdf38e5Schristos expect_zu_eq(EDATA_CACHE_FAST_FILL - 1, 206*7bdf38e5Schristos atomic_load_zu(&ec.count, ATOMIC_RELAXED), 207*7bdf38e5Schristos "Disabled ecf should forward on get"); 208*7bdf38e5Schristos 209*7bdf38e5Schristos edata_cache_fast_put(TSDN_NULL, &ecf, edata); 210*7bdf38e5Schristos expect_zu_eq(0, ecf_count(&ecf), ""); 211*7bdf38e5Schristos expect_zu_eq(EDATA_CACHE_FAST_FILL, 212*7bdf38e5Schristos atomic_load_zu(&ec.count, ATOMIC_RELAXED), 213*7bdf38e5Schristos "Disabled ecf should forward on put"); 214*7bdf38e5Schristos 215*7bdf38e5Schristos test_edata_cache_destroy(&ec); 216*7bdf38e5Schristos } 217*7bdf38e5Schristos TEST_END 218*7bdf38e5Schristos 219*7bdf38e5Schristos int 220*7bdf38e5Schristos main(void) { 221*7bdf38e5Schristos return test( 222*7bdf38e5Schristos test_edata_cache, 223*7bdf38e5Schristos test_edata_cache_fast_simple, 224*7bdf38e5Schristos test_edata_cache_fill, 225*7bdf38e5Schristos test_edata_cache_disable); 226*7bdf38e5Schristos } 227