123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227 |
- #include "test/jemalloc_test.h"
- #include "jemalloc/internal/edata_cache.h"
- static void
- test_edata_cache_init(edata_cache_t *edata_cache) {
- base_t *base = base_new(TSDN_NULL, /* ind */ 1,
- &ehooks_default_extent_hooks, /* metadata_use_hooks */ true);
- assert_ptr_not_null(base, "");
- bool err = edata_cache_init(edata_cache, base);
- assert_false(err, "");
- }
- static void
- test_edata_cache_destroy(edata_cache_t *edata_cache) {
- base_delete(TSDN_NULL, edata_cache->base);
- }
- TEST_BEGIN(test_edata_cache) {
- edata_cache_t ec;
- test_edata_cache_init(&ec);
- /* Get one */
- edata_t *ed1 = edata_cache_get(TSDN_NULL, &ec);
- assert_ptr_not_null(ed1, "");
- /* Cache should be empty */
- assert_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
- /* Get another */
- edata_t *ed2 = edata_cache_get(TSDN_NULL, &ec);
- assert_ptr_not_null(ed2, "");
- /* Still empty */
- assert_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
- /* Put one back, and the cache should now have one item */
- edata_cache_put(TSDN_NULL, &ec, ed1);
- assert_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 1, "");
- /* Reallocating should reuse the item, and leave an empty cache. */
- edata_t *ed1_again = edata_cache_get(TSDN_NULL, &ec);
- assert_ptr_eq(ed1, ed1_again, "");
- assert_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
- test_edata_cache_destroy(&ec);
- }
- TEST_END
- static size_t
- ecf_count(edata_cache_fast_t *ecf) {
- size_t count = 0;
- edata_t *cur;
- ql_foreach(cur, &ecf->list.head, ql_link_inactive) {
- count++;
- }
- return count;
- }
- TEST_BEGIN(test_edata_cache_fast_simple) {
- edata_cache_t ec;
- edata_cache_fast_t ecf;
- test_edata_cache_init(&ec);
- edata_cache_fast_init(&ecf, &ec);
- edata_t *ed1 = edata_cache_fast_get(TSDN_NULL, &ecf);
- expect_ptr_not_null(ed1, "");
- expect_zu_eq(ecf_count(&ecf), 0, "");
- expect_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
- edata_t *ed2 = edata_cache_fast_get(TSDN_NULL, &ecf);
- expect_ptr_not_null(ed2, "");
- expect_zu_eq(ecf_count(&ecf), 0, "");
- expect_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
- edata_cache_fast_put(TSDN_NULL, &ecf, ed1);
- expect_zu_eq(ecf_count(&ecf), 1, "");
- expect_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
- edata_cache_fast_put(TSDN_NULL, &ecf, ed2);
- expect_zu_eq(ecf_count(&ecf), 2, "");
- expect_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
- /* LIFO ordering. */
- expect_ptr_eq(ed2, edata_cache_fast_get(TSDN_NULL, &ecf), "");
- expect_zu_eq(ecf_count(&ecf), 1, "");
- expect_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
- expect_ptr_eq(ed1, edata_cache_fast_get(TSDN_NULL, &ecf), "");
- expect_zu_eq(ecf_count(&ecf), 0, "");
- expect_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
- test_edata_cache_destroy(&ec);
- }
- TEST_END
- TEST_BEGIN(test_edata_cache_fill) {
- edata_cache_t ec;
- edata_cache_fast_t ecf;
- test_edata_cache_init(&ec);
- edata_cache_fast_init(&ecf, &ec);
- edata_t *allocs[EDATA_CACHE_FAST_FILL * 2];
- /*
- * If the fallback cache can't satisfy the request, we shouldn't do
- * extra allocations until compelled to. Put half the fill goal in the
- * fallback.
- */
- for (int i = 0; i < EDATA_CACHE_FAST_FILL / 2; i++) {
- allocs[i] = edata_cache_get(TSDN_NULL, &ec);
- }
- for (int i = 0; i < EDATA_CACHE_FAST_FILL / 2; i++) {
- edata_cache_put(TSDN_NULL, &ec, allocs[i]);
- }
- expect_zu_eq(EDATA_CACHE_FAST_FILL / 2,
- atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
- allocs[0] = edata_cache_fast_get(TSDN_NULL, &ecf);
- expect_zu_eq(EDATA_CACHE_FAST_FILL / 2 - 1, ecf_count(&ecf),
- "Should have grabbed all edatas available but no more.");
- for (int i = 1; i < EDATA_CACHE_FAST_FILL / 2; i++) {
- allocs[i] = edata_cache_fast_get(TSDN_NULL, &ecf);
- expect_ptr_not_null(allocs[i], "");
- }
- expect_zu_eq(0, ecf_count(&ecf), "");
- /* When forced, we should alloc from the base. */
- edata_t *edata = edata_cache_fast_get(TSDN_NULL, &ecf);
- expect_ptr_not_null(edata, "");
- expect_zu_eq(0, ecf_count(&ecf), "Allocated more than necessary");
- expect_zu_eq(0, atomic_load_zu(&ec.count, ATOMIC_RELAXED),
- "Allocated more than necessary");
- /*
- * We should correctly fill in the common case where the fallback isn't
- * exhausted, too.
- */
- for (int i = 0; i < EDATA_CACHE_FAST_FILL * 2; i++) {
- allocs[i] = edata_cache_get(TSDN_NULL, &ec);
- expect_ptr_not_null(allocs[i], "");
- }
- for (int i = 0; i < EDATA_CACHE_FAST_FILL * 2; i++) {
- edata_cache_put(TSDN_NULL, &ec, allocs[i]);
- }
- allocs[0] = edata_cache_fast_get(TSDN_NULL, &ecf);
- expect_zu_eq(EDATA_CACHE_FAST_FILL - 1, ecf_count(&ecf), "");
- expect_zu_eq(EDATA_CACHE_FAST_FILL,
- atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
- for (int i = 1; i < EDATA_CACHE_FAST_FILL; i++) {
- expect_zu_eq(EDATA_CACHE_FAST_FILL - i, ecf_count(&ecf), "");
- expect_zu_eq(EDATA_CACHE_FAST_FILL,
- atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
- allocs[i] = edata_cache_fast_get(TSDN_NULL, &ecf);
- expect_ptr_not_null(allocs[i], "");
- }
- expect_zu_eq(0, ecf_count(&ecf), "");
- expect_zu_eq(EDATA_CACHE_FAST_FILL,
- atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
- allocs[0] = edata_cache_fast_get(TSDN_NULL, &ecf);
- expect_zu_eq(EDATA_CACHE_FAST_FILL - 1, ecf_count(&ecf), "");
- expect_zu_eq(0, atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
- for (int i = 1; i < EDATA_CACHE_FAST_FILL; i++) {
- expect_zu_eq(EDATA_CACHE_FAST_FILL - i, ecf_count(&ecf), "");
- expect_zu_eq(0, atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
- allocs[i] = edata_cache_fast_get(TSDN_NULL, &ecf);
- expect_ptr_not_null(allocs[i], "");
- }
- expect_zu_eq(0, ecf_count(&ecf), "");
- expect_zu_eq(0, atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
- test_edata_cache_destroy(&ec);
- }
- TEST_END
- TEST_BEGIN(test_edata_cache_disable) {
- edata_cache_t ec;
- edata_cache_fast_t ecf;
- test_edata_cache_init(&ec);
- edata_cache_fast_init(&ecf, &ec);
- for (int i = 0; i < EDATA_CACHE_FAST_FILL; i++) {
- edata_t *edata = edata_cache_get(TSDN_NULL, &ec);
- expect_ptr_not_null(edata, "");
- edata_cache_fast_put(TSDN_NULL, &ecf, edata);
- }
- expect_zu_eq(EDATA_CACHE_FAST_FILL, ecf_count(&ecf), "");
- expect_zu_eq(0, atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
- edata_cache_fast_disable(TSDN_NULL, &ecf);
- expect_zu_eq(0, ecf_count(&ecf), "");
- expect_zu_eq(EDATA_CACHE_FAST_FILL,
- atomic_load_zu(&ec.count, ATOMIC_RELAXED), "Disabling should flush");
- edata_t *edata = edata_cache_fast_get(TSDN_NULL, &ecf);
- expect_zu_eq(0, ecf_count(&ecf), "");
- expect_zu_eq(EDATA_CACHE_FAST_FILL - 1,
- atomic_load_zu(&ec.count, ATOMIC_RELAXED),
- "Disabled ecf should forward on get");
- edata_cache_fast_put(TSDN_NULL, &ecf, edata);
- expect_zu_eq(0, ecf_count(&ecf), "");
- expect_zu_eq(EDATA_CACHE_FAST_FILL,
- atomic_load_zu(&ec.count, ATOMIC_RELAXED),
- "Disabled ecf should forward on put");
- test_edata_cache_destroy(&ec);
- }
- TEST_END
- int
- main(void) {
- return test(
- test_edata_cache,
- test_edata_cache_fast_simple,
- test_edata_cache_fill,
- test_edata_cache_disable);
- }
|