extent.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. #include "test/jemalloc_test.h"
  2. #include "test/extent_hooks.h"
  3. #include "jemalloc/internal/arena_types.h"
  4. static void
  5. test_extent_body(unsigned arena_ind) {
  6. void *p;
  7. size_t large0, large1, large2, sz;
  8. size_t purge_mib[3];
  9. size_t purge_miblen;
  10. int flags;
  11. bool xallocx_success_a, xallocx_success_b, xallocx_success_c;
  12. flags = MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE;
  13. /* Get large size classes. */
  14. sz = sizeof(size_t);
  15. expect_d_eq(mallctl("arenas.lextent.0.size", (void *)&large0, &sz, NULL,
  16. 0), 0, "Unexpected arenas.lextent.0.size failure");
  17. expect_d_eq(mallctl("arenas.lextent.1.size", (void *)&large1, &sz, NULL,
  18. 0), 0, "Unexpected arenas.lextent.1.size failure");
  19. expect_d_eq(mallctl("arenas.lextent.2.size", (void *)&large2, &sz, NULL,
  20. 0), 0, "Unexpected arenas.lextent.2.size failure");
  21. /* Test dalloc/decommit/purge cascade. */
  22. purge_miblen = sizeof(purge_mib)/sizeof(size_t);
  23. expect_d_eq(mallctlnametomib("arena.0.purge", purge_mib, &purge_miblen),
  24. 0, "Unexpected mallctlnametomib() failure");
  25. purge_mib[1] = (size_t)arena_ind;
  26. called_alloc = false;
  27. try_alloc = true;
  28. try_dalloc = false;
  29. try_decommit = false;
  30. p = mallocx(large0 * 2, flags);
  31. expect_ptr_not_null(p, "Unexpected mallocx() error");
  32. expect_true(called_alloc, "Expected alloc call");
  33. called_dalloc = false;
  34. called_decommit = false;
  35. did_purge_lazy = false;
  36. did_purge_forced = false;
  37. called_split = false;
  38. xallocx_success_a = (xallocx(p, large0, 0, flags) == large0);
  39. expect_d_eq(mallctlbymib(purge_mib, purge_miblen, NULL, NULL, NULL, 0),
  40. 0, "Unexpected arena.%u.purge error", arena_ind);
  41. if (xallocx_success_a) {
  42. expect_true(called_dalloc, "Expected dalloc call");
  43. expect_true(called_decommit, "Expected decommit call");
  44. expect_true(did_purge_lazy || did_purge_forced,
  45. "Expected purge");
  46. expect_true(called_split, "Expected split call");
  47. }
  48. dallocx(p, flags);
  49. try_dalloc = true;
  50. /* Test decommit/commit and observe split/merge. */
  51. try_dalloc = false;
  52. try_decommit = true;
  53. p = mallocx(large0 * 2, flags);
  54. expect_ptr_not_null(p, "Unexpected mallocx() error");
  55. did_decommit = false;
  56. did_commit = false;
  57. called_split = false;
  58. did_split = false;
  59. did_merge = false;
  60. xallocx_success_b = (xallocx(p, large0, 0, flags) == large0);
  61. expect_d_eq(mallctlbymib(purge_mib, purge_miblen, NULL, NULL, NULL, 0),
  62. 0, "Unexpected arena.%u.purge error", arena_ind);
  63. if (xallocx_success_b) {
  64. expect_true(did_split, "Expected split");
  65. }
  66. xallocx_success_c = (xallocx(p, large0 * 2, 0, flags) == large0 * 2);
  67. if (did_split) {
  68. expect_b_eq(did_decommit, did_commit,
  69. "Expected decommit/commit match");
  70. }
  71. if (xallocx_success_b && xallocx_success_c) {
  72. expect_true(did_merge, "Expected merge");
  73. }
  74. dallocx(p, flags);
  75. try_dalloc = true;
  76. try_decommit = false;
  77. /* Make sure non-large allocation succeeds. */
  78. p = mallocx(42, flags);
  79. expect_ptr_not_null(p, "Unexpected mallocx() error");
  80. dallocx(p, flags);
  81. }
  82. static void
  83. test_manual_hook_auto_arena(void) {
  84. unsigned narenas;
  85. size_t old_size, new_size, sz;
  86. size_t hooks_mib[3];
  87. size_t hooks_miblen;
  88. extent_hooks_t *new_hooks, *old_hooks;
  89. extent_hooks_prep();
  90. sz = sizeof(unsigned);
  91. /* Get number of auto arenas. */
  92. expect_d_eq(mallctl("opt.narenas", (void *)&narenas, &sz, NULL, 0),
  93. 0, "Unexpected mallctl() failure");
  94. if (narenas == 1) {
  95. return;
  96. }
  97. /* Install custom extent hooks on arena 1 (might not be initialized). */
  98. hooks_miblen = sizeof(hooks_mib)/sizeof(size_t);
  99. expect_d_eq(mallctlnametomib("arena.0.extent_hooks", hooks_mib,
  100. &hooks_miblen), 0, "Unexpected mallctlnametomib() failure");
  101. hooks_mib[1] = 1;
  102. old_size = sizeof(extent_hooks_t *);
  103. new_hooks = &hooks;
  104. new_size = sizeof(extent_hooks_t *);
  105. expect_d_eq(mallctlbymib(hooks_mib, hooks_miblen, (void *)&old_hooks,
  106. &old_size, (void *)&new_hooks, new_size), 0,
  107. "Unexpected extent_hooks error");
  108. static bool auto_arena_created = false;
  109. if (old_hooks != &hooks) {
  110. expect_b_eq(auto_arena_created, false,
  111. "Expected auto arena 1 created only once.");
  112. auto_arena_created = true;
  113. }
  114. }
  115. static void
  116. test_manual_hook_body(void) {
  117. unsigned arena_ind;
  118. size_t old_size, new_size, sz;
  119. size_t hooks_mib[3];
  120. size_t hooks_miblen;
  121. extent_hooks_t *new_hooks, *old_hooks;
  122. extent_hooks_prep();
  123. sz = sizeof(unsigned);
  124. expect_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, NULL, 0),
  125. 0, "Unexpected mallctl() failure");
  126. /* Install custom extent hooks. */
  127. hooks_miblen = sizeof(hooks_mib)/sizeof(size_t);
  128. expect_d_eq(mallctlnametomib("arena.0.extent_hooks", hooks_mib,
  129. &hooks_miblen), 0, "Unexpected mallctlnametomib() failure");
  130. hooks_mib[1] = (size_t)arena_ind;
  131. old_size = sizeof(extent_hooks_t *);
  132. new_hooks = &hooks;
  133. new_size = sizeof(extent_hooks_t *);
  134. expect_d_eq(mallctlbymib(hooks_mib, hooks_miblen, (void *)&old_hooks,
  135. &old_size, (void *)&new_hooks, new_size), 0,
  136. "Unexpected extent_hooks error");
  137. expect_ptr_ne(old_hooks->alloc, extent_alloc_hook,
  138. "Unexpected extent_hooks error");
  139. expect_ptr_ne(old_hooks->dalloc, extent_dalloc_hook,
  140. "Unexpected extent_hooks error");
  141. expect_ptr_ne(old_hooks->commit, extent_commit_hook,
  142. "Unexpected extent_hooks error");
  143. expect_ptr_ne(old_hooks->decommit, extent_decommit_hook,
  144. "Unexpected extent_hooks error");
  145. expect_ptr_ne(old_hooks->purge_lazy, extent_purge_lazy_hook,
  146. "Unexpected extent_hooks error");
  147. expect_ptr_ne(old_hooks->purge_forced, extent_purge_forced_hook,
  148. "Unexpected extent_hooks error");
  149. expect_ptr_ne(old_hooks->split, extent_split_hook,
  150. "Unexpected extent_hooks error");
  151. expect_ptr_ne(old_hooks->merge, extent_merge_hook,
  152. "Unexpected extent_hooks error");
  153. if (!is_background_thread_enabled()) {
  154. test_extent_body(arena_ind);
  155. }
  156. /* Restore extent hooks. */
  157. expect_d_eq(mallctlbymib(hooks_mib, hooks_miblen, NULL, NULL,
  158. (void *)&old_hooks, new_size), 0, "Unexpected extent_hooks error");
  159. expect_d_eq(mallctlbymib(hooks_mib, hooks_miblen, (void *)&old_hooks,
  160. &old_size, NULL, 0), 0, "Unexpected extent_hooks error");
  161. expect_ptr_eq(old_hooks, default_hooks, "Unexpected extent_hooks error");
  162. expect_ptr_eq(old_hooks->alloc, default_hooks->alloc,
  163. "Unexpected extent_hooks error");
  164. expect_ptr_eq(old_hooks->dalloc, default_hooks->dalloc,
  165. "Unexpected extent_hooks error");
  166. expect_ptr_eq(old_hooks->commit, default_hooks->commit,
  167. "Unexpected extent_hooks error");
  168. expect_ptr_eq(old_hooks->decommit, default_hooks->decommit,
  169. "Unexpected extent_hooks error");
  170. expect_ptr_eq(old_hooks->purge_lazy, default_hooks->purge_lazy,
  171. "Unexpected extent_hooks error");
  172. expect_ptr_eq(old_hooks->purge_forced, default_hooks->purge_forced,
  173. "Unexpected extent_hooks error");
  174. expect_ptr_eq(old_hooks->split, default_hooks->split,
  175. "Unexpected extent_hooks error");
  176. expect_ptr_eq(old_hooks->merge, default_hooks->merge,
  177. "Unexpected extent_hooks error");
  178. }
  179. TEST_BEGIN(test_extent_manual_hook) {
  180. test_manual_hook_auto_arena();
  181. test_manual_hook_body();
  182. /* Test failure paths. */
  183. try_split = false;
  184. test_manual_hook_body();
  185. try_merge = false;
  186. test_manual_hook_body();
  187. try_purge_lazy = false;
  188. try_purge_forced = false;
  189. test_manual_hook_body();
  190. try_split = try_merge = try_purge_lazy = try_purge_forced = true;
  191. }
  192. TEST_END
  193. TEST_BEGIN(test_extent_auto_hook) {
  194. unsigned arena_ind;
  195. size_t new_size, sz;
  196. extent_hooks_t *new_hooks;
  197. extent_hooks_prep();
  198. sz = sizeof(unsigned);
  199. new_hooks = &hooks;
  200. new_size = sizeof(extent_hooks_t *);
  201. expect_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz,
  202. (void *)&new_hooks, new_size), 0, "Unexpected mallctl() failure");
  203. test_skip_if(is_background_thread_enabled());
  204. test_extent_body(arena_ind);
  205. }
  206. TEST_END
  207. static void
  208. test_arenas_create_ext_base(arena_config_t config,
  209. bool expect_hook_data, bool expect_hook_metadata)
  210. {
  211. unsigned arena, arena1;
  212. void *ptr;
  213. size_t sz = sizeof(unsigned);
  214. extent_hooks_prep();
  215. called_alloc = false;
  216. expect_d_eq(mallctl("experimental.arenas_create_ext",
  217. (void *)&arena, &sz, &config, sizeof(arena_config_t)), 0,
  218. "Unexpected mallctl() failure");
  219. expect_b_eq(called_alloc, expect_hook_metadata,
  220. "expected hook metadata alloc mismatch");
  221. called_alloc = false;
  222. ptr = mallocx(42, MALLOCX_ARENA(arena) | MALLOCX_TCACHE_NONE);
  223. expect_b_eq(called_alloc, expect_hook_data,
  224. "expected hook data alloc mismatch");
  225. expect_ptr_not_null(ptr, "Unexpected mallocx() failure");
  226. expect_d_eq(mallctl("arenas.lookup", &arena1, &sz, &ptr, sizeof(ptr)),
  227. 0, "Unexpected mallctl() failure");
  228. expect_u_eq(arena, arena1, "Unexpected arena index");
  229. dallocx(ptr, 0);
  230. }
  231. TEST_BEGIN(test_arenas_create_ext_with_ehooks_no_metadata) {
  232. arena_config_t config;
  233. config.extent_hooks = &hooks;
  234. config.metadata_use_hooks = false;
  235. test_arenas_create_ext_base(config, true, false);
  236. }
  237. TEST_END
  238. TEST_BEGIN(test_arenas_create_ext_with_ehooks_with_metadata) {
  239. arena_config_t config;
  240. config.extent_hooks = &hooks;
  241. config.metadata_use_hooks = true;
  242. test_arenas_create_ext_base(config, true, true);
  243. }
  244. TEST_END
  245. int
  246. main(void) {
  247. return test(
  248. test_extent_manual_hook,
  249. test_extent_auto_hook,
  250. test_arenas_create_ext_with_ehooks_no_metadata,
  251. test_arenas_create_ext_with_ehooks_with_metadata);
  252. }