123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318 |
- #include "test/jemalloc_test.h"
- #include "jemalloc/internal/ph.h"
- typedef struct node_s node_t;
- struct node_s {
- #define NODE_MAGIC 0x9823af7e
- uint32_t magic;
- phn(node_t) link;
- uint64_t key;
- };
- static int
- node_cmp(const node_t *a, const node_t *b) {
- int ret;
- ret = (a->key > b->key) - (a->key < b->key);
- if (ret == 0) {
- /*
- * Duplicates are not allowed in the heap, so force an
- * arbitrary ordering for non-identical items with equal keys.
- */
- ret = (((uintptr_t)a) > ((uintptr_t)b))
- - (((uintptr_t)a) < ((uintptr_t)b));
- }
- return ret;
- }
- static int
- node_cmp_magic(const node_t *a, const node_t *b) {
- assert_u32_eq(a->magic, NODE_MAGIC, "Bad magic");
- assert_u32_eq(b->magic, NODE_MAGIC, "Bad magic");
- return node_cmp(a, b);
- }
- typedef ph(node_t) heap_t;
- ph_gen(static, heap_, heap_t, node_t, link, node_cmp_magic);
- static void
- node_print(const node_t *node, unsigned depth) {
- unsigned i;
- node_t *leftmost_child, *sibling;
- for (i = 0; i < depth; i++) {
- malloc_printf("\t");
- }
- malloc_printf("%2"FMTu64"\n", node->key);
- leftmost_child = phn_lchild_get(node_t, link, node);
- if (leftmost_child == NULL) {
- return;
- }
- node_print(leftmost_child, depth + 1);
- for (sibling = phn_next_get(node_t, link, leftmost_child); sibling !=
- NULL; sibling = phn_next_get(node_t, link, sibling)) {
- node_print(sibling, depth + 1);
- }
- }
- static void
- heap_print(const heap_t *heap) {
- node_t *auxelm;
- malloc_printf("vvv heap %p vvv\n", heap);
- if (heap->ph_root == NULL) {
- goto label_return;
- }
- node_print(heap->ph_root, 0);
- for (auxelm = phn_next_get(node_t, link, heap->ph_root); auxelm != NULL;
- auxelm = phn_next_get(node_t, link, auxelm)) {
- assert_ptr_eq(phn_next_get(node_t, link, phn_prev_get(node_t,
- link, auxelm)), auxelm,
- "auxelm's prev doesn't link to auxelm");
- node_print(auxelm, 0);
- }
- label_return:
- malloc_printf("^^^ heap %p ^^^\n", heap);
- }
- static unsigned
- node_validate(const node_t *node, const node_t *parent) {
- unsigned nnodes = 1;
- node_t *leftmost_child, *sibling;
- if (parent != NULL) {
- assert_d_ge(node_cmp_magic(node, parent), 0,
- "Child is less than parent");
- }
- leftmost_child = phn_lchild_get(node_t, link, node);
- if (leftmost_child == NULL) {
- return nnodes;
- }
- assert_ptr_eq((void *)phn_prev_get(node_t, link, leftmost_child),
- (void *)node, "Leftmost child does not link to node");
- nnodes += node_validate(leftmost_child, node);
- for (sibling = phn_next_get(node_t, link, leftmost_child); sibling !=
- NULL; sibling = phn_next_get(node_t, link, sibling)) {
- assert_ptr_eq(phn_next_get(node_t, link, phn_prev_get(node_t,
- link, sibling)), sibling,
- "sibling's prev doesn't link to sibling");
- nnodes += node_validate(sibling, node);
- }
- return nnodes;
- }
- static unsigned
- heap_validate(const heap_t *heap) {
- unsigned nnodes = 0;
- node_t *auxelm;
- if (heap->ph_root == NULL) {
- goto label_return;
- }
- nnodes += node_validate(heap->ph_root, NULL);
- for (auxelm = phn_next_get(node_t, link, heap->ph_root); auxelm != NULL;
- auxelm = phn_next_get(node_t, link, auxelm)) {
- assert_ptr_eq(phn_next_get(node_t, link, phn_prev_get(node_t,
- link, auxelm)), auxelm,
- "auxelm's prev doesn't link to auxelm");
- nnodes += node_validate(auxelm, NULL);
- }
- label_return:
- if (false) {
- heap_print(heap);
- }
- return nnodes;
- }
- TEST_BEGIN(test_ph_empty) {
- heap_t heap;
- heap_new(&heap);
- assert_true(heap_empty(&heap), "Heap should be empty");
- assert_ptr_null(heap_first(&heap), "Unexpected node");
- assert_ptr_null(heap_any(&heap), "Unexpected node");
- }
- TEST_END
- static void
- node_remove(heap_t *heap, node_t *node) {
- heap_remove(heap, node);
- node->magic = 0;
- }
- static node_t *
- node_remove_first(heap_t *heap) {
- node_t *node = heap_remove_first(heap);
- node->magic = 0;
- return node;
- }
- static node_t *
- node_remove_any(heap_t *heap) {
- node_t *node = heap_remove_any(heap);
- node->magic = 0;
- return node;
- }
- TEST_BEGIN(test_ph_random) {
- #define NNODES 25
- #define NBAGS 250
- #define SEED 42
- sfmt_t *sfmt;
- uint64_t bag[NNODES];
- heap_t heap;
- node_t nodes[NNODES];
- unsigned i, j, k;
- sfmt = init_gen_rand(SEED);
- for (i = 0; i < NBAGS; i++) {
- switch (i) {
- case 0:
- /* Insert in order. */
- for (j = 0; j < NNODES; j++) {
- bag[j] = j;
- }
- break;
- case 1:
- /* Insert in reverse order. */
- for (j = 0; j < NNODES; j++) {
- bag[j] = NNODES - j - 1;
- }
- break;
- default:
- for (j = 0; j < NNODES; j++) {
- bag[j] = gen_rand64_range(sfmt, NNODES);
- }
- }
- for (j = 1; j <= NNODES; j++) {
- /* Initialize heap and nodes. */
- heap_new(&heap);
- assert_u_eq(heap_validate(&heap), 0,
- "Incorrect node count");
- for (k = 0; k < j; k++) {
- nodes[k].magic = NODE_MAGIC;
- nodes[k].key = bag[k];
- }
- /* Insert nodes. */
- for (k = 0; k < j; k++) {
- heap_insert(&heap, &nodes[k]);
- if (i % 13 == 12) {
- assert_ptr_not_null(heap_any(&heap),
- "Heap should not be empty");
- /* Trigger merging. */
- assert_ptr_not_null(heap_first(&heap),
- "Heap should not be empty");
- }
- assert_u_eq(heap_validate(&heap), k + 1,
- "Incorrect node count");
- }
- assert_false(heap_empty(&heap),
- "Heap should not be empty");
- /* Remove nodes. */
- switch (i % 6) {
- case 0:
- for (k = 0; k < j; k++) {
- assert_u_eq(heap_validate(&heap), j - k,
- "Incorrect node count");
- node_remove(&heap, &nodes[k]);
- assert_u_eq(heap_validate(&heap), j - k
- - 1, "Incorrect node count");
- }
- break;
- case 1:
- for (k = j; k > 0; k--) {
- node_remove(&heap, &nodes[k-1]);
- assert_u_eq(heap_validate(&heap), k - 1,
- "Incorrect node count");
- }
- break;
- case 2: {
- node_t *prev = NULL;
- for (k = 0; k < j; k++) {
- node_t *node = node_remove_first(&heap);
- assert_u_eq(heap_validate(&heap), j - k
- - 1, "Incorrect node count");
- if (prev != NULL) {
- assert_d_ge(node_cmp(node,
- prev), 0,
- "Bad removal order");
- }
- prev = node;
- }
- break;
- } case 3: {
- node_t *prev = NULL;
- for (k = 0; k < j; k++) {
- node_t *node = heap_first(&heap);
- assert_u_eq(heap_validate(&heap), j - k,
- "Incorrect node count");
- if (prev != NULL) {
- assert_d_ge(node_cmp(node,
- prev), 0,
- "Bad removal order");
- }
- node_remove(&heap, node);
- assert_u_eq(heap_validate(&heap), j - k
- - 1, "Incorrect node count");
- prev = node;
- }
- break;
- } case 4: {
- for (k = 0; k < j; k++) {
- node_remove_any(&heap);
- assert_u_eq(heap_validate(&heap), j - k
- - 1, "Incorrect node count");
- }
- break;
- } case 5: {
- for (k = 0; k < j; k++) {
- node_t *node = heap_any(&heap);
- assert_u_eq(heap_validate(&heap), j - k,
- "Incorrect node count");
- node_remove(&heap, node);
- assert_u_eq(heap_validate(&heap), j - k
- - 1, "Incorrect node count");
- }
- break;
- } default:
- not_reached();
- }
- assert_ptr_null(heap_first(&heap),
- "Heap should be empty");
- assert_ptr_null(heap_any(&heap),
- "Heap should be empty");
- assert_true(heap_empty(&heap), "Heap should be empty");
- }
- }
- fini_gen_rand(sfmt);
- #undef NNODES
- #undef SEED
- }
- TEST_END
- int
- main(void) {
- return test(
- test_ph_empty,
- test_ph_random);
- }
|