arena_reset.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. #ifndef ARENA_RESET_PROF_C_
  2. #include "test/jemalloc_test.h"
  3. #endif
  4. #include "jemalloc/internal/extent_mmap.h"
  5. #include "jemalloc/internal/rtree.h"
  6. #include "test/extent_hooks.h"
  7. static unsigned
  8. get_nsizes_impl(const char *cmd) {
  9. unsigned ret;
  10. size_t z;
  11. z = sizeof(unsigned);
  12. expect_d_eq(mallctl(cmd, (void *)&ret, &z, NULL, 0), 0,
  13. "Unexpected mallctl(\"%s\", ...) failure", cmd);
  14. return ret;
  15. }
  16. static unsigned
  17. get_nsmall(void) {
  18. return get_nsizes_impl("arenas.nbins");
  19. }
  20. static unsigned
  21. get_nlarge(void) {
  22. return get_nsizes_impl("arenas.nlextents");
  23. }
  24. static size_t
  25. get_size_impl(const char *cmd, size_t ind) {
  26. size_t ret;
  27. size_t z;
  28. size_t mib[4];
  29. size_t miblen = 4;
  30. z = sizeof(size_t);
  31. expect_d_eq(mallctlnametomib(cmd, mib, &miblen),
  32. 0, "Unexpected mallctlnametomib(\"%s\", ...) failure", cmd);
  33. mib[2] = ind;
  34. z = sizeof(size_t);
  35. expect_d_eq(mallctlbymib(mib, miblen, (void *)&ret, &z, NULL, 0),
  36. 0, "Unexpected mallctlbymib([\"%s\", %zu], ...) failure", cmd, ind);
  37. return ret;
  38. }
  39. static size_t
  40. get_small_size(size_t ind) {
  41. return get_size_impl("arenas.bin.0.size", ind);
  42. }
  43. static size_t
  44. get_large_size(size_t ind) {
  45. return get_size_impl("arenas.lextent.0.size", ind);
  46. }
  47. /* Like ivsalloc(), but safe to call on discarded allocations. */
  48. static size_t
  49. vsalloc(tsdn_t *tsdn, const void *ptr) {
  50. emap_full_alloc_ctx_t full_alloc_ctx;
  51. bool missing = emap_full_alloc_ctx_try_lookup(tsdn, &arena_emap_global,
  52. ptr, &full_alloc_ctx);
  53. if (missing) {
  54. return 0;
  55. }
  56. if (full_alloc_ctx.edata == NULL) {
  57. return 0;
  58. }
  59. if (edata_state_get(full_alloc_ctx.edata) != extent_state_active) {
  60. return 0;
  61. }
  62. if (full_alloc_ctx.szind == SC_NSIZES) {
  63. return 0;
  64. }
  65. return sz_index2size(full_alloc_ctx.szind);
  66. }
  67. static unsigned
  68. do_arena_create(extent_hooks_t *h) {
  69. unsigned arena_ind;
  70. size_t sz = sizeof(unsigned);
  71. expect_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz,
  72. (void *)(h != NULL ? &h : NULL), (h != NULL ? sizeof(h) : 0)), 0,
  73. "Unexpected mallctl() failure");
  74. return arena_ind;
  75. }
  76. static void
  77. do_arena_reset_pre(unsigned arena_ind, void ***ptrs, unsigned *nptrs) {
  78. #define NLARGE 32
  79. unsigned nsmall, nlarge, i;
  80. size_t sz;
  81. int flags;
  82. tsdn_t *tsdn;
  83. flags = MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE;
  84. nsmall = get_nsmall();
  85. nlarge = get_nlarge() > NLARGE ? NLARGE : get_nlarge();
  86. *nptrs = nsmall + nlarge;
  87. *ptrs = (void **)malloc(*nptrs * sizeof(void *));
  88. expect_ptr_not_null(*ptrs, "Unexpected malloc() failure");
  89. /* Allocate objects with a wide range of sizes. */
  90. for (i = 0; i < nsmall; i++) {
  91. sz = get_small_size(i);
  92. (*ptrs)[i] = mallocx(sz, flags);
  93. expect_ptr_not_null((*ptrs)[i],
  94. "Unexpected mallocx(%zu, %#x) failure", sz, flags);
  95. }
  96. for (i = 0; i < nlarge; i++) {
  97. sz = get_large_size(i);
  98. (*ptrs)[nsmall + i] = mallocx(sz, flags);
  99. expect_ptr_not_null((*ptrs)[i],
  100. "Unexpected mallocx(%zu, %#x) failure", sz, flags);
  101. }
  102. tsdn = tsdn_fetch();
  103. /* Verify allocations. */
  104. for (i = 0; i < *nptrs; i++) {
  105. expect_zu_gt(ivsalloc(tsdn, (*ptrs)[i]), 0,
  106. "Allocation should have queryable size");
  107. }
  108. }
  109. static void
  110. do_arena_reset_post(void **ptrs, unsigned nptrs, unsigned arena_ind) {
  111. tsdn_t *tsdn;
  112. unsigned i;
  113. tsdn = tsdn_fetch();
  114. if (have_background_thread) {
  115. malloc_mutex_lock(tsdn,
  116. &background_thread_info_get(arena_ind)->mtx);
  117. }
  118. /* Verify allocations no longer exist. */
  119. for (i = 0; i < nptrs; i++) {
  120. expect_zu_eq(vsalloc(tsdn, ptrs[i]), 0,
  121. "Allocation should no longer exist");
  122. }
  123. if (have_background_thread) {
  124. malloc_mutex_unlock(tsdn,
  125. &background_thread_info_get(arena_ind)->mtx);
  126. }
  127. free(ptrs);
  128. }
  129. static void
  130. do_arena_reset_destroy(const char *name, unsigned arena_ind) {
  131. size_t mib[3];
  132. size_t miblen;
  133. miblen = sizeof(mib)/sizeof(size_t);
  134. expect_d_eq(mallctlnametomib(name, mib, &miblen), 0,
  135. "Unexpected mallctlnametomib() failure");
  136. mib[1] = (size_t)arena_ind;
  137. expect_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0,
  138. "Unexpected mallctlbymib() failure");
  139. }
  140. static void
  141. do_arena_reset(unsigned arena_ind) {
  142. do_arena_reset_destroy("arena.0.reset", arena_ind);
  143. }
  144. static void
  145. do_arena_destroy(unsigned arena_ind) {
  146. do_arena_reset_destroy("arena.0.destroy", arena_ind);
  147. }
  148. TEST_BEGIN(test_arena_reset) {
  149. unsigned arena_ind;
  150. void **ptrs;
  151. unsigned nptrs;
  152. arena_ind = do_arena_create(NULL);
  153. do_arena_reset_pre(arena_ind, &ptrs, &nptrs);
  154. do_arena_reset(arena_ind);
  155. do_arena_reset_post(ptrs, nptrs, arena_ind);
  156. }
  157. TEST_END
  158. static bool
  159. arena_i_initialized(unsigned arena_ind, bool refresh) {
  160. bool initialized;
  161. size_t mib[3];
  162. size_t miblen, sz;
  163. if (refresh) {
  164. uint64_t epoch = 1;
  165. expect_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch,
  166. sizeof(epoch)), 0, "Unexpected mallctl() failure");
  167. }
  168. miblen = sizeof(mib)/sizeof(size_t);
  169. expect_d_eq(mallctlnametomib("arena.0.initialized", mib, &miblen), 0,
  170. "Unexpected mallctlnametomib() failure");
  171. mib[1] = (size_t)arena_ind;
  172. sz = sizeof(initialized);
  173. expect_d_eq(mallctlbymib(mib, miblen, (void *)&initialized, &sz, NULL,
  174. 0), 0, "Unexpected mallctlbymib() failure");
  175. return initialized;
  176. }
  177. TEST_BEGIN(test_arena_destroy_initial) {
  178. expect_false(arena_i_initialized(MALLCTL_ARENAS_DESTROYED, false),
  179. "Destroyed arena stats should not be initialized");
  180. }
  181. TEST_END
  182. TEST_BEGIN(test_arena_destroy_hooks_default) {
  183. unsigned arena_ind, arena_ind_another, arena_ind_prev;
  184. void **ptrs;
  185. unsigned nptrs;
  186. arena_ind = do_arena_create(NULL);
  187. do_arena_reset_pre(arena_ind, &ptrs, &nptrs);
  188. expect_false(arena_i_initialized(arena_ind, false),
  189. "Arena stats should not be initialized");
  190. expect_true(arena_i_initialized(arena_ind, true),
  191. "Arena stats should be initialized");
  192. /*
  193. * Create another arena before destroying one, to better verify arena
  194. * index reuse.
  195. */
  196. arena_ind_another = do_arena_create(NULL);
  197. do_arena_destroy(arena_ind);
  198. expect_false(arena_i_initialized(arena_ind, true),
  199. "Arena stats should not be initialized");
  200. expect_true(arena_i_initialized(MALLCTL_ARENAS_DESTROYED, false),
  201. "Destroyed arena stats should be initialized");
  202. do_arena_reset_post(ptrs, nptrs, arena_ind);
  203. arena_ind_prev = arena_ind;
  204. arena_ind = do_arena_create(NULL);
  205. do_arena_reset_pre(arena_ind, &ptrs, &nptrs);
  206. expect_u_eq(arena_ind, arena_ind_prev,
  207. "Arena index should have been recycled");
  208. do_arena_destroy(arena_ind);
  209. do_arena_reset_post(ptrs, nptrs, arena_ind);
  210. do_arena_destroy(arena_ind_another);
  211. /* Try arena.create with custom hooks. */
  212. size_t sz = sizeof(extent_hooks_t *);
  213. extent_hooks_t *a0_default_hooks;
  214. expect_d_eq(mallctl("arena.0.extent_hooks", (void *)&a0_default_hooks,
  215. &sz, NULL, 0), 0, "Unexpected mallctlnametomib() failure");
  216. /* Default impl; but wrapped as "customized". */
  217. extent_hooks_t new_hooks = *a0_default_hooks;
  218. extent_hooks_t *hook = &new_hooks;
  219. sz = sizeof(unsigned);
  220. expect_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz,
  221. (void *)&hook, sizeof(void *)), 0,
  222. "Unexpected mallctl() failure");
  223. do_arena_destroy(arena_ind);
  224. }
  225. TEST_END
  226. /*
  227. * Actually unmap extents, regardless of opt_retain, so that attempts to access
  228. * a destroyed arena's memory will segfault.
  229. */
  230. static bool
  231. extent_dalloc_unmap(extent_hooks_t *extent_hooks, void *addr, size_t size,
  232. bool committed, unsigned arena_ind) {
  233. TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, committed=%s, "
  234. "arena_ind=%u)\n", __func__, extent_hooks, addr, size, committed ?
  235. "true" : "false", arena_ind);
  236. expect_ptr_eq(extent_hooks, &hooks,
  237. "extent_hooks should be same as pointer used to set hooks");
  238. expect_ptr_eq(extent_hooks->dalloc, extent_dalloc_unmap,
  239. "Wrong hook function");
  240. called_dalloc = true;
  241. if (!try_dalloc) {
  242. return true;
  243. }
  244. did_dalloc = true;
  245. if (!maps_coalesce && opt_retain) {
  246. return true;
  247. }
  248. pages_unmap(addr, size);
  249. return false;
  250. }
  251. static extent_hooks_t hooks_orig;
  252. static extent_hooks_t hooks_unmap = {
  253. extent_alloc_hook,
  254. extent_dalloc_unmap, /* dalloc */
  255. extent_destroy_hook,
  256. extent_commit_hook,
  257. extent_decommit_hook,
  258. extent_purge_lazy_hook,
  259. extent_purge_forced_hook,
  260. extent_split_hook,
  261. extent_merge_hook
  262. };
  263. TEST_BEGIN(test_arena_destroy_hooks_unmap) {
  264. unsigned arena_ind;
  265. void **ptrs;
  266. unsigned nptrs;
  267. extent_hooks_prep();
  268. if (maps_coalesce) {
  269. try_decommit = false;
  270. }
  271. memcpy(&hooks_orig, &hooks, sizeof(extent_hooks_t));
  272. memcpy(&hooks, &hooks_unmap, sizeof(extent_hooks_t));
  273. did_alloc = false;
  274. arena_ind = do_arena_create(&hooks);
  275. do_arena_reset_pre(arena_ind, &ptrs, &nptrs);
  276. expect_true(did_alloc, "Expected alloc");
  277. expect_false(arena_i_initialized(arena_ind, false),
  278. "Arena stats should not be initialized");
  279. expect_true(arena_i_initialized(arena_ind, true),
  280. "Arena stats should be initialized");
  281. did_dalloc = false;
  282. do_arena_destroy(arena_ind);
  283. expect_true(did_dalloc, "Expected dalloc");
  284. expect_false(arena_i_initialized(arena_ind, true),
  285. "Arena stats should not be initialized");
  286. expect_true(arena_i_initialized(MALLCTL_ARENAS_DESTROYED, false),
  287. "Destroyed arena stats should be initialized");
  288. do_arena_reset_post(ptrs, nptrs, arena_ind);
  289. memcpy(&hooks, &hooks_orig, sizeof(extent_hooks_t));
  290. }
  291. TEST_END
  292. int
  293. main(void) {
  294. return test(
  295. test_arena_reset,
  296. test_arena_destroy_initial,
  297. test_arena_destroy_hooks_default,
  298. test_arena_destroy_hooks_unmap);
  299. }