hpdata.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. #include "test/jemalloc_test.h"
  2. #define HPDATA_ADDR ((void *)(10 * HUGEPAGE))
  3. #define HPDATA_AGE 123
  4. TEST_BEGIN(test_reserve_alloc) {
  5. hpdata_t hpdata;
  6. hpdata_init(&hpdata, HPDATA_ADDR, HPDATA_AGE);
  7. /* Allocating a page at a time, we should do first fit. */
  8. for (size_t i = 0; i < HUGEPAGE_PAGES; i++) {
  9. expect_true(hpdata_consistent(&hpdata), "");
  10. expect_zu_eq(HUGEPAGE_PAGES - i,
  11. hpdata_longest_free_range_get(&hpdata), "");
  12. void *alloc = hpdata_reserve_alloc(&hpdata, PAGE);
  13. expect_ptr_eq((char *)HPDATA_ADDR + i * PAGE, alloc, "");
  14. expect_true(hpdata_consistent(&hpdata), "");
  15. }
  16. expect_true(hpdata_consistent(&hpdata), "");
  17. expect_zu_eq(0, hpdata_longest_free_range_get(&hpdata), "");
  18. /*
  19. * Build up a bigger free-range, 2 pages at a time, until we've got 6
  20. * adjacent free pages total. Pages 8-13 should be unreserved after
  21. * this.
  22. */
  23. hpdata_unreserve(&hpdata, (char *)HPDATA_ADDR + 10 * PAGE, 2 * PAGE);
  24. expect_true(hpdata_consistent(&hpdata), "");
  25. expect_zu_eq(2, hpdata_longest_free_range_get(&hpdata), "");
  26. hpdata_unreserve(&hpdata, (char *)HPDATA_ADDR + 12 * PAGE, 2 * PAGE);
  27. expect_true(hpdata_consistent(&hpdata), "");
  28. expect_zu_eq(4, hpdata_longest_free_range_get(&hpdata), "");
  29. hpdata_unreserve(&hpdata, (char *)HPDATA_ADDR + 8 * PAGE, 2 * PAGE);
  30. expect_true(hpdata_consistent(&hpdata), "");
  31. expect_zu_eq(6, hpdata_longest_free_range_get(&hpdata), "");
  32. /*
  33. * Leave page 14 reserved, but free page 15 (this test the case where
  34. * unreserving combines two ranges).
  35. */
  36. hpdata_unreserve(&hpdata, (char *)HPDATA_ADDR + 15 * PAGE, PAGE);
  37. /*
  38. * Longest free range shouldn't change; we've got a free range of size
  39. * 6, then a reserved page, then another free range.
  40. */
  41. expect_true(hpdata_consistent(&hpdata), "");
  42. expect_zu_eq(6, hpdata_longest_free_range_get(&hpdata), "");
  43. /* After freeing page 14, the two ranges get combined. */
  44. hpdata_unreserve(&hpdata, (char *)HPDATA_ADDR + 14 * PAGE, PAGE);
  45. expect_true(hpdata_consistent(&hpdata), "");
  46. expect_zu_eq(8, hpdata_longest_free_range_get(&hpdata), "");
  47. }
  48. TEST_END
  49. TEST_BEGIN(test_purge_simple) {
  50. hpdata_t hpdata;
  51. hpdata_init(&hpdata, HPDATA_ADDR, HPDATA_AGE);
  52. void *alloc = hpdata_reserve_alloc(&hpdata, HUGEPAGE_PAGES / 2 * PAGE);
  53. expect_ptr_eq(alloc, HPDATA_ADDR, "");
  54. /* Create HUGEPAGE_PAGES / 4 dirty inactive pages at the beginning. */
  55. hpdata_unreserve(&hpdata, alloc, HUGEPAGE_PAGES / 4 * PAGE);
  56. expect_zu_eq(hpdata_ntouched_get(&hpdata), HUGEPAGE_PAGES / 2, "");
  57. hpdata_alloc_allowed_set(&hpdata, false);
  58. hpdata_purge_state_t purge_state;
  59. size_t to_purge = hpdata_purge_begin(&hpdata, &purge_state);
  60. expect_zu_eq(HUGEPAGE_PAGES / 4, to_purge, "");
  61. void *purge_addr;
  62. size_t purge_size;
  63. bool got_result = hpdata_purge_next(&hpdata, &purge_state, &purge_addr,
  64. &purge_size);
  65. expect_true(got_result, "");
  66. expect_ptr_eq(HPDATA_ADDR, purge_addr, "");
  67. expect_zu_eq(HUGEPAGE_PAGES / 4 * PAGE, purge_size, "");
  68. got_result = hpdata_purge_next(&hpdata, &purge_state, &purge_addr,
  69. &purge_size);
  70. expect_false(got_result, "Unexpected additional purge range: "
  71. "extent at %p of size %zu", purge_addr, purge_size);
  72. hpdata_purge_end(&hpdata, &purge_state);
  73. expect_zu_eq(hpdata_ntouched_get(&hpdata), HUGEPAGE_PAGES / 4, "");
  74. }
  75. TEST_END
  76. /*
  77. * We only test intervening dalloc's not intervening allocs; the latter are
  78. * disallowed as a purging precondition (because they interfere with purging
  79. * across a retained extent, saving a purge call).
  80. */
  81. TEST_BEGIN(test_purge_intervening_dalloc) {
  82. hpdata_t hpdata;
  83. hpdata_init(&hpdata, HPDATA_ADDR, HPDATA_AGE);
  84. /* Allocate the first 3/4 of the pages. */
  85. void *alloc = hpdata_reserve_alloc(&hpdata, 3 * HUGEPAGE_PAGES / 4 * PAGE);
  86. expect_ptr_eq(alloc, HPDATA_ADDR, "");
  87. /* Free the first 1/4 and the third 1/4 of the pages. */
  88. hpdata_unreserve(&hpdata, alloc, HUGEPAGE_PAGES / 4 * PAGE);
  89. hpdata_unreserve(&hpdata,
  90. (void *)((uintptr_t)alloc + 2 * HUGEPAGE_PAGES / 4 * PAGE),
  91. HUGEPAGE_PAGES / 4 * PAGE);
  92. expect_zu_eq(hpdata_ntouched_get(&hpdata), 3 * HUGEPAGE_PAGES / 4, "");
  93. hpdata_alloc_allowed_set(&hpdata, false);
  94. hpdata_purge_state_t purge_state;
  95. size_t to_purge = hpdata_purge_begin(&hpdata, &purge_state);
  96. expect_zu_eq(HUGEPAGE_PAGES / 2, to_purge, "");
  97. void *purge_addr;
  98. size_t purge_size;
  99. /* First purge. */
  100. bool got_result = hpdata_purge_next(&hpdata, &purge_state, &purge_addr,
  101. &purge_size);
  102. expect_true(got_result, "");
  103. expect_ptr_eq(HPDATA_ADDR, purge_addr, "");
  104. expect_zu_eq(HUGEPAGE_PAGES / 4 * PAGE, purge_size, "");
  105. /* Deallocate the second 1/4 before the second purge occurs. */
  106. hpdata_unreserve(&hpdata,
  107. (void *)((uintptr_t)alloc + 1 * HUGEPAGE_PAGES / 4 * PAGE),
  108. HUGEPAGE_PAGES / 4 * PAGE);
  109. /* Now continue purging. */
  110. got_result = hpdata_purge_next(&hpdata, &purge_state, &purge_addr,
  111. &purge_size);
  112. expect_true(got_result, "");
  113. expect_ptr_eq(
  114. (void *)((uintptr_t)alloc + 2 * HUGEPAGE_PAGES / 4 * PAGE),
  115. purge_addr, "");
  116. expect_zu_ge(HUGEPAGE_PAGES / 4 * PAGE, purge_size, "");
  117. got_result = hpdata_purge_next(&hpdata, &purge_state, &purge_addr,
  118. &purge_size);
  119. expect_false(got_result, "Unexpected additional purge range: "
  120. "extent at %p of size %zu", purge_addr, purge_size);
  121. hpdata_purge_end(&hpdata, &purge_state);
  122. expect_zu_eq(hpdata_ntouched_get(&hpdata), HUGEPAGE_PAGES / 4, "");
  123. }
  124. TEST_END
  125. TEST_BEGIN(test_purge_over_retained) {
  126. void *purge_addr;
  127. size_t purge_size;
  128. hpdata_t hpdata;
  129. hpdata_init(&hpdata, HPDATA_ADDR, HPDATA_AGE);
  130. /* Allocate the first 3/4 of the pages. */
  131. void *alloc = hpdata_reserve_alloc(&hpdata, 3 * HUGEPAGE_PAGES / 4 * PAGE);
  132. expect_ptr_eq(alloc, HPDATA_ADDR, "");
  133. /* Free the second quarter. */
  134. void *second_quarter =
  135. (void *)((uintptr_t)alloc + HUGEPAGE_PAGES / 4 * PAGE);
  136. hpdata_unreserve(&hpdata, second_quarter, HUGEPAGE_PAGES / 4 * PAGE);
  137. expect_zu_eq(hpdata_ntouched_get(&hpdata), 3 * HUGEPAGE_PAGES / 4, "");
  138. /* Purge the second quarter. */
  139. hpdata_alloc_allowed_set(&hpdata, false);
  140. hpdata_purge_state_t purge_state;
  141. size_t to_purge_dirty = hpdata_purge_begin(&hpdata, &purge_state);
  142. expect_zu_eq(HUGEPAGE_PAGES / 4, to_purge_dirty, "");
  143. bool got_result = hpdata_purge_next(&hpdata, &purge_state, &purge_addr,
  144. &purge_size);
  145. expect_true(got_result, "");
  146. expect_ptr_eq(second_quarter, purge_addr, "");
  147. expect_zu_eq(HUGEPAGE_PAGES / 4 * PAGE, purge_size, "");
  148. got_result = hpdata_purge_next(&hpdata, &purge_state, &purge_addr,
  149. &purge_size);
  150. expect_false(got_result, "Unexpected additional purge range: "
  151. "extent at %p of size %zu", purge_addr, purge_size);
  152. hpdata_purge_end(&hpdata, &purge_state);
  153. expect_zu_eq(hpdata_ntouched_get(&hpdata), HUGEPAGE_PAGES / 2, "");
  154. /* Free the first and third quarter. */
  155. hpdata_unreserve(&hpdata, HPDATA_ADDR, HUGEPAGE_PAGES / 4 * PAGE);
  156. hpdata_unreserve(&hpdata,
  157. (void *)((uintptr_t)alloc + 2 * HUGEPAGE_PAGES / 4 * PAGE),
  158. HUGEPAGE_PAGES / 4 * PAGE);
  159. /*
  160. * Purge again. The second quarter is retained, so we can safely
  161. * re-purge it. We expect a single purge of 3/4 of the hugepage,
  162. * purging half its pages.
  163. */
  164. to_purge_dirty = hpdata_purge_begin(&hpdata, &purge_state);
  165. expect_zu_eq(HUGEPAGE_PAGES / 2, to_purge_dirty, "");
  166. got_result = hpdata_purge_next(&hpdata, &purge_state, &purge_addr,
  167. &purge_size);
  168. expect_true(got_result, "");
  169. expect_ptr_eq(HPDATA_ADDR, purge_addr, "");
  170. expect_zu_eq(3 * HUGEPAGE_PAGES / 4 * PAGE, purge_size, "");
  171. got_result = hpdata_purge_next(&hpdata, &purge_state, &purge_addr,
  172. &purge_size);
  173. expect_false(got_result, "Unexpected additional purge range: "
  174. "extent at %p of size %zu", purge_addr, purge_size);
  175. hpdata_purge_end(&hpdata, &purge_state);
  176. expect_zu_eq(hpdata_ntouched_get(&hpdata), 0, "");
  177. }
  178. TEST_END
  179. TEST_BEGIN(test_hugify) {
  180. hpdata_t hpdata;
  181. hpdata_init(&hpdata, HPDATA_ADDR, HPDATA_AGE);
  182. void *alloc = hpdata_reserve_alloc(&hpdata, HUGEPAGE / 2);
  183. expect_ptr_eq(alloc, HPDATA_ADDR, "");
  184. expect_zu_eq(HUGEPAGE_PAGES / 2, hpdata_ntouched_get(&hpdata), "");
  185. hpdata_hugify(&hpdata);
  186. /* Hugeifying should have increased the dirty page count. */
  187. expect_zu_eq(HUGEPAGE_PAGES, hpdata_ntouched_get(&hpdata), "");
  188. }
  189. TEST_END
  190. int main(void) {
  191. return test_no_reentrancy(
  192. test_reserve_alloc,
  193. test_purge_simple,
  194. test_purge_intervening_dalloc,
  195. test_purge_over_retained,
  196. test_hugify);
  197. }