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