xref: /netbsd-src/external/bsd/jemalloc.old/dist/test/unit/ph.c (revision 8e33eff89e26cf71871ead62f0d5063e1313c33a)
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