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