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