123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635 |
- #include "test/jemalloc_test.h"
- #include "jemalloc/internal/sec.h"
- typedef struct pai_test_allocator_s pai_test_allocator_t;
- struct pai_test_allocator_s {
- pai_t pai;
- bool alloc_fail;
- size_t alloc_count;
- size_t alloc_batch_count;
- size_t dalloc_count;
- size_t dalloc_batch_count;
- /*
- * We use a simple bump allocator as the implementation. This isn't
- * *really* correct, since we may allow expansion into a subsequent
- * allocation, but it's not like the SEC is really examining the
- * pointers it gets back; this is mostly just helpful for debugging.
- */
- uintptr_t next_ptr;
- size_t expand_count;
- bool expand_return_value;
- size_t shrink_count;
- bool shrink_return_value;
- };
- static void
- test_sec_init(sec_t *sec, pai_t *fallback, size_t nshards, size_t max_alloc,
- size_t max_bytes) {
- sec_opts_t opts;
- opts.nshards = 1;
- opts.max_alloc = max_alloc;
- opts.max_bytes = max_bytes;
- /*
- * Just choose reasonable defaults for these; most tests don't care so
- * long as they're something reasonable.
- */
- opts.bytes_after_flush = max_bytes / 2;
- opts.batch_fill_extra = 4;
- /*
- * We end up leaking this base, but that's fine; this test is
- * short-running, and SECs are arena-scoped in reality.
- */
- base_t *base = base_new(TSDN_NULL, /* ind */ 123,
- &ehooks_default_extent_hooks, /* metadata_use_hooks */ true);
- bool err = sec_init(TSDN_NULL, sec, base, fallback, &opts);
- assert_false(err, "Unexpected initialization failure");
- assert_u_ge(sec->npsizes, 0, "Zero size classes allowed for caching");
- }
- static inline edata_t *
- pai_test_allocator_alloc(tsdn_t *tsdn, pai_t *self, size_t size,
- size_t alignment, bool zero, bool guarded, bool frequent_reuse,
- bool *deferred_work_generated) {
- assert(!guarded);
- pai_test_allocator_t *ta = (pai_test_allocator_t *)self;
- if (ta->alloc_fail) {
- return NULL;
- }
- edata_t *edata = malloc(sizeof(edata_t));
- assert_ptr_not_null(edata, "");
- ta->next_ptr += alignment - 1;
- edata_init(edata, /* arena_ind */ 0,
- (void *)(ta->next_ptr & ~(alignment - 1)), size,
- /* slab */ false,
- /* szind */ 0, /* sn */ 1, extent_state_active, /* zero */ zero,
- /* comitted */ true, /* ranged */ false, EXTENT_NOT_HEAD);
- ta->next_ptr += size;
- ta->alloc_count++;
- return edata;
- }
- static inline size_t
- pai_test_allocator_alloc_batch(tsdn_t *tsdn, pai_t *self, size_t size,
- size_t nallocs, edata_list_active_t *results,
- bool *deferred_work_generated) {
- pai_test_allocator_t *ta = (pai_test_allocator_t *)self;
- if (ta->alloc_fail) {
- return 0;
- }
- for (size_t i = 0; i < nallocs; i++) {
- edata_t *edata = malloc(sizeof(edata_t));
- assert_ptr_not_null(edata, "");
- edata_init(edata, /* arena_ind */ 0,
- (void *)ta->next_ptr, size,
- /* slab */ false, /* szind */ 0, /* sn */ 1,
- extent_state_active, /* zero */ false, /* comitted */ true,
- /* ranged */ false, EXTENT_NOT_HEAD);
- ta->next_ptr += size;
- ta->alloc_batch_count++;
- edata_list_active_append(results, edata);
- }
- return nallocs;
- }
- static bool
- pai_test_allocator_expand(tsdn_t *tsdn, pai_t *self, edata_t *edata,
- size_t old_size, size_t new_size, bool zero,
- bool *deferred_work_generated) {
- pai_test_allocator_t *ta = (pai_test_allocator_t *)self;
- ta->expand_count++;
- return ta->expand_return_value;
- }
- static bool
- pai_test_allocator_shrink(tsdn_t *tsdn, pai_t *self, edata_t *edata,
- size_t old_size, size_t new_size, bool *deferred_work_generated) {
- pai_test_allocator_t *ta = (pai_test_allocator_t *)self;
- ta->shrink_count++;
- return ta->shrink_return_value;
- }
- static void
- pai_test_allocator_dalloc(tsdn_t *tsdn, pai_t *self, edata_t *edata,
- bool *deferred_work_generated) {
- pai_test_allocator_t *ta = (pai_test_allocator_t *)self;
- ta->dalloc_count++;
- free(edata);
- }
- static void
- pai_test_allocator_dalloc_batch(tsdn_t *tsdn, pai_t *self,
- edata_list_active_t *list, bool *deferred_work_generated) {
- pai_test_allocator_t *ta = (pai_test_allocator_t *)self;
- edata_t *edata;
- while ((edata = edata_list_active_first(list)) != NULL) {
- edata_list_active_remove(list, edata);
- ta->dalloc_batch_count++;
- free(edata);
- }
- }
- static inline void
- pai_test_allocator_init(pai_test_allocator_t *ta) {
- ta->alloc_fail = false;
- ta->alloc_count = 0;
- ta->alloc_batch_count = 0;
- ta->dalloc_count = 0;
- ta->dalloc_batch_count = 0;
- /* Just don't start the edata at 0. */
- ta->next_ptr = 10 * PAGE;
- ta->expand_count = 0;
- ta->expand_return_value = false;
- ta->shrink_count = 0;
- ta->shrink_return_value = false;
- ta->pai.alloc = &pai_test_allocator_alloc;
- ta->pai.alloc_batch = &pai_test_allocator_alloc_batch;
- ta->pai.expand = &pai_test_allocator_expand;
- ta->pai.shrink = &pai_test_allocator_shrink;
- ta->pai.dalloc = &pai_test_allocator_dalloc;
- ta->pai.dalloc_batch = &pai_test_allocator_dalloc_batch;
- }
- TEST_BEGIN(test_reuse) {
- pai_test_allocator_t ta;
- pai_test_allocator_init(&ta);
- sec_t sec;
- /*
- * We can't use the "real" tsd, since we malloc within the test
- * allocator hooks; we'd get lock inversion crashes. Eventually, we
- * should have a way to mock tsds, but for now just don't do any
- * lock-order checking.
- */
- tsdn_t *tsdn = TSDN_NULL;
- /*
- * 11 allocs apiece of 1-PAGE and 2-PAGE objects means that we should be
- * able to get to 33 pages in the cache before triggering a flush. We
- * set the flush liimt to twice this amount, to avoid accidentally
- * triggering a flush caused by the batch-allocation down the cache fill
- * pathway disrupting ordering.
- */
- enum { NALLOCS = 11 };
- edata_t *one_page[NALLOCS];
- edata_t *two_page[NALLOCS];
- bool deferred_work_generated = false;
- test_sec_init(&sec, &ta.pai, /* nshards */ 1, /* max_alloc */ 2 * PAGE,
- /* max_bytes */ 2 * (NALLOCS * PAGE + NALLOCS * 2 * PAGE));
- for (int i = 0; i < NALLOCS; i++) {
- one_page[i] = pai_alloc(tsdn, &sec.pai, PAGE, PAGE,
- /* zero */ false, /* guarded */ false, /* frequent_reuse */
- false, &deferred_work_generated);
- expect_ptr_not_null(one_page[i], "Unexpected alloc failure");
- two_page[i] = pai_alloc(tsdn, &sec.pai, 2 * PAGE, PAGE,
- /* zero */ false, /* guarded */ false, /* frequent_reuse */
- false, &deferred_work_generated);
- expect_ptr_not_null(one_page[i], "Unexpected alloc failure");
- }
- expect_zu_eq(0, ta.alloc_count, "Should be using batch allocs");
- size_t max_allocs = ta.alloc_count + ta.alloc_batch_count;
- expect_zu_le(2 * NALLOCS, max_allocs,
- "Incorrect number of allocations");
- expect_zu_eq(0, ta.dalloc_count,
- "Incorrect number of allocations");
- /*
- * Free in a different order than we allocated, to make sure free-list
- * separation works correctly.
- */
- for (int i = NALLOCS - 1; i >= 0; i--) {
- pai_dalloc(tsdn, &sec.pai, one_page[i],
- &deferred_work_generated);
- }
- for (int i = NALLOCS - 1; i >= 0; i--) {
- pai_dalloc(tsdn, &sec.pai, two_page[i],
- &deferred_work_generated);
- }
- expect_zu_eq(max_allocs, ta.alloc_count + ta.alloc_batch_count,
- "Incorrect number of allocations");
- expect_zu_eq(0, ta.dalloc_count,
- "Incorrect number of allocations");
- /*
- * Check that the n'th most recent deallocated extent is returned for
- * the n'th alloc request of a given size.
- */
- for (int i = 0; i < NALLOCS; i++) {
- edata_t *alloc1 = pai_alloc(tsdn, &sec.pai, PAGE, PAGE,
- /* zero */ false, /* guarded */ false, /* frequent_reuse */
- false, &deferred_work_generated);
- edata_t *alloc2 = pai_alloc(tsdn, &sec.pai, 2 * PAGE, PAGE,
- /* zero */ false, /* guarded */ false, /* frequent_reuse */
- false, &deferred_work_generated);
- expect_ptr_eq(one_page[i], alloc1,
- "Got unexpected allocation");
- expect_ptr_eq(two_page[i], alloc2,
- "Got unexpected allocation");
- }
- expect_zu_eq(max_allocs, ta.alloc_count + ta.alloc_batch_count,
- "Incorrect number of allocations");
- expect_zu_eq(0, ta.dalloc_count,
- "Incorrect number of allocations");
- }
- TEST_END
- TEST_BEGIN(test_auto_flush) {
- pai_test_allocator_t ta;
- pai_test_allocator_init(&ta);
- sec_t sec;
- /* See the note above -- we can't use the real tsd. */
- tsdn_t *tsdn = TSDN_NULL;
- /*
- * 10-allocs apiece of 1-PAGE and 2-PAGE objects means that we should be
- * able to get to 30 pages in the cache before triggering a flush. The
- * choice of NALLOCS here is chosen to match the batch allocation
- * default (4 extra + 1 == 5; so 10 allocations leaves the cache exactly
- * empty, even in the presence of batch allocation on fill).
- * Eventually, once our allocation batching strategies become smarter,
- * this should change.
- */
- enum { NALLOCS = 10 };
- edata_t *extra_alloc;
- edata_t *allocs[NALLOCS];
- bool deferred_work_generated = false;
- test_sec_init(&sec, &ta.pai, /* nshards */ 1, /* max_alloc */ PAGE,
- /* max_bytes */ NALLOCS * PAGE);
- for (int i = 0; i < NALLOCS; i++) {
- allocs[i] = pai_alloc(tsdn, &sec.pai, PAGE, PAGE,
- /* zero */ false, /* guarded */ false, /* frequent_reuse */
- false, &deferred_work_generated);
- expect_ptr_not_null(allocs[i], "Unexpected alloc failure");
- }
- extra_alloc = pai_alloc(tsdn, &sec.pai, PAGE, PAGE, /* zero */ false,
- /* guarded */ false, /* frequent_reuse */ false,
- &deferred_work_generated);
- expect_ptr_not_null(extra_alloc, "Unexpected alloc failure");
- size_t max_allocs = ta.alloc_count + ta.alloc_batch_count;
- expect_zu_le(NALLOCS + 1, max_allocs,
- "Incorrect number of allocations");
- expect_zu_eq(0, ta.dalloc_count,
- "Incorrect number of allocations");
- /* Free until the SEC is full, but should not have flushed yet. */
- for (int i = 0; i < NALLOCS; i++) {
- pai_dalloc(tsdn, &sec.pai, allocs[i], &deferred_work_generated);
- }
- expect_zu_le(NALLOCS + 1, max_allocs,
- "Incorrect number of allocations");
- expect_zu_eq(0, ta.dalloc_count,
- "Incorrect number of allocations");
- /*
- * Free the extra allocation; this should trigger a flush. The internal
- * flushing logic is allowed to get complicated; for now, we rely on our
- * whitebox knowledge of the fact that the SEC flushes bins in their
- * entirety when it decides to do so, and it has only one bin active
- * right now.
- */
- pai_dalloc(tsdn, &sec.pai, extra_alloc, &deferred_work_generated);
- expect_zu_eq(max_allocs, ta.alloc_count + ta.alloc_batch_count,
- "Incorrect number of allocations");
- expect_zu_eq(0, ta.dalloc_count,
- "Incorrect number of (non-batch) deallocations");
- expect_zu_eq(NALLOCS + 1, ta.dalloc_batch_count,
- "Incorrect number of batch deallocations");
- }
- TEST_END
- /*
- * A disable and a flush are *almost* equivalent; the only difference is what
- * happens afterwards; disabling disallows all future caching as well.
- */
- static void
- do_disable_flush_test(bool is_disable) {
- pai_test_allocator_t ta;
- pai_test_allocator_init(&ta);
- sec_t sec;
- /* See the note above -- we can't use the real tsd. */
- tsdn_t *tsdn = TSDN_NULL;
- enum { NALLOCS = 11 };
- edata_t *allocs[NALLOCS];
- bool deferred_work_generated = false;
- test_sec_init(&sec, &ta.pai, /* nshards */ 1, /* max_alloc */ PAGE,
- /* max_bytes */ NALLOCS * PAGE);
- for (int i = 0; i < NALLOCS; i++) {
- allocs[i] = pai_alloc(tsdn, &sec.pai, PAGE, PAGE,
- /* zero */ false, /* guarded */ false, /* frequent_reuse */
- false, &deferred_work_generated);
- expect_ptr_not_null(allocs[i], "Unexpected alloc failure");
- }
- /* Free all but the last aloc. */
- for (int i = 0; i < NALLOCS - 1; i++) {
- pai_dalloc(tsdn, &sec.pai, allocs[i], &deferred_work_generated);
- }
- size_t max_allocs = ta.alloc_count + ta.alloc_batch_count;
- expect_zu_le(NALLOCS, max_allocs, "Incorrect number of allocations");
- expect_zu_eq(0, ta.dalloc_count,
- "Incorrect number of allocations");
- if (is_disable) {
- sec_disable(tsdn, &sec);
- } else {
- sec_flush(tsdn, &sec);
- }
- expect_zu_eq(max_allocs, ta.alloc_count + ta.alloc_batch_count,
- "Incorrect number of allocations");
- expect_zu_eq(0, ta.dalloc_count,
- "Incorrect number of (non-batch) deallocations");
- expect_zu_le(NALLOCS - 1, ta.dalloc_batch_count,
- "Incorrect number of batch deallocations");
- size_t old_dalloc_batch_count = ta.dalloc_batch_count;
- /*
- * If we free into a disabled SEC, it should forward to the fallback.
- * Otherwise, the SEC should accept the allocation.
- */
- pai_dalloc(tsdn, &sec.pai, allocs[NALLOCS - 1],
- &deferred_work_generated);
- expect_zu_eq(max_allocs, ta.alloc_count + ta.alloc_batch_count,
- "Incorrect number of allocations");
- expect_zu_eq(is_disable ? 1 : 0, ta.dalloc_count,
- "Incorrect number of (non-batch) deallocations");
- expect_zu_eq(old_dalloc_batch_count, ta.dalloc_batch_count,
- "Incorrect number of batch deallocations");
- }
- TEST_BEGIN(test_disable) {
- do_disable_flush_test(/* is_disable */ true);
- }
- TEST_END
- TEST_BEGIN(test_flush) {
- do_disable_flush_test(/* is_disable */ false);
- }
- TEST_END
- TEST_BEGIN(test_max_alloc_respected) {
- pai_test_allocator_t ta;
- pai_test_allocator_init(&ta);
- sec_t sec;
- /* See the note above -- we can't use the real tsd. */
- tsdn_t *tsdn = TSDN_NULL;
- size_t max_alloc = 2 * PAGE;
- size_t attempted_alloc = 3 * PAGE;
- bool deferred_work_generated = false;
- test_sec_init(&sec, &ta.pai, /* nshards */ 1, max_alloc,
- /* max_bytes */ 1000 * PAGE);
- for (size_t i = 0; i < 100; i++) {
- expect_zu_eq(i, ta.alloc_count,
- "Incorrect number of allocations");
- expect_zu_eq(i, ta.dalloc_count,
- "Incorrect number of deallocations");
- edata_t *edata = pai_alloc(tsdn, &sec.pai, attempted_alloc,
- PAGE, /* zero */ false, /* guarded */ false,
- /* frequent_reuse */ false, &deferred_work_generated);
- expect_ptr_not_null(edata, "Unexpected alloc failure");
- expect_zu_eq(i + 1, ta.alloc_count,
- "Incorrect number of allocations");
- expect_zu_eq(i, ta.dalloc_count,
- "Incorrect number of deallocations");
- pai_dalloc(tsdn, &sec.pai, edata, &deferred_work_generated);
- }
- }
- TEST_END
- TEST_BEGIN(test_expand_shrink_delegate) {
- /*
- * Expand and shrink shouldn't affect sec state; they should just
- * delegate to the fallback PAI.
- */
- pai_test_allocator_t ta;
- pai_test_allocator_init(&ta);
- sec_t sec;
- /* See the note above -- we can't use the real tsd. */
- tsdn_t *tsdn = TSDN_NULL;
- bool deferred_work_generated = false;
- test_sec_init(&sec, &ta.pai, /* nshards */ 1, /* max_alloc */ 10 * PAGE,
- /* max_bytes */ 1000 * PAGE);
- edata_t *edata = pai_alloc(tsdn, &sec.pai, PAGE, PAGE,
- /* zero */ false, /* guarded */ false, /* frequent_reuse */ false,
- &deferred_work_generated);
- expect_ptr_not_null(edata, "Unexpected alloc failure");
- bool err = pai_expand(tsdn, &sec.pai, edata, PAGE, 4 * PAGE,
- /* zero */ false, &deferred_work_generated);
- expect_false(err, "Unexpected expand failure");
- expect_zu_eq(1, ta.expand_count, "");
- ta.expand_return_value = true;
- err = pai_expand(tsdn, &sec.pai, edata, 4 * PAGE, 3 * PAGE,
- /* zero */ false, &deferred_work_generated);
- expect_true(err, "Unexpected expand success");
- expect_zu_eq(2, ta.expand_count, "");
- err = pai_shrink(tsdn, &sec.pai, edata, 4 * PAGE, 2 * PAGE,
- &deferred_work_generated);
- expect_false(err, "Unexpected shrink failure");
- expect_zu_eq(1, ta.shrink_count, "");
- ta.shrink_return_value = true;
- err = pai_shrink(tsdn, &sec.pai, edata, 2 * PAGE, PAGE,
- &deferred_work_generated);
- expect_true(err, "Unexpected shrink success");
- expect_zu_eq(2, ta.shrink_count, "");
- }
- TEST_END
- TEST_BEGIN(test_nshards_0) {
- pai_test_allocator_t ta;
- pai_test_allocator_init(&ta);
- sec_t sec;
- /* See the note above -- we can't use the real tsd. */
- tsdn_t *tsdn = TSDN_NULL;
- base_t *base = base_new(TSDN_NULL, /* ind */ 123,
- &ehooks_default_extent_hooks, /* metadata_use_hooks */ true);
- sec_opts_t opts = SEC_OPTS_DEFAULT;
- opts.nshards = 0;
- sec_init(TSDN_NULL, &sec, base, &ta.pai, &opts);
- bool deferred_work_generated = false;
- edata_t *edata = pai_alloc(tsdn, &sec.pai, PAGE, PAGE,
- /* zero */ false, /* guarded */ false, /* frequent_reuse */ false,
- &deferred_work_generated);
- pai_dalloc(tsdn, &sec.pai, edata, &deferred_work_generated);
- /* Both operations should have gone directly to the fallback. */
- expect_zu_eq(1, ta.alloc_count, "");
- expect_zu_eq(1, ta.dalloc_count, "");
- }
- TEST_END
- static void
- expect_stats_pages(tsdn_t *tsdn, sec_t *sec, size_t npages) {
- sec_stats_t stats;
- /*
- * Check that the stats merging accumulates rather than overwrites by
- * putting some (made up) data there to begin with.
- */
- stats.bytes = 123;
- sec_stats_merge(tsdn, sec, &stats);
- assert_zu_le(npages * PAGE + 123, stats.bytes, "");
- }
- TEST_BEGIN(test_stats_simple) {
- pai_test_allocator_t ta;
- pai_test_allocator_init(&ta);
- sec_t sec;
- /* See the note above -- we can't use the real tsd. */
- tsdn_t *tsdn = TSDN_NULL;
- enum {
- NITERS = 100,
- FLUSH_PAGES = 20,
- };
- bool deferred_work_generated = false;
- test_sec_init(&sec, &ta.pai, /* nshards */ 1, /* max_alloc */ PAGE,
- /* max_bytes */ FLUSH_PAGES * PAGE);
- edata_t *allocs[FLUSH_PAGES];
- for (size_t i = 0; i < FLUSH_PAGES; i++) {
- allocs[i] = pai_alloc(tsdn, &sec.pai, PAGE, PAGE,
- /* zero */ false, /* guarded */ false, /* frequent_reuse */
- false, &deferred_work_generated);
- expect_stats_pages(tsdn, &sec, 0);
- }
- /* Increase and decrease, without flushing. */
- for (size_t i = 0; i < NITERS; i++) {
- for (size_t j = 0; j < FLUSH_PAGES / 2; j++) {
- pai_dalloc(tsdn, &sec.pai, allocs[j],
- &deferred_work_generated);
- expect_stats_pages(tsdn, &sec, j + 1);
- }
- for (size_t j = 0; j < FLUSH_PAGES / 2; j++) {
- allocs[j] = pai_alloc(tsdn, &sec.pai, PAGE, PAGE,
- /* zero */ false, /* guarded */ false,
- /* frequent_reuse */ false,
- &deferred_work_generated);
- expect_stats_pages(tsdn, &sec, FLUSH_PAGES / 2 - j - 1);
- }
- }
- }
- TEST_END
- TEST_BEGIN(test_stats_auto_flush) {
- pai_test_allocator_t ta;
- pai_test_allocator_init(&ta);
- sec_t sec;
- /* See the note above -- we can't use the real tsd. */
- tsdn_t *tsdn = TSDN_NULL;
- enum {
- FLUSH_PAGES = 10,
- };
- test_sec_init(&sec, &ta.pai, /* nshards */ 1, /* max_alloc */ PAGE,
- /* max_bytes */ FLUSH_PAGES * PAGE);
- edata_t *extra_alloc0;
- edata_t *extra_alloc1;
- edata_t *allocs[2 * FLUSH_PAGES];
- bool deferred_work_generated = false;
- extra_alloc0 = pai_alloc(tsdn, &sec.pai, PAGE, PAGE, /* zero */ false,
- /* guarded */ false, /* frequent_reuse */ false,
- &deferred_work_generated);
- extra_alloc1 = pai_alloc(tsdn, &sec.pai, PAGE, PAGE, /* zero */ false,
- /* guarded */ false, /* frequent_reuse */ false,
- &deferred_work_generated);
- for (size_t i = 0; i < 2 * FLUSH_PAGES; i++) {
- allocs[i] = pai_alloc(tsdn, &sec.pai, PAGE, PAGE,
- /* zero */ false, /* guarded */ false, /* frequent_reuse */
- false, &deferred_work_generated);
- }
- for (size_t i = 0; i < FLUSH_PAGES; i++) {
- pai_dalloc(tsdn, &sec.pai, allocs[i], &deferred_work_generated);
- }
- pai_dalloc(tsdn, &sec.pai, extra_alloc0, &deferred_work_generated);
- /* Flush the remaining pages; stats should still work. */
- for (size_t i = 0; i < FLUSH_PAGES; i++) {
- pai_dalloc(tsdn, &sec.pai, allocs[FLUSH_PAGES + i],
- &deferred_work_generated);
- }
- pai_dalloc(tsdn, &sec.pai, extra_alloc1, &deferred_work_generated);
- expect_stats_pages(tsdn, &sec, ta.alloc_count + ta.alloc_batch_count
- - ta.dalloc_count - ta.dalloc_batch_count);
- }
- TEST_END
- TEST_BEGIN(test_stats_manual_flush) {
- pai_test_allocator_t ta;
- pai_test_allocator_init(&ta);
- sec_t sec;
- /* See the note above -- we can't use the real tsd. */
- tsdn_t *tsdn = TSDN_NULL;
- enum {
- FLUSH_PAGES = 10,
- };
- test_sec_init(&sec, &ta.pai, /* nshards */ 1, /* max_alloc */ PAGE,
- /* max_bytes */ FLUSH_PAGES * PAGE);
- bool deferred_work_generated = false;
- edata_t *allocs[FLUSH_PAGES];
- for (size_t i = 0; i < FLUSH_PAGES; i++) {
- allocs[i] = pai_alloc(tsdn, &sec.pai, PAGE, PAGE,
- /* zero */ false, /* guarded */ false, /* frequent_reuse */
- false, &deferred_work_generated);
- expect_stats_pages(tsdn, &sec, 0);
- }
- /* Dalloc the first half of the allocations. */
- for (size_t i = 0; i < FLUSH_PAGES / 2; i++) {
- pai_dalloc(tsdn, &sec.pai, allocs[i], &deferred_work_generated);
- expect_stats_pages(tsdn, &sec, i + 1);
- }
- sec_flush(tsdn, &sec);
- expect_stats_pages(tsdn, &sec, 0);
- /* Flush the remaining pages. */
- for (size_t i = 0; i < FLUSH_PAGES / 2; i++) {
- pai_dalloc(tsdn, &sec.pai, allocs[FLUSH_PAGES / 2 + i],
- &deferred_work_generated);
- expect_stats_pages(tsdn, &sec, i + 1);
- }
- sec_disable(tsdn, &sec);
- expect_stats_pages(tsdn, &sec, 0);
- }
- TEST_END
- int
- main(void) {
- return test(
- test_reuse,
- test_auto_flush,
- test_disable,
- test_flush,
- test_max_alloc_respected,
- test_expand_shrink_delegate,
- test_nshards_0,
- test_stats_simple,
- test_stats_auto_flush,
- test_stats_manual_flush);
- }
|