base.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. #include "test/jemalloc_test.h"
  2. #include "test/extent_hooks.h"
  3. static extent_hooks_t hooks_null = {
  4. extent_alloc_hook,
  5. NULL, /* dalloc */
  6. NULL, /* destroy */
  7. NULL, /* commit */
  8. NULL, /* decommit */
  9. NULL, /* purge_lazy */
  10. NULL, /* purge_forced */
  11. NULL, /* split */
  12. NULL /* merge */
  13. };
  14. static extent_hooks_t hooks_not_null = {
  15. extent_alloc_hook,
  16. extent_dalloc_hook,
  17. extent_destroy_hook,
  18. NULL, /* commit */
  19. extent_decommit_hook,
  20. extent_purge_lazy_hook,
  21. extent_purge_forced_hook,
  22. NULL, /* split */
  23. NULL /* merge */
  24. };
  25. TEST_BEGIN(test_base_hooks_default) {
  26. base_t *base;
  27. size_t allocated0, allocated1, resident, mapped, n_thp;
  28. tsdn_t *tsdn = tsd_tsdn(tsd_fetch());
  29. base = base_new(tsdn, 0, (extent_hooks_t *)&extent_hooks_default);
  30. if (config_stats) {
  31. base_stats_get(tsdn, base, &allocated0, &resident, &mapped,
  32. &n_thp);
  33. assert_zu_ge(allocated0, sizeof(base_t),
  34. "Base header should count as allocated");
  35. if (opt_metadata_thp == metadata_thp_always) {
  36. assert_zu_gt(n_thp, 0,
  37. "Base should have 1 THP at least.");
  38. }
  39. }
  40. assert_ptr_not_null(base_alloc(tsdn, base, 42, 1),
  41. "Unexpected base_alloc() failure");
  42. if (config_stats) {
  43. base_stats_get(tsdn, base, &allocated1, &resident, &mapped,
  44. &n_thp);
  45. assert_zu_ge(allocated1 - allocated0, 42,
  46. "At least 42 bytes were allocated by base_alloc()");
  47. }
  48. base_delete(tsdn, base);
  49. }
  50. TEST_END
  51. TEST_BEGIN(test_base_hooks_null) {
  52. extent_hooks_t hooks_orig;
  53. base_t *base;
  54. size_t allocated0, allocated1, resident, mapped, n_thp;
  55. extent_hooks_prep();
  56. try_dalloc = false;
  57. try_destroy = true;
  58. try_decommit = false;
  59. try_purge_lazy = false;
  60. try_purge_forced = false;
  61. memcpy(&hooks_orig, &hooks, sizeof(extent_hooks_t));
  62. memcpy(&hooks, &hooks_null, sizeof(extent_hooks_t));
  63. tsdn_t *tsdn = tsd_tsdn(tsd_fetch());
  64. base = base_new(tsdn, 0, &hooks);
  65. assert_ptr_not_null(base, "Unexpected base_new() failure");
  66. if (config_stats) {
  67. base_stats_get(tsdn, base, &allocated0, &resident, &mapped,
  68. &n_thp);
  69. assert_zu_ge(allocated0, sizeof(base_t),
  70. "Base header should count as allocated");
  71. if (opt_metadata_thp == metadata_thp_always) {
  72. assert_zu_gt(n_thp, 0,
  73. "Base should have 1 THP at least.");
  74. }
  75. }
  76. assert_ptr_not_null(base_alloc(tsdn, base, 42, 1),
  77. "Unexpected base_alloc() failure");
  78. if (config_stats) {
  79. base_stats_get(tsdn, base, &allocated1, &resident, &mapped,
  80. &n_thp);
  81. assert_zu_ge(allocated1 - allocated0, 42,
  82. "At least 42 bytes were allocated by base_alloc()");
  83. }
  84. base_delete(tsdn, base);
  85. memcpy(&hooks, &hooks_orig, sizeof(extent_hooks_t));
  86. }
  87. TEST_END
  88. TEST_BEGIN(test_base_hooks_not_null) {
  89. extent_hooks_t hooks_orig;
  90. base_t *base;
  91. void *p, *q, *r, *r_exp;
  92. extent_hooks_prep();
  93. try_dalloc = false;
  94. try_destroy = true;
  95. try_decommit = false;
  96. try_purge_lazy = false;
  97. try_purge_forced = false;
  98. memcpy(&hooks_orig, &hooks, sizeof(extent_hooks_t));
  99. memcpy(&hooks, &hooks_not_null, sizeof(extent_hooks_t));
  100. tsdn_t *tsdn = tsd_tsdn(tsd_fetch());
  101. did_alloc = false;
  102. base = base_new(tsdn, 0, &hooks);
  103. assert_ptr_not_null(base, "Unexpected base_new() failure");
  104. assert_true(did_alloc, "Expected alloc");
  105. /*
  106. * Check for tight packing at specified alignment under simple
  107. * conditions.
  108. */
  109. {
  110. const size_t alignments[] = {
  111. 1,
  112. QUANTUM,
  113. QUANTUM << 1,
  114. CACHELINE,
  115. CACHELINE << 1,
  116. };
  117. unsigned i;
  118. for (i = 0; i < sizeof(alignments) / sizeof(size_t); i++) {
  119. size_t alignment = alignments[i];
  120. size_t align_ceil = ALIGNMENT_CEILING(alignment,
  121. QUANTUM);
  122. p = base_alloc(tsdn, base, 1, alignment);
  123. assert_ptr_not_null(p,
  124. "Unexpected base_alloc() failure");
  125. assert_ptr_eq(p,
  126. (void *)(ALIGNMENT_CEILING((uintptr_t)p,
  127. alignment)), "Expected quantum alignment");
  128. q = base_alloc(tsdn, base, alignment, alignment);
  129. assert_ptr_not_null(q,
  130. "Unexpected base_alloc() failure");
  131. assert_ptr_eq((void *)((uintptr_t)p + align_ceil), q,
  132. "Minimal allocation should take up %zu bytes",
  133. align_ceil);
  134. r = base_alloc(tsdn, base, 1, alignment);
  135. assert_ptr_not_null(r,
  136. "Unexpected base_alloc() failure");
  137. assert_ptr_eq((void *)((uintptr_t)q + align_ceil), r,
  138. "Minimal allocation should take up %zu bytes",
  139. align_ceil);
  140. }
  141. }
  142. /*
  143. * Allocate an object that cannot fit in the first block, then verify
  144. * that the first block's remaining space is considered for subsequent
  145. * allocation.
  146. */
  147. assert_zu_ge(extent_bsize_get(&base->blocks->extent), QUANTUM,
  148. "Remainder insufficient for test");
  149. /* Use up all but one quantum of block. */
  150. while (extent_bsize_get(&base->blocks->extent) > QUANTUM) {
  151. p = base_alloc(tsdn, base, QUANTUM, QUANTUM);
  152. assert_ptr_not_null(p, "Unexpected base_alloc() failure");
  153. }
  154. r_exp = extent_addr_get(&base->blocks->extent);
  155. assert_zu_eq(base->extent_sn_next, 1, "One extant block expected");
  156. q = base_alloc(tsdn, base, QUANTUM + 1, QUANTUM);
  157. assert_ptr_not_null(q, "Unexpected base_alloc() failure");
  158. assert_ptr_ne(q, r_exp, "Expected allocation from new block");
  159. assert_zu_eq(base->extent_sn_next, 2, "Two extant blocks expected");
  160. r = base_alloc(tsdn, base, QUANTUM, QUANTUM);
  161. assert_ptr_not_null(r, "Unexpected base_alloc() failure");
  162. assert_ptr_eq(r, r_exp, "Expected allocation from first block");
  163. assert_zu_eq(base->extent_sn_next, 2, "Two extant blocks expected");
  164. /*
  165. * Check for proper alignment support when normal blocks are too small.
  166. */
  167. {
  168. const size_t alignments[] = {
  169. HUGEPAGE,
  170. HUGEPAGE << 1
  171. };
  172. unsigned i;
  173. for (i = 0; i < sizeof(alignments) / sizeof(size_t); i++) {
  174. size_t alignment = alignments[i];
  175. p = base_alloc(tsdn, base, QUANTUM, alignment);
  176. assert_ptr_not_null(p,
  177. "Unexpected base_alloc() failure");
  178. assert_ptr_eq(p,
  179. (void *)(ALIGNMENT_CEILING((uintptr_t)p,
  180. alignment)), "Expected %zu-byte alignment",
  181. alignment);
  182. }
  183. }
  184. called_dalloc = called_destroy = called_decommit = called_purge_lazy =
  185. called_purge_forced = false;
  186. base_delete(tsdn, base);
  187. assert_true(called_dalloc, "Expected dalloc call");
  188. assert_true(!called_destroy, "Unexpected destroy call");
  189. assert_true(called_decommit, "Expected decommit call");
  190. assert_true(called_purge_lazy, "Expected purge_lazy call");
  191. assert_true(called_purge_forced, "Expected purge_forced call");
  192. try_dalloc = true;
  193. try_destroy = true;
  194. try_decommit = true;
  195. try_purge_lazy = true;
  196. try_purge_forced = true;
  197. memcpy(&hooks, &hooks_orig, sizeof(extent_hooks_t));
  198. }
  199. TEST_END
  200. int
  201. main(void) {
  202. return test(
  203. test_base_hooks_default,
  204. test_base_hooks_null,
  205. test_base_hooks_not_null);
  206. }