Home | History | Annotate | Line # | Download | only in unit
batch_alloc.c revision 1.1.1.1
      1  1.1  christos #include "test/jemalloc_test.h"
      2  1.1  christos 
      3  1.1  christos #define BATCH_MAX ((1U << 16) + 1024)
      4  1.1  christos static void *global_ptrs[BATCH_MAX];
      5  1.1  christos 
      6  1.1  christos #define PAGE_ALIGNED(ptr) (((uintptr_t)ptr & PAGE_MASK) == 0)
      7  1.1  christos 
      8  1.1  christos static void
      9  1.1  christos verify_batch_basic(tsd_t *tsd, void **ptrs, size_t batch, size_t usize,
     10  1.1  christos     bool zero) {
     11  1.1  christos 	for (size_t i = 0; i < batch; ++i) {
     12  1.1  christos 		void *p = ptrs[i];
     13  1.1  christos 		expect_zu_eq(isalloc(tsd_tsdn(tsd), p), usize, "");
     14  1.1  christos 		if (zero) {
     15  1.1  christos 			for (size_t k = 0; k < usize; ++k) {
     16  1.1  christos 				expect_true(*((unsigned char *)p + k) == 0, "");
     17  1.1  christos 			}
     18  1.1  christos 		}
     19  1.1  christos 	}
     20  1.1  christos }
     21  1.1  christos 
     22  1.1  christos static void
     23  1.1  christos verify_batch_locality(tsd_t *tsd, void **ptrs, size_t batch, size_t usize,
     24  1.1  christos     arena_t *arena, unsigned nregs) {
     25  1.1  christos 	if (config_prof && opt_prof) {
     26  1.1  christos 		/*
     27  1.1  christos 		 * Checking batch locality when prof is on is feasible but
     28  1.1  christos 		 * complicated, while checking the non-prof case suffices for
     29  1.1  christos 		 * unit-test purpose.
     30  1.1  christos 		 */
     31  1.1  christos 		return;
     32  1.1  christos 	}
     33  1.1  christos 	for (size_t i = 0, j = 0; i < batch; ++i, ++j) {
     34  1.1  christos 		if (j == nregs) {
     35  1.1  christos 			j = 0;
     36  1.1  christos 		}
     37  1.1  christos 		if (j == 0 && batch - i < nregs) {
     38  1.1  christos 			break;
     39  1.1  christos 		}
     40  1.1  christos 		void *p = ptrs[i];
     41  1.1  christos 		expect_ptr_eq(iaalloc(tsd_tsdn(tsd), p), arena, "");
     42  1.1  christos 		if (j == 0) {
     43  1.1  christos 			expect_true(PAGE_ALIGNED(p), "");
     44  1.1  christos 			continue;
     45  1.1  christos 		}
     46  1.1  christos 		assert(i > 0);
     47  1.1  christos 		void *q = ptrs[i - 1];
     48  1.1  christos 		expect_true((uintptr_t)p > (uintptr_t)q
     49  1.1  christos 		    && (size_t)((uintptr_t)p - (uintptr_t)q) == usize, "");
     50  1.1  christos 	}
     51  1.1  christos }
     52  1.1  christos 
     53  1.1  christos static void
     54  1.1  christos release_batch(void **ptrs, size_t batch, size_t size) {
     55  1.1  christos 	for (size_t i = 0; i < batch; ++i) {
     56  1.1  christos 		sdallocx(ptrs[i], size, 0);
     57  1.1  christos 	}
     58  1.1  christos }
     59  1.1  christos 
     60  1.1  christos typedef struct batch_alloc_packet_s batch_alloc_packet_t;
     61  1.1  christos struct batch_alloc_packet_s {
     62  1.1  christos 	void **ptrs;
     63  1.1  christos 	size_t num;
     64  1.1  christos 	size_t size;
     65  1.1  christos 	int flags;
     66  1.1  christos };
     67  1.1  christos 
     68  1.1  christos static size_t
     69  1.1  christos batch_alloc_wrapper(void **ptrs, size_t num, size_t size, int flags) {
     70  1.1  christos 	batch_alloc_packet_t batch_alloc_packet = {ptrs, num, size, flags};
     71  1.1  christos 	size_t filled;
     72  1.1  christos 	size_t len = sizeof(size_t);
     73  1.1  christos 	assert_d_eq(mallctl("experimental.batch_alloc", &filled, &len,
     74  1.1  christos 	    &batch_alloc_packet, sizeof(batch_alloc_packet)), 0, "");
     75  1.1  christos 	return filled;
     76  1.1  christos }
     77  1.1  christos 
     78  1.1  christos static void
     79  1.1  christos test_wrapper(size_t size, size_t alignment, bool zero, unsigned arena_flag) {
     80  1.1  christos 	tsd_t *tsd = tsd_fetch();
     81  1.1  christos 	assert(tsd != NULL);
     82  1.1  christos 	const size_t usize =
     83  1.1  christos 	    (alignment != 0 ? sz_sa2u(size, alignment) : sz_s2u(size));
     84  1.1  christos 	const szind_t ind = sz_size2index(usize);
     85  1.1  christos 	const bin_info_t *bin_info = &bin_infos[ind];
     86  1.1  christos 	const unsigned nregs = bin_info->nregs;
     87  1.1  christos 	assert(nregs > 0);
     88  1.1  christos 	arena_t *arena;
     89  1.1  christos 	if (arena_flag != 0) {
     90  1.1  christos 		arena = arena_get(tsd_tsdn(tsd), MALLOCX_ARENA_GET(arena_flag),
     91  1.1  christos 		    false);
     92  1.1  christos 	} else {
     93  1.1  christos 		arena = arena_choose(tsd, NULL);
     94  1.1  christos 	}
     95  1.1  christos 	assert(arena != NULL);
     96  1.1  christos 	int flags = arena_flag;
     97  1.1  christos 	if (alignment != 0) {
     98  1.1  christos 		flags |= MALLOCX_ALIGN(alignment);
     99  1.1  christos 	}
    100  1.1  christos 	if (zero) {
    101  1.1  christos 		flags |= MALLOCX_ZERO;
    102  1.1  christos 	}
    103  1.1  christos 
    104  1.1  christos 	/*
    105  1.1  christos 	 * Allocate for the purpose of bootstrapping arena_tdata, so that the
    106  1.1  christos 	 * change in bin stats won't contaminate the stats to be verified below.
    107  1.1  christos 	 */
    108  1.1  christos 	void *p = mallocx(size, flags | MALLOCX_TCACHE_NONE);
    109  1.1  christos 
    110  1.1  christos 	for (size_t i = 0; i < 4; ++i) {
    111  1.1  christos 		size_t base = 0;
    112  1.1  christos 		if (i == 1) {
    113  1.1  christos 			base = nregs;
    114  1.1  christos 		} else if (i == 2) {
    115  1.1  christos 			base = nregs * 2;
    116  1.1  christos 		} else if (i == 3) {
    117  1.1  christos 			base = (1 << 16);
    118  1.1  christos 		}
    119  1.1  christos 		for (int j = -1; j <= 1; ++j) {
    120  1.1  christos 			if (base == 0 && j == -1) {
    121  1.1  christos 				continue;
    122  1.1  christos 			}
    123  1.1  christos 			size_t batch = base + (size_t)j;
    124  1.1  christos 			assert(batch < BATCH_MAX);
    125  1.1  christos 			size_t filled = batch_alloc_wrapper(global_ptrs, batch,
    126  1.1  christos 			    size, flags);
    127  1.1  christos 			assert_zu_eq(filled, batch, "");
    128  1.1  christos 			verify_batch_basic(tsd, global_ptrs, batch, usize,
    129  1.1  christos 			    zero);
    130  1.1  christos 			verify_batch_locality(tsd, global_ptrs, batch, usize,
    131  1.1  christos 			    arena, nregs);
    132  1.1  christos 			release_batch(global_ptrs, batch, usize);
    133  1.1  christos 		}
    134  1.1  christos 	}
    135  1.1  christos 
    136  1.1  christos 	free(p);
    137  1.1  christos }
    138  1.1  christos 
    139  1.1  christos TEST_BEGIN(test_batch_alloc) {
    140  1.1  christos 	test_wrapper(11, 0, false, 0);
    141  1.1  christos }
    142  1.1  christos TEST_END
    143  1.1  christos 
    144  1.1  christos TEST_BEGIN(test_batch_alloc_zero) {
    145  1.1  christos 	test_wrapper(11, 0, true, 0);
    146  1.1  christos }
    147  1.1  christos TEST_END
    148  1.1  christos 
    149  1.1  christos TEST_BEGIN(test_batch_alloc_aligned) {
    150  1.1  christos 	test_wrapper(7, 16, false, 0);
    151  1.1  christos }
    152  1.1  christos TEST_END
    153  1.1  christos 
    154  1.1  christos TEST_BEGIN(test_batch_alloc_manual_arena) {
    155  1.1  christos 	unsigned arena_ind;
    156  1.1  christos 	size_t len_unsigned = sizeof(unsigned);
    157  1.1  christos 	assert_d_eq(mallctl("arenas.create", &arena_ind, &len_unsigned, NULL,
    158  1.1  christos 	    0), 0, "");
    159  1.1  christos 	test_wrapper(11, 0, false, MALLOCX_ARENA(arena_ind));
    160  1.1  christos }
    161  1.1  christos TEST_END
    162  1.1  christos 
    163  1.1  christos TEST_BEGIN(test_batch_alloc_large) {
    164  1.1  christos 	size_t size = SC_LARGE_MINCLASS;
    165  1.1  christos 	for (size_t batch = 0; batch < 4; ++batch) {
    166  1.1  christos 		assert(batch < BATCH_MAX);
    167  1.1  christos 		size_t filled = batch_alloc(global_ptrs, batch, size, 0);
    168  1.1  christos 		assert_zu_eq(filled, batch, "");
    169  1.1  christos 		release_batch(global_ptrs, batch, size);
    170  1.1  christos 	}
    171  1.1  christos 	size = tcache_maxclass + 1;
    172  1.1  christos 	for (size_t batch = 0; batch < 4; ++batch) {
    173  1.1  christos 		assert(batch < BATCH_MAX);
    174  1.1  christos 		size_t filled = batch_alloc(global_ptrs, batch, size, 0);
    175  1.1  christos 		assert_zu_eq(filled, batch, "");
    176  1.1  christos 		release_batch(global_ptrs, batch, size);
    177  1.1  christos 	}
    178  1.1  christos }
    179  1.1  christos TEST_END
    180  1.1  christos 
    181  1.1  christos int
    182  1.1  christos main(void) {
    183  1.1  christos 	return test(
    184  1.1  christos 	    test_batch_alloc,
    185  1.1  christos 	    test_batch_alloc_zero,
    186  1.1  christos 	    test_batch_alloc_aligned,
    187  1.1  christos 	    test_batch_alloc_manual_arena,
    188  1.1  christos 	    test_batch_alloc_large);
    189  1.1  christos }
    190