stats.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. #include "test/jemalloc_test.h"
  2. #define STRINGIFY_HELPER(x) #x
  3. #define STRINGIFY(x) STRINGIFY_HELPER(x)
  4. TEST_BEGIN(test_stats_summary) {
  5. size_t sz, allocated, active, resident, mapped;
  6. int expected = config_stats ? 0 : ENOENT;
  7. sz = sizeof(size_t);
  8. expect_d_eq(mallctl("stats.allocated", (void *)&allocated, &sz, NULL,
  9. 0), expected, "Unexpected mallctl() result");
  10. expect_d_eq(mallctl("stats.active", (void *)&active, &sz, NULL, 0),
  11. expected, "Unexpected mallctl() result");
  12. expect_d_eq(mallctl("stats.resident", (void *)&resident, &sz, NULL, 0),
  13. expected, "Unexpected mallctl() result");
  14. expect_d_eq(mallctl("stats.mapped", (void *)&mapped, &sz, NULL, 0),
  15. expected, "Unexpected mallctl() result");
  16. if (config_stats) {
  17. expect_zu_le(allocated, active,
  18. "allocated should be no larger than active");
  19. expect_zu_lt(active, resident,
  20. "active should be less than resident");
  21. expect_zu_lt(active, mapped,
  22. "active should be less than mapped");
  23. }
  24. }
  25. TEST_END
  26. TEST_BEGIN(test_stats_large) {
  27. void *p;
  28. uint64_t epoch;
  29. size_t allocated;
  30. uint64_t nmalloc, ndalloc, nrequests;
  31. size_t sz;
  32. int expected = config_stats ? 0 : ENOENT;
  33. p = mallocx(SC_SMALL_MAXCLASS + 1, MALLOCX_ARENA(0));
  34. expect_ptr_not_null(p, "Unexpected mallocx() failure");
  35. expect_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)),
  36. 0, "Unexpected mallctl() failure");
  37. sz = sizeof(size_t);
  38. expect_d_eq(mallctl("stats.arenas.0.large.allocated",
  39. (void *)&allocated, &sz, NULL, 0), expected,
  40. "Unexpected mallctl() result");
  41. sz = sizeof(uint64_t);
  42. expect_d_eq(mallctl("stats.arenas.0.large.nmalloc", (void *)&nmalloc,
  43. &sz, NULL, 0), expected, "Unexpected mallctl() result");
  44. expect_d_eq(mallctl("stats.arenas.0.large.ndalloc", (void *)&ndalloc,
  45. &sz, NULL, 0), expected, "Unexpected mallctl() result");
  46. expect_d_eq(mallctl("stats.arenas.0.large.nrequests",
  47. (void *)&nrequests, &sz, NULL, 0), expected,
  48. "Unexpected mallctl() result");
  49. if (config_stats) {
  50. expect_zu_gt(allocated, 0,
  51. "allocated should be greater than zero");
  52. expect_u64_ge(nmalloc, ndalloc,
  53. "nmalloc should be at least as large as ndalloc");
  54. expect_u64_le(nmalloc, nrequests,
  55. "nmalloc should no larger than nrequests");
  56. }
  57. dallocx(p, 0);
  58. }
  59. TEST_END
  60. TEST_BEGIN(test_stats_arenas_summary) {
  61. void *little, *large;
  62. uint64_t epoch;
  63. size_t sz;
  64. int expected = config_stats ? 0 : ENOENT;
  65. size_t mapped;
  66. uint64_t dirty_npurge, dirty_nmadvise, dirty_purged;
  67. uint64_t muzzy_npurge, muzzy_nmadvise, muzzy_purged;
  68. little = mallocx(SC_SMALL_MAXCLASS, MALLOCX_ARENA(0));
  69. expect_ptr_not_null(little, "Unexpected mallocx() failure");
  70. large = mallocx((1U << SC_LG_LARGE_MINCLASS),
  71. MALLOCX_ARENA(0));
  72. expect_ptr_not_null(large, "Unexpected mallocx() failure");
  73. dallocx(little, 0);
  74. dallocx(large, 0);
  75. expect_d_eq(mallctl("thread.tcache.flush", NULL, NULL, NULL, 0),
  76. opt_tcache ? 0 : EFAULT, "Unexpected mallctl() result");
  77. expect_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0,
  78. "Unexpected mallctl() failure");
  79. expect_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)),
  80. 0, "Unexpected mallctl() failure");
  81. sz = sizeof(size_t);
  82. expect_d_eq(mallctl("stats.arenas.0.mapped", (void *)&mapped, &sz, NULL,
  83. 0), expected, "Unexepected mallctl() result");
  84. sz = sizeof(uint64_t);
  85. expect_d_eq(mallctl("stats.arenas.0.dirty_npurge",
  86. (void *)&dirty_npurge, &sz, NULL, 0), expected,
  87. "Unexepected mallctl() result");
  88. expect_d_eq(mallctl("stats.arenas.0.dirty_nmadvise",
  89. (void *)&dirty_nmadvise, &sz, NULL, 0), expected,
  90. "Unexepected mallctl() result");
  91. expect_d_eq(mallctl("stats.arenas.0.dirty_purged",
  92. (void *)&dirty_purged, &sz, NULL, 0), expected,
  93. "Unexepected mallctl() result");
  94. expect_d_eq(mallctl("stats.arenas.0.muzzy_npurge",
  95. (void *)&muzzy_npurge, &sz, NULL, 0), expected,
  96. "Unexepected mallctl() result");
  97. expect_d_eq(mallctl("stats.arenas.0.muzzy_nmadvise",
  98. (void *)&muzzy_nmadvise, &sz, NULL, 0), expected,
  99. "Unexepected mallctl() result");
  100. expect_d_eq(mallctl("stats.arenas.0.muzzy_purged",
  101. (void *)&muzzy_purged, &sz, NULL, 0), expected,
  102. "Unexepected mallctl() result");
  103. if (config_stats) {
  104. if (!is_background_thread_enabled() && !opt_hpa) {
  105. expect_u64_gt(dirty_npurge + muzzy_npurge, 0,
  106. "At least one purge should have occurred");
  107. }
  108. expect_u64_le(dirty_nmadvise, dirty_purged,
  109. "dirty_nmadvise should be no greater than dirty_purged");
  110. expect_u64_le(muzzy_nmadvise, muzzy_purged,
  111. "muzzy_nmadvise should be no greater than muzzy_purged");
  112. }
  113. }
  114. TEST_END
  115. void *
  116. thd_start(void *arg) {
  117. return NULL;
  118. }
  119. static void
  120. no_lazy_lock(void) {
  121. thd_t thd;
  122. thd_create(&thd, thd_start, NULL);
  123. thd_join(thd, NULL);
  124. }
  125. TEST_BEGIN(test_stats_arenas_small) {
  126. void *p;
  127. size_t sz, allocated;
  128. uint64_t epoch, nmalloc, ndalloc, nrequests;
  129. int expected = config_stats ? 0 : ENOENT;
  130. no_lazy_lock(); /* Lazy locking would dodge tcache testing. */
  131. p = mallocx(SC_SMALL_MAXCLASS, MALLOCX_ARENA(0));
  132. expect_ptr_not_null(p, "Unexpected mallocx() failure");
  133. expect_d_eq(mallctl("thread.tcache.flush", NULL, NULL, NULL, 0),
  134. opt_tcache ? 0 : EFAULT, "Unexpected mallctl() result");
  135. expect_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)),
  136. 0, "Unexpected mallctl() failure");
  137. sz = sizeof(size_t);
  138. expect_d_eq(mallctl("stats.arenas.0.small.allocated",
  139. (void *)&allocated, &sz, NULL, 0), expected,
  140. "Unexpected mallctl() result");
  141. sz = sizeof(uint64_t);
  142. expect_d_eq(mallctl("stats.arenas.0.small.nmalloc", (void *)&nmalloc,
  143. &sz, NULL, 0), expected, "Unexpected mallctl() result");
  144. expect_d_eq(mallctl("stats.arenas.0.small.ndalloc", (void *)&ndalloc,
  145. &sz, NULL, 0), expected, "Unexpected mallctl() result");
  146. expect_d_eq(mallctl("stats.arenas.0.small.nrequests",
  147. (void *)&nrequests, &sz, NULL, 0), expected,
  148. "Unexpected mallctl() result");
  149. if (config_stats) {
  150. expect_zu_gt(allocated, 0,
  151. "allocated should be greater than zero");
  152. expect_u64_gt(nmalloc, 0,
  153. "nmalloc should be no greater than zero");
  154. expect_u64_ge(nmalloc, ndalloc,
  155. "nmalloc should be at least as large as ndalloc");
  156. expect_u64_gt(nrequests, 0,
  157. "nrequests should be greater than zero");
  158. }
  159. dallocx(p, 0);
  160. }
  161. TEST_END
  162. TEST_BEGIN(test_stats_arenas_large) {
  163. void *p;
  164. size_t sz, allocated;
  165. uint64_t epoch, nmalloc, ndalloc;
  166. int expected = config_stats ? 0 : ENOENT;
  167. p = mallocx((1U << SC_LG_LARGE_MINCLASS), MALLOCX_ARENA(0));
  168. expect_ptr_not_null(p, "Unexpected mallocx() failure");
  169. expect_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)),
  170. 0, "Unexpected mallctl() failure");
  171. sz = sizeof(size_t);
  172. expect_d_eq(mallctl("stats.arenas.0.large.allocated",
  173. (void *)&allocated, &sz, NULL, 0), expected,
  174. "Unexpected mallctl() result");
  175. sz = sizeof(uint64_t);
  176. expect_d_eq(mallctl("stats.arenas.0.large.nmalloc", (void *)&nmalloc,
  177. &sz, NULL, 0), expected, "Unexpected mallctl() result");
  178. expect_d_eq(mallctl("stats.arenas.0.large.ndalloc", (void *)&ndalloc,
  179. &sz, NULL, 0), expected, "Unexpected mallctl() result");
  180. if (config_stats) {
  181. expect_zu_gt(allocated, 0,
  182. "allocated should be greater than zero");
  183. expect_u64_gt(nmalloc, 0,
  184. "nmalloc should be greater than zero");
  185. expect_u64_ge(nmalloc, ndalloc,
  186. "nmalloc should be at least as large as ndalloc");
  187. }
  188. dallocx(p, 0);
  189. }
  190. TEST_END
  191. static void
  192. gen_mallctl_str(char *cmd, char *name, unsigned arena_ind) {
  193. sprintf(cmd, "stats.arenas.%u.bins.0.%s", arena_ind, name);
  194. }
  195. TEST_BEGIN(test_stats_arenas_bins) {
  196. void *p;
  197. size_t sz, curslabs, curregs, nonfull_slabs;
  198. uint64_t epoch, nmalloc, ndalloc, nrequests, nfills, nflushes;
  199. uint64_t nslabs, nreslabs;
  200. int expected = config_stats ? 0 : ENOENT;
  201. /* Make sure allocation below isn't satisfied by tcache. */
  202. expect_d_eq(mallctl("thread.tcache.flush", NULL, NULL, NULL, 0),
  203. opt_tcache ? 0 : EFAULT, "Unexpected mallctl() result");
  204. unsigned arena_ind, old_arena_ind;
  205. sz = sizeof(unsigned);
  206. expect_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, NULL, 0),
  207. 0, "Arena creation failure");
  208. sz = sizeof(arena_ind);
  209. expect_d_eq(mallctl("thread.arena", (void *)&old_arena_ind, &sz,
  210. (void *)&arena_ind, sizeof(arena_ind)), 0,
  211. "Unexpected mallctl() failure");
  212. p = malloc(bin_infos[0].reg_size);
  213. expect_ptr_not_null(p, "Unexpected malloc() failure");
  214. expect_d_eq(mallctl("thread.tcache.flush", NULL, NULL, NULL, 0),
  215. opt_tcache ? 0 : EFAULT, "Unexpected mallctl() result");
  216. expect_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)),
  217. 0, "Unexpected mallctl() failure");
  218. char cmd[128];
  219. sz = sizeof(uint64_t);
  220. gen_mallctl_str(cmd, "nmalloc", arena_ind);
  221. expect_d_eq(mallctl(cmd, (void *)&nmalloc, &sz, NULL, 0), expected,
  222. "Unexpected mallctl() result");
  223. gen_mallctl_str(cmd, "ndalloc", arena_ind);
  224. expect_d_eq(mallctl(cmd, (void *)&ndalloc, &sz, NULL, 0), expected,
  225. "Unexpected mallctl() result");
  226. gen_mallctl_str(cmd, "nrequests", arena_ind);
  227. expect_d_eq(mallctl(cmd, (void *)&nrequests, &sz, NULL, 0), expected,
  228. "Unexpected mallctl() result");
  229. sz = sizeof(size_t);
  230. gen_mallctl_str(cmd, "curregs", arena_ind);
  231. expect_d_eq(mallctl(cmd, (void *)&curregs, &sz, NULL, 0), expected,
  232. "Unexpected mallctl() result");
  233. sz = sizeof(uint64_t);
  234. gen_mallctl_str(cmd, "nfills", arena_ind);
  235. expect_d_eq(mallctl(cmd, (void *)&nfills, &sz, NULL, 0), expected,
  236. "Unexpected mallctl() result");
  237. gen_mallctl_str(cmd, "nflushes", arena_ind);
  238. expect_d_eq(mallctl(cmd, (void *)&nflushes, &sz, NULL, 0), expected,
  239. "Unexpected mallctl() result");
  240. gen_mallctl_str(cmd, "nslabs", arena_ind);
  241. expect_d_eq(mallctl(cmd, (void *)&nslabs, &sz, NULL, 0), expected,
  242. "Unexpected mallctl() result");
  243. gen_mallctl_str(cmd, "nreslabs", arena_ind);
  244. expect_d_eq(mallctl(cmd, (void *)&nreslabs, &sz, NULL, 0), expected,
  245. "Unexpected mallctl() result");
  246. sz = sizeof(size_t);
  247. gen_mallctl_str(cmd, "curslabs", arena_ind);
  248. expect_d_eq(mallctl(cmd, (void *)&curslabs, &sz, NULL, 0), expected,
  249. "Unexpected mallctl() result");
  250. gen_mallctl_str(cmd, "nonfull_slabs", arena_ind);
  251. expect_d_eq(mallctl(cmd, (void *)&nonfull_slabs, &sz, NULL, 0),
  252. expected, "Unexpected mallctl() result");
  253. if (config_stats) {
  254. expect_u64_gt(nmalloc, 0,
  255. "nmalloc should be greater than zero");
  256. expect_u64_ge(nmalloc, ndalloc,
  257. "nmalloc should be at least as large as ndalloc");
  258. expect_u64_gt(nrequests, 0,
  259. "nrequests should be greater than zero");
  260. expect_zu_gt(curregs, 0,
  261. "allocated should be greater than zero");
  262. if (opt_tcache) {
  263. expect_u64_gt(nfills, 0,
  264. "At least one fill should have occurred");
  265. expect_u64_gt(nflushes, 0,
  266. "At least one flush should have occurred");
  267. }
  268. expect_u64_gt(nslabs, 0,
  269. "At least one slab should have been allocated");
  270. expect_zu_gt(curslabs, 0,
  271. "At least one slab should be currently allocated");
  272. expect_zu_eq(nonfull_slabs, 0,
  273. "slabs_nonfull should be empty");
  274. }
  275. dallocx(p, 0);
  276. }
  277. TEST_END
  278. TEST_BEGIN(test_stats_arenas_lextents) {
  279. void *p;
  280. uint64_t epoch, nmalloc, ndalloc;
  281. size_t curlextents, sz, hsize;
  282. int expected = config_stats ? 0 : ENOENT;
  283. sz = sizeof(size_t);
  284. expect_d_eq(mallctl("arenas.lextent.0.size", (void *)&hsize, &sz, NULL,
  285. 0), 0, "Unexpected mallctl() failure");
  286. p = mallocx(hsize, MALLOCX_ARENA(0));
  287. expect_ptr_not_null(p, "Unexpected mallocx() failure");
  288. expect_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)),
  289. 0, "Unexpected mallctl() failure");
  290. sz = sizeof(uint64_t);
  291. expect_d_eq(mallctl("stats.arenas.0.lextents.0.nmalloc",
  292. (void *)&nmalloc, &sz, NULL, 0), expected,
  293. "Unexpected mallctl() result");
  294. expect_d_eq(mallctl("stats.arenas.0.lextents.0.ndalloc",
  295. (void *)&ndalloc, &sz, NULL, 0), expected,
  296. "Unexpected mallctl() result");
  297. sz = sizeof(size_t);
  298. expect_d_eq(mallctl("stats.arenas.0.lextents.0.curlextents",
  299. (void *)&curlextents, &sz, NULL, 0), expected,
  300. "Unexpected mallctl() result");
  301. if (config_stats) {
  302. expect_u64_gt(nmalloc, 0,
  303. "nmalloc should be greater than zero");
  304. expect_u64_ge(nmalloc, ndalloc,
  305. "nmalloc should be at least as large as ndalloc");
  306. expect_u64_gt(curlextents, 0,
  307. "At least one extent should be currently allocated");
  308. }
  309. dallocx(p, 0);
  310. }
  311. TEST_END
  312. static void
  313. test_tcache_bytes_for_usize(size_t usize) {
  314. uint64_t epoch;
  315. size_t tcache_bytes, tcache_stashed_bytes;
  316. size_t sz = sizeof(tcache_bytes);
  317. void *ptr = mallocx(usize, 0);
  318. expect_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)),
  319. 0, "Unexpected mallctl() failure");
  320. assert_d_eq(mallctl(
  321. "stats.arenas." STRINGIFY(MALLCTL_ARENAS_ALL) ".tcache_bytes",
  322. &tcache_bytes, &sz, NULL, 0), 0, "Unexpected mallctl failure");
  323. assert_d_eq(mallctl(
  324. "stats.arenas." STRINGIFY(MALLCTL_ARENAS_ALL)
  325. ".tcache_stashed_bytes", &tcache_stashed_bytes, &sz, NULL, 0), 0,
  326. "Unexpected mallctl failure");
  327. size_t tcache_bytes_before = tcache_bytes + tcache_stashed_bytes;
  328. dallocx(ptr, 0);
  329. expect_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)),
  330. 0, "Unexpected mallctl() failure");
  331. assert_d_eq(mallctl(
  332. "stats.arenas." STRINGIFY(MALLCTL_ARENAS_ALL) ".tcache_bytes",
  333. &tcache_bytes, &sz, NULL, 0), 0, "Unexpected mallctl failure");
  334. assert_d_eq(mallctl(
  335. "stats.arenas." STRINGIFY(MALLCTL_ARENAS_ALL)
  336. ".tcache_stashed_bytes", &tcache_stashed_bytes, &sz, NULL, 0), 0,
  337. "Unexpected mallctl failure");
  338. size_t tcache_bytes_after = tcache_bytes + tcache_stashed_bytes;
  339. assert_zu_eq(tcache_bytes_after - tcache_bytes_before,
  340. usize, "Incorrectly attributed a free");
  341. }
  342. TEST_BEGIN(test_stats_tcache_bytes_small) {
  343. test_skip_if(!config_stats);
  344. test_skip_if(!opt_tcache);
  345. test_skip_if(opt_tcache_max < SC_SMALL_MAXCLASS);
  346. test_tcache_bytes_for_usize(SC_SMALL_MAXCLASS);
  347. }
  348. TEST_END
  349. TEST_BEGIN(test_stats_tcache_bytes_large) {
  350. test_skip_if(!config_stats);
  351. test_skip_if(!opt_tcache);
  352. test_skip_if(opt_tcache_max < SC_LARGE_MINCLASS);
  353. test_tcache_bytes_for_usize(SC_LARGE_MINCLASS);
  354. }
  355. TEST_END
  356. int
  357. main(void) {
  358. return test_no_reentrancy(
  359. test_stats_summary,
  360. test_stats_large,
  361. test_stats_arenas_summary,
  362. test_stats_arenas_small,
  363. test_stats_arenas_large,
  364. test_stats_arenas_bins,
  365. test_stats_arenas_lextents,
  366. test_stats_tcache_bytes_small,
  367. test_stats_tcache_bytes_large);
  368. }