1 #include "test/jemalloc_test.h" 2 3 #include "jemalloc/internal/ph.h" 4 5 typedef struct node_s node_t; 6 7 struct node_s { 8 #define NODE_MAGIC 0x9823af7e 9 uint32_t magic; 10 phn(node_t) link; 11 uint64_t key; 12 }; 13 14 static int 15 node_cmp(const node_t *a, const node_t *b) { 16 int ret; 17 18 ret = (a->key > b->key) - (a->key < b->key); 19 if (ret == 0) { 20 /* 21 * Duplicates are not allowed in the heap, so force an 22 * arbitrary ordering for non-identical items with equal keys. 23 */ 24 ret = (((uintptr_t)a) > ((uintptr_t)b)) 25 - (((uintptr_t)a) < ((uintptr_t)b)); 26 } 27 return ret; 28 } 29 30 static int 31 node_cmp_magic(const node_t *a, const node_t *b) { 32 33 assert_u32_eq(a->magic, NODE_MAGIC, "Bad magic"); 34 assert_u32_eq(b->magic, NODE_MAGIC, "Bad magic"); 35 36 return node_cmp(a, b); 37 } 38 39 typedef ph(node_t) heap_t; 40 ph_gen(static, heap_, heap_t, node_t, link, node_cmp_magic); 41 42 static void 43 node_print(const node_t *node, unsigned depth) { 44 unsigned i; 45 node_t *leftmost_child, *sibling; 46 47 for (i = 0; i < depth; i++) { 48 malloc_printf("\t"); 49 } 50 malloc_printf("%2"FMTu64"\n", node->key); 51 52 leftmost_child = phn_lchild_get(node_t, link, node); 53 if (leftmost_child == NULL) { 54 return; 55 } 56 node_print(leftmost_child, depth + 1); 57 58 for (sibling = phn_next_get(node_t, link, leftmost_child); sibling != 59 NULL; sibling = phn_next_get(node_t, link, sibling)) { 60 node_print(sibling, depth + 1); 61 } 62 } 63 64 static void 65 heap_print(const heap_t *heap) { 66 node_t *auxelm; 67 68 malloc_printf("vvv heap %p vvv\n", heap); 69 if (heap->ph_root == NULL) { 70 goto label_return; 71 } 72 73 node_print(heap->ph_root, 0); 74 75 for (auxelm = phn_next_get(node_t, link, heap->ph_root); auxelm != NULL; 76 auxelm = phn_next_get(node_t, link, auxelm)) { 77 assert_ptr_eq(phn_next_get(node_t, link, phn_prev_get(node_t, 78 link, auxelm)), auxelm, 79 "auxelm's prev doesn't link to auxelm"); 80 node_print(auxelm, 0); 81 } 82 83 label_return: 84 malloc_printf("^^^ heap %p ^^^\n", heap); 85 } 86 87 static unsigned 88 node_validate(const node_t *node, const node_t *parent) { 89 unsigned nnodes = 1; 90 node_t *leftmost_child, *sibling; 91 92 if (parent != NULL) { 93 assert_d_ge(node_cmp_magic(node, parent), 0, 94 "Child is less than parent"); 95 } 96 97 leftmost_child = phn_lchild_get(node_t, link, node); 98 if (leftmost_child == NULL) { 99 return nnodes; 100 } 101 assert_ptr_eq((void *)phn_prev_get(node_t, link, leftmost_child), 102 (void *)node, "Leftmost child does not link to node"); 103 nnodes += node_validate(leftmost_child, node); 104 105 for (sibling = phn_next_get(node_t, link, leftmost_child); sibling != 106 NULL; sibling = phn_next_get(node_t, link, sibling)) { 107 assert_ptr_eq(phn_next_get(node_t, link, phn_prev_get(node_t, 108 link, sibling)), sibling, 109 "sibling's prev doesn't link to sibling"); 110 nnodes += node_validate(sibling, node); 111 } 112 return nnodes; 113 } 114 115 static unsigned 116 heap_validate(const heap_t *heap) { 117 unsigned nnodes = 0; 118 node_t *auxelm; 119 120 if (heap->ph_root == NULL) { 121 goto label_return; 122 } 123 124 nnodes += node_validate(heap->ph_root, NULL); 125 126 for (auxelm = phn_next_get(node_t, link, heap->ph_root); auxelm != NULL; 127 auxelm = phn_next_get(node_t, link, auxelm)) { 128 assert_ptr_eq(phn_next_get(node_t, link, phn_prev_get(node_t, 129 link, auxelm)), auxelm, 130 "auxelm's prev doesn't link to auxelm"); 131 nnodes += node_validate(auxelm, NULL); 132 } 133 134 label_return: 135 if (false) { 136 heap_print(heap); 137 } 138 return nnodes; 139 } 140 141 TEST_BEGIN(test_ph_empty) { 142 heap_t heap; 143 144 heap_new(&heap); 145 assert_true(heap_empty(&heap), "Heap should be empty"); 146 assert_ptr_null(heap_first(&heap), "Unexpected node"); 147 assert_ptr_null(heap_any(&heap), "Unexpected node"); 148 } 149 TEST_END 150 151 static void 152 node_remove(heap_t *heap, node_t *node) { 153 heap_remove(heap, node); 154 155 node->magic = 0; 156 } 157 158 static node_t * 159 node_remove_first(heap_t *heap) { 160 node_t *node = heap_remove_first(heap); 161 node->magic = 0; 162 return node; 163 } 164 165 static node_t * 166 node_remove_any(heap_t *heap) { 167 node_t *node = heap_remove_any(heap); 168 node->magic = 0; 169 return node; 170 } 171 172 TEST_BEGIN(test_ph_random) { 173 #define NNODES 25 174 #define NBAGS 250 175 #define SEED 42 176 sfmt_t *sfmt; 177 uint64_t bag[NNODES]; 178 heap_t heap; 179 node_t nodes[NNODES]; 180 unsigned i, j, k; 181 182 sfmt = init_gen_rand(SEED); 183 for (i = 0; i < NBAGS; i++) { 184 switch (i) { 185 case 0: 186 /* Insert in order. */ 187 for (j = 0; j < NNODES; j++) { 188 bag[j] = j; 189 } 190 break; 191 case 1: 192 /* Insert in reverse order. */ 193 for (j = 0; j < NNODES; j++) { 194 bag[j] = NNODES - j - 1; 195 } 196 break; 197 default: 198 for (j = 0; j < NNODES; j++) { 199 bag[j] = gen_rand64_range(sfmt, NNODES); 200 } 201 } 202 203 for (j = 1; j <= NNODES; j++) { 204 /* Initialize heap and nodes. */ 205 heap_new(&heap); 206 assert_u_eq(heap_validate(&heap), 0, 207 "Incorrect node count"); 208 for (k = 0; k < j; k++) { 209 nodes[k].magic = NODE_MAGIC; 210 nodes[k].key = bag[k]; 211 } 212 213 /* Insert nodes. */ 214 for (k = 0; k < j; k++) { 215 heap_insert(&heap, &nodes[k]); 216 if (i % 13 == 12) { 217 assert_ptr_not_null(heap_any(&heap), 218 "Heap should not be empty"); 219 /* Trigger merging. */ 220 assert_ptr_not_null(heap_first(&heap), 221 "Heap should not be empty"); 222 } 223 assert_u_eq(heap_validate(&heap), k + 1, 224 "Incorrect node count"); 225 } 226 227 assert_false(heap_empty(&heap), 228 "Heap should not be empty"); 229 230 /* Remove nodes. */ 231 switch (i % 6) { 232 case 0: 233 for (k = 0; k < j; k++) { 234 assert_u_eq(heap_validate(&heap), j - k, 235 "Incorrect node count"); 236 node_remove(&heap, &nodes[k]); 237 assert_u_eq(heap_validate(&heap), j - k 238 - 1, "Incorrect node count"); 239 } 240 break; 241 case 1: 242 for (k = j; k > 0; k--) { 243 node_remove(&heap, &nodes[k-1]); 244 assert_u_eq(heap_validate(&heap), k - 1, 245 "Incorrect node count"); 246 } 247 break; 248 case 2: { 249 node_t *prev = NULL; 250 for (k = 0; k < j; k++) { 251 node_t *node = node_remove_first(&heap); 252 assert_u_eq(heap_validate(&heap), j - k 253 - 1, "Incorrect node count"); 254 if (prev != NULL) { 255 assert_d_ge(node_cmp(node, 256 prev), 0, 257 "Bad removal order"); 258 } 259 prev = node; 260 } 261 break; 262 } case 3: { 263 node_t *prev = NULL; 264 for (k = 0; k < j; k++) { 265 node_t *node = heap_first(&heap); 266 assert_u_eq(heap_validate(&heap), j - k, 267 "Incorrect node count"); 268 if (prev != NULL) { 269 assert_d_ge(node_cmp(node, 270 prev), 0, 271 "Bad removal order"); 272 } 273 node_remove(&heap, node); 274 assert_u_eq(heap_validate(&heap), j - k 275 - 1, "Incorrect node count"); 276 prev = node; 277 } 278 break; 279 } case 4: { 280 for (k = 0; k < j; k++) { 281 node_remove_any(&heap); 282 assert_u_eq(heap_validate(&heap), j - k 283 - 1, "Incorrect node count"); 284 } 285 break; 286 } case 5: { 287 for (k = 0; k < j; k++) { 288 node_t *node = heap_any(&heap); 289 assert_u_eq(heap_validate(&heap), j - k, 290 "Incorrect node count"); 291 node_remove(&heap, node); 292 assert_u_eq(heap_validate(&heap), j - k 293 - 1, "Incorrect node count"); 294 } 295 break; 296 } default: 297 not_reached(); 298 } 299 300 assert_ptr_null(heap_first(&heap), 301 "Heap should be empty"); 302 assert_ptr_null(heap_any(&heap), 303 "Heap should be empty"); 304 assert_true(heap_empty(&heap), "Heap should be empty"); 305 } 306 } 307 fini_gen_rand(sfmt); 308 #undef NNODES 309 #undef SEED 310 } 311 TEST_END 312 313 int 314 main(void) { 315 return test( 316 test_ph_empty, 317 test_ph_random); 318 } 319