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