1 #include "test/jemalloc_test.h" 2 3 const char *malloc_conf = 4 /* Use smallest possible chunk size. */ 5 "lg_chunk:0" 6 /* Immediately purge to minimize fragmentation. */ 7 ",lg_dirty_mult:-1" 8 ",decay_time:-1" 9 ; 10 11 /* 12 * Size class that is a divisor of the page size, ideally 4+ regions per run. 13 */ 14 #if LG_PAGE <= 14 15 #define SZ (ZU(1) << (LG_PAGE - 2)) 16 #else 17 #define SZ 4096 18 #endif 19 20 /* 21 * Number of chunks to consume at high water mark. Should be at least 2 so that 22 * if mmap()ed memory grows downward, downward growth of mmap()ed memory is 23 * tested. 24 */ 25 #define NCHUNKS 8 26 27 static unsigned 28 binind_compute(void) 29 { 30 size_t sz; 31 unsigned nbins, i; 32 33 sz = sizeof(nbins); 34 assert_d_eq(mallctl("arenas.nbins", (void *)&nbins, &sz, NULL, 0), 0, 35 "Unexpected mallctl failure"); 36 37 for (i = 0; i < nbins; i++) { 38 size_t mib[4]; 39 size_t miblen = sizeof(mib)/sizeof(size_t); 40 size_t size; 41 42 assert_d_eq(mallctlnametomib("arenas.bin.0.size", mib, 43 &miblen), 0, "Unexpected mallctlnametomb failure"); 44 mib[2] = (size_t)i; 45 46 sz = sizeof(size); 47 assert_d_eq(mallctlbymib(mib, miblen, (void *)&size, &sz, NULL, 48 0), 0, "Unexpected mallctlbymib failure"); 49 if (size == SZ) 50 return (i); 51 } 52 53 test_fail("Unable to compute nregs_per_run"); 54 return (0); 55 } 56 57 static size_t 58 nregs_per_run_compute(void) 59 { 60 uint32_t nregs; 61 size_t sz; 62 unsigned binind = binind_compute(); 63 size_t mib[4]; 64 size_t miblen = sizeof(mib)/sizeof(size_t); 65 66 assert_d_eq(mallctlnametomib("arenas.bin.0.nregs", mib, &miblen), 0, 67 "Unexpected mallctlnametomb failure"); 68 mib[2] = (size_t)binind; 69 sz = sizeof(nregs); 70 assert_d_eq(mallctlbymib(mib, miblen, (void *)&nregs, &sz, NULL, 71 0), 0, "Unexpected mallctlbymib failure"); 72 return (nregs); 73 } 74 75 static size_t 76 npages_per_run_compute(void) 77 { 78 size_t sz; 79 unsigned binind = binind_compute(); 80 size_t mib[4]; 81 size_t miblen = sizeof(mib)/sizeof(size_t); 82 size_t run_size; 83 84 assert_d_eq(mallctlnametomib("arenas.bin.0.run_size", mib, &miblen), 0, 85 "Unexpected mallctlnametomb failure"); 86 mib[2] = (size_t)binind; 87 sz = sizeof(run_size); 88 assert_d_eq(mallctlbymib(mib, miblen, (void *)&run_size, &sz, NULL, 89 0), 0, "Unexpected mallctlbymib failure"); 90 return (run_size >> LG_PAGE); 91 } 92 93 static size_t 94 npages_per_chunk_compute(void) 95 { 96 97 return ((chunksize >> LG_PAGE) - map_bias); 98 } 99 100 static size_t 101 nruns_per_chunk_compute(void) 102 { 103 104 return (npages_per_chunk_compute() / npages_per_run_compute()); 105 } 106 107 static unsigned 108 arenas_extend_mallctl(void) 109 { 110 unsigned arena_ind; 111 size_t sz; 112 113 sz = sizeof(arena_ind); 114 assert_d_eq(mallctl("arenas.extend", (void *)&arena_ind, &sz, NULL, 0), 115 0, "Error in arenas.extend"); 116 117 return (arena_ind); 118 } 119 120 static void 121 arena_reset_mallctl(unsigned arena_ind) 122 { 123 size_t mib[3]; 124 size_t miblen = sizeof(mib)/sizeof(size_t); 125 126 assert_d_eq(mallctlnametomib("arena.0.reset", mib, &miblen), 0, 127 "Unexpected mallctlnametomib() failure"); 128 mib[1] = (size_t)arena_ind; 129 assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0, 130 "Unexpected mallctlbymib() failure"); 131 } 132 133 TEST_BEGIN(test_pack) 134 { 135 unsigned arena_ind = arenas_extend_mallctl(); 136 size_t nregs_per_run = nregs_per_run_compute(); 137 size_t nruns_per_chunk = nruns_per_chunk_compute(); 138 size_t nruns = nruns_per_chunk * NCHUNKS; 139 size_t nregs = nregs_per_run * nruns; 140 VARIABLE_ARRAY(void *, ptrs, nregs); 141 size_t i, j, offset; 142 143 /* Fill matrix. */ 144 for (i = offset = 0; i < nruns; i++) { 145 for (j = 0; j < nregs_per_run; j++) { 146 void *p = mallocx(SZ, MALLOCX_ARENA(arena_ind) | 147 MALLOCX_TCACHE_NONE); 148 assert_ptr_not_null(p, 149 "Unexpected mallocx(%zu, MALLOCX_ARENA(%u) |" 150 " MALLOCX_TCACHE_NONE) failure, run=%zu, reg=%zu", 151 SZ, arena_ind, i, j); 152 ptrs[(i * nregs_per_run) + j] = p; 153 } 154 } 155 156 /* 157 * Free all but one region of each run, but rotate which region is 158 * preserved, so that subsequent allocations exercise the within-run 159 * layout policy. 160 */ 161 offset = 0; 162 for (i = offset = 0; 163 i < nruns; 164 i++, offset = (offset + 1) % nregs_per_run) { 165 for (j = 0; j < nregs_per_run; j++) { 166 void *p = ptrs[(i * nregs_per_run) + j]; 167 if (offset == j) 168 continue; 169 dallocx(p, MALLOCX_ARENA(arena_ind) | 170 MALLOCX_TCACHE_NONE); 171 } 172 } 173 174 /* 175 * Logically refill matrix, skipping preserved regions and verifying 176 * that the matrix is unmodified. 177 */ 178 offset = 0; 179 for (i = offset = 0; 180 i < nruns; 181 i++, offset = (offset + 1) % nregs_per_run) { 182 for (j = 0; j < nregs_per_run; j++) { 183 void *p; 184 185 if (offset == j) 186 continue; 187 p = mallocx(SZ, MALLOCX_ARENA(arena_ind) | 188 MALLOCX_TCACHE_NONE); 189 assert_ptr_eq(p, ptrs[(i * nregs_per_run) + j], 190 "Unexpected refill discrepancy, run=%zu, reg=%zu\n", 191 i, j); 192 } 193 } 194 195 /* Clean up. */ 196 arena_reset_mallctl(arena_ind); 197 } 198 TEST_END 199 200 int 201 main(void) 202 { 203 204 return (test( 205 test_pack)); 206 } 207