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