2
0

ph.c 7.2 KB

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