123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- #include "test/jemalloc_test.h"
- #define BATCH_MAX ((1U << 16) + 1024)
- static void *global_ptrs[BATCH_MAX];
- #define PAGE_ALIGNED(ptr) (((uintptr_t)ptr & PAGE_MASK) == 0)
- static void
- verify_batch_basic(tsd_t *tsd, void **ptrs, size_t batch, size_t usize,
- bool zero) {
- for (size_t i = 0; i < batch; ++i) {
- void *p = ptrs[i];
- expect_zu_eq(isalloc(tsd_tsdn(tsd), p), usize, "");
- if (zero) {
- for (size_t k = 0; k < usize; ++k) {
- expect_true(*((unsigned char *)p + k) == 0, "");
- }
- }
- }
- }
- static void
- verify_batch_locality(tsd_t *tsd, void **ptrs, size_t batch, size_t usize,
- arena_t *arena, unsigned nregs) {
- if (config_prof && opt_prof) {
- /*
- * Checking batch locality when prof is on is feasible but
- * complicated, while checking the non-prof case suffices for
- * unit-test purpose.
- */
- return;
- }
- for (size_t i = 0, j = 0; i < batch; ++i, ++j) {
- if (j == nregs) {
- j = 0;
- }
- if (j == 0 && batch - i < nregs) {
- break;
- }
- void *p = ptrs[i];
- expect_ptr_eq(iaalloc(tsd_tsdn(tsd), p), arena, "");
- if (j == 0) {
- expect_true(PAGE_ALIGNED(p), "");
- continue;
- }
- assert(i > 0);
- void *q = ptrs[i - 1];
- expect_true((uintptr_t)p > (uintptr_t)q
- && (size_t)((uintptr_t)p - (uintptr_t)q) == usize, "");
- }
- }
- static void
- release_batch(void **ptrs, size_t batch, size_t size) {
- for (size_t i = 0; i < batch; ++i) {
- sdallocx(ptrs[i], size, 0);
- }
- }
- typedef struct batch_alloc_packet_s batch_alloc_packet_t;
- struct batch_alloc_packet_s {
- void **ptrs;
- size_t num;
- size_t size;
- int flags;
- };
- static size_t
- batch_alloc_wrapper(void **ptrs, size_t num, size_t size, int flags) {
- batch_alloc_packet_t batch_alloc_packet = {ptrs, num, size, flags};
- size_t filled;
- size_t len = sizeof(size_t);
- assert_d_eq(mallctl("experimental.batch_alloc", &filled, &len,
- &batch_alloc_packet, sizeof(batch_alloc_packet)), 0, "");
- return filled;
- }
- static void
- test_wrapper(size_t size, size_t alignment, bool zero, unsigned arena_flag) {
- tsd_t *tsd = tsd_fetch();
- assert(tsd != NULL);
- const size_t usize =
- (alignment != 0 ? sz_sa2u(size, alignment) : sz_s2u(size));
- const szind_t ind = sz_size2index(usize);
- const bin_info_t *bin_info = &bin_infos[ind];
- const unsigned nregs = bin_info->nregs;
- assert(nregs > 0);
- arena_t *arena;
- if (arena_flag != 0) {
- arena = arena_get(tsd_tsdn(tsd), MALLOCX_ARENA_GET(arena_flag),
- false);
- } else {
- arena = arena_choose(tsd, NULL);
- }
- assert(arena != NULL);
- int flags = arena_flag;
- if (alignment != 0) {
- flags |= MALLOCX_ALIGN(alignment);
- }
- if (zero) {
- flags |= MALLOCX_ZERO;
- }
- /*
- * Allocate for the purpose of bootstrapping arena_tdata, so that the
- * change in bin stats won't contaminate the stats to be verified below.
- */
- void *p = mallocx(size, flags | MALLOCX_TCACHE_NONE);
- for (size_t i = 0; i < 4; ++i) {
- size_t base = 0;
- if (i == 1) {
- base = nregs;
- } else if (i == 2) {
- base = nregs * 2;
- } else if (i == 3) {
- base = (1 << 16);
- }
- for (int j = -1; j <= 1; ++j) {
- if (base == 0 && j == -1) {
- continue;
- }
- size_t batch = base + (size_t)j;
- assert(batch < BATCH_MAX);
- size_t filled = batch_alloc_wrapper(global_ptrs, batch,
- size, flags);
- assert_zu_eq(filled, batch, "");
- verify_batch_basic(tsd, global_ptrs, batch, usize,
- zero);
- verify_batch_locality(tsd, global_ptrs, batch, usize,
- arena, nregs);
- release_batch(global_ptrs, batch, usize);
- }
- }
- free(p);
- }
- TEST_BEGIN(test_batch_alloc) {
- test_wrapper(11, 0, false, 0);
- }
- TEST_END
- TEST_BEGIN(test_batch_alloc_zero) {
- test_wrapper(11, 0, true, 0);
- }
- TEST_END
- TEST_BEGIN(test_batch_alloc_aligned) {
- test_wrapper(7, 16, false, 0);
- }
- TEST_END
- TEST_BEGIN(test_batch_alloc_manual_arena) {
- unsigned arena_ind;
- size_t len_unsigned = sizeof(unsigned);
- assert_d_eq(mallctl("arenas.create", &arena_ind, &len_unsigned, NULL,
- 0), 0, "");
- test_wrapper(11, 0, false, MALLOCX_ARENA(arena_ind));
- }
- TEST_END
- TEST_BEGIN(test_batch_alloc_large) {
- size_t size = SC_LARGE_MINCLASS;
- for (size_t batch = 0; batch < 4; ++batch) {
- assert(batch < BATCH_MAX);
- size_t filled = batch_alloc(global_ptrs, batch, size, 0);
- assert_zu_eq(filled, batch, "");
- release_batch(global_ptrs, batch, size);
- }
- size = tcache_maxclass + 1;
- for (size_t batch = 0; batch < 4; ++batch) {
- assert(batch < BATCH_MAX);
- size_t filled = batch_alloc(global_ptrs, batch, size, 0);
- assert_zu_eq(filled, batch, "");
- release_batch(global_ptrs, batch, size);
- }
- }
- TEST_END
- int
- main(void) {
- return test(
- test_batch_alloc,
- test_batch_alloc_zero,
- test_batch_alloc_aligned,
- test_batch_alloc_manual_arena,
- test_batch_alloc_large);
- }
|