PageRenderTime 62ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/contrib/jemalloc/src/stats.c

https://bitbucket.org/freebsd/freebsd-head/
C | 543 lines | 469 code | 54 blank | 20 comment | 73 complexity | 99a2f0b13e1e80c857448d78d743cb70 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, BSD-3-Clause, LGPL-2.0, LGPL-2.1, BSD-2-Clause, 0BSD, JSON, AGPL-1.0, GPL-2.0
  1. #define JEMALLOC_STATS_C_
  2. #include "jemalloc/internal/jemalloc_internal.h"
  3. #define CTL_GET(n, v, t) do { \
  4. size_t sz = sizeof(t); \
  5. xmallctl(n, v, &sz, NULL, 0); \
  6. } while (0)
  7. #define CTL_I_GET(n, v, t) do { \
  8. size_t mib[6]; \
  9. size_t miblen = sizeof(mib) / sizeof(size_t); \
  10. size_t sz = sizeof(t); \
  11. xmallctlnametomib(n, mib, &miblen); \
  12. mib[2] = i; \
  13. xmallctlbymib(mib, miblen, v, &sz, NULL, 0); \
  14. } while (0)
  15. #define CTL_J_GET(n, v, t) do { \
  16. size_t mib[6]; \
  17. size_t miblen = sizeof(mib) / sizeof(size_t); \
  18. size_t sz = sizeof(t); \
  19. xmallctlnametomib(n, mib, &miblen); \
  20. mib[2] = j; \
  21. xmallctlbymib(mib, miblen, v, &sz, NULL, 0); \
  22. } while (0)
  23. #define CTL_IJ_GET(n, v, t) do { \
  24. size_t mib[6]; \
  25. size_t miblen = sizeof(mib) / sizeof(size_t); \
  26. size_t sz = sizeof(t); \
  27. xmallctlnametomib(n, mib, &miblen); \
  28. mib[2] = i; \
  29. mib[4] = j; \
  30. xmallctlbymib(mib, miblen, v, &sz, NULL, 0); \
  31. } while (0)
  32. /******************************************************************************/
  33. /* Data. */
  34. bool opt_stats_print = false;
  35. size_t stats_cactive = 0;
  36. /******************************************************************************/
  37. /* Function prototypes for non-inline static functions. */
  38. static void stats_arena_bins_print(void (*write_cb)(void *, const char *),
  39. void *cbopaque, unsigned i);
  40. static void stats_arena_lruns_print(void (*write_cb)(void *, const char *),
  41. void *cbopaque, unsigned i);
  42. static void stats_arena_print(void (*write_cb)(void *, const char *),
  43. void *cbopaque, unsigned i, bool bins, bool large);
  44. /******************************************************************************/
  45. static void
  46. stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque,
  47. unsigned i)
  48. {
  49. size_t page;
  50. bool config_tcache;
  51. unsigned nbins, j, gap_start;
  52. CTL_GET("arenas.page", &page, size_t);
  53. CTL_GET("config.tcache", &config_tcache, bool);
  54. if (config_tcache) {
  55. malloc_cprintf(write_cb, cbopaque,
  56. "bins: bin size regs pgs allocated nmalloc"
  57. " ndalloc nrequests nfills nflushes"
  58. " newruns reruns curruns\n");
  59. } else {
  60. malloc_cprintf(write_cb, cbopaque,
  61. "bins: bin size regs pgs allocated nmalloc"
  62. " ndalloc newruns reruns curruns\n");
  63. }
  64. CTL_GET("arenas.nbins", &nbins, unsigned);
  65. for (j = 0, gap_start = UINT_MAX; j < nbins; j++) {
  66. uint64_t nruns;
  67. CTL_IJ_GET("stats.arenas.0.bins.0.nruns", &nruns, uint64_t);
  68. if (nruns == 0) {
  69. if (gap_start == UINT_MAX)
  70. gap_start = j;
  71. } else {
  72. size_t reg_size, run_size, allocated;
  73. uint32_t nregs;
  74. uint64_t nmalloc, ndalloc, nrequests, nfills, nflushes;
  75. uint64_t reruns;
  76. size_t curruns;
  77. if (gap_start != UINT_MAX) {
  78. if (j > gap_start + 1) {
  79. /* Gap of more than one size class. */
  80. malloc_cprintf(write_cb, cbopaque,
  81. "[%u..%u]\n", gap_start,
  82. j - 1);
  83. } else {
  84. /* Gap of one size class. */
  85. malloc_cprintf(write_cb, cbopaque,
  86. "[%u]\n", gap_start);
  87. }
  88. gap_start = UINT_MAX;
  89. }
  90. CTL_J_GET("arenas.bin.0.size", &reg_size, size_t);
  91. CTL_J_GET("arenas.bin.0.nregs", &nregs, uint32_t);
  92. CTL_J_GET("arenas.bin.0.run_size", &run_size, size_t);
  93. CTL_IJ_GET("stats.arenas.0.bins.0.allocated",
  94. &allocated, size_t);
  95. CTL_IJ_GET("stats.arenas.0.bins.0.nmalloc",
  96. &nmalloc, uint64_t);
  97. CTL_IJ_GET("stats.arenas.0.bins.0.ndalloc",
  98. &ndalloc, uint64_t);
  99. if (config_tcache) {
  100. CTL_IJ_GET("stats.arenas.0.bins.0.nrequests",
  101. &nrequests, uint64_t);
  102. CTL_IJ_GET("stats.arenas.0.bins.0.nfills",
  103. &nfills, uint64_t);
  104. CTL_IJ_GET("stats.arenas.0.bins.0.nflushes",
  105. &nflushes, uint64_t);
  106. }
  107. CTL_IJ_GET("stats.arenas.0.bins.0.nreruns", &reruns,
  108. uint64_t);
  109. CTL_IJ_GET("stats.arenas.0.bins.0.curruns", &curruns,
  110. size_t);
  111. if (config_tcache) {
  112. malloc_cprintf(write_cb, cbopaque,
  113. "%13u %5zu %4u %3zu %12zu %12"PRIu64
  114. " %12"PRIu64" %12"PRIu64" %12"PRIu64
  115. " %12"PRIu64" %12"PRIu64" %12"PRIu64
  116. " %12zu\n",
  117. j, reg_size, nregs, run_size / page,
  118. allocated, nmalloc, ndalloc, nrequests,
  119. nfills, nflushes, nruns, reruns, curruns);
  120. } else {
  121. malloc_cprintf(write_cb, cbopaque,
  122. "%13u %5zu %4u %3zu %12zu %12"PRIu64
  123. " %12"PRIu64" %12"PRIu64" %12"PRIu64
  124. " %12zu\n",
  125. j, reg_size, nregs, run_size / page,
  126. allocated, nmalloc, ndalloc, nruns, reruns,
  127. curruns);
  128. }
  129. }
  130. }
  131. if (gap_start != UINT_MAX) {
  132. if (j > gap_start + 1) {
  133. /* Gap of more than one size class. */
  134. malloc_cprintf(write_cb, cbopaque, "[%u..%u]\n",
  135. gap_start, j - 1);
  136. } else {
  137. /* Gap of one size class. */
  138. malloc_cprintf(write_cb, cbopaque, "[%u]\n", gap_start);
  139. }
  140. }
  141. }
  142. static void
  143. stats_arena_lruns_print(void (*write_cb)(void *, const char *), void *cbopaque,
  144. unsigned i)
  145. {
  146. size_t page, nlruns, j;
  147. ssize_t gap_start;
  148. CTL_GET("arenas.page", &page, size_t);
  149. malloc_cprintf(write_cb, cbopaque,
  150. "large: size pages nmalloc ndalloc nrequests"
  151. " curruns\n");
  152. CTL_GET("arenas.nlruns", &nlruns, size_t);
  153. for (j = 0, gap_start = -1; j < nlruns; j++) {
  154. uint64_t nmalloc, ndalloc, nrequests;
  155. size_t run_size, curruns;
  156. CTL_IJ_GET("stats.arenas.0.lruns.0.nmalloc", &nmalloc,
  157. uint64_t);
  158. CTL_IJ_GET("stats.arenas.0.lruns.0.ndalloc", &ndalloc,
  159. uint64_t);
  160. CTL_IJ_GET("stats.arenas.0.lruns.0.nrequests", &nrequests,
  161. uint64_t);
  162. if (nrequests == 0) {
  163. if (gap_start == -1)
  164. gap_start = j;
  165. } else {
  166. CTL_J_GET("arenas.lrun.0.size", &run_size, size_t);
  167. CTL_IJ_GET("stats.arenas.0.lruns.0.curruns", &curruns,
  168. size_t);
  169. if (gap_start != -1) {
  170. malloc_cprintf(write_cb, cbopaque, "[%zu]\n",
  171. j - gap_start);
  172. gap_start = -1;
  173. }
  174. malloc_cprintf(write_cb, cbopaque,
  175. "%13zu %5zu %12"PRIu64" %12"PRIu64" %12"PRIu64
  176. " %12zu\n",
  177. run_size, run_size / page, nmalloc, ndalloc,
  178. nrequests, curruns);
  179. }
  180. }
  181. if (gap_start != -1)
  182. malloc_cprintf(write_cb, cbopaque, "[%zu]\n", j - gap_start);
  183. }
  184. static void
  185. stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque,
  186. unsigned i, bool bins, bool large)
  187. {
  188. unsigned nthreads;
  189. size_t page, pactive, pdirty, mapped;
  190. uint64_t npurge, nmadvise, purged;
  191. size_t small_allocated;
  192. uint64_t small_nmalloc, small_ndalloc, small_nrequests;
  193. size_t large_allocated;
  194. uint64_t large_nmalloc, large_ndalloc, large_nrequests;
  195. CTL_GET("arenas.page", &page, size_t);
  196. CTL_I_GET("stats.arenas.0.nthreads", &nthreads, unsigned);
  197. malloc_cprintf(write_cb, cbopaque,
  198. "assigned threads: %u\n", nthreads);
  199. CTL_I_GET("stats.arenas.0.pactive", &pactive, size_t);
  200. CTL_I_GET("stats.arenas.0.pdirty", &pdirty, size_t);
  201. CTL_I_GET("stats.arenas.0.npurge", &npurge, uint64_t);
  202. CTL_I_GET("stats.arenas.0.nmadvise", &nmadvise, uint64_t);
  203. CTL_I_GET("stats.arenas.0.purged", &purged, uint64_t);
  204. malloc_cprintf(write_cb, cbopaque,
  205. "dirty pages: %zu:%zu active:dirty, %"PRIu64" sweep%s,"
  206. " %"PRIu64" madvise%s, %"PRIu64" purged\n",
  207. pactive, pdirty, npurge, npurge == 1 ? "" : "s",
  208. nmadvise, nmadvise == 1 ? "" : "s", purged);
  209. malloc_cprintf(write_cb, cbopaque,
  210. " allocated nmalloc ndalloc nrequests\n");
  211. CTL_I_GET("stats.arenas.0.small.allocated", &small_allocated, size_t);
  212. CTL_I_GET("stats.arenas.0.small.nmalloc", &small_nmalloc, uint64_t);
  213. CTL_I_GET("stats.arenas.0.small.ndalloc", &small_ndalloc, uint64_t);
  214. CTL_I_GET("stats.arenas.0.small.nrequests", &small_nrequests, uint64_t);
  215. malloc_cprintf(write_cb, cbopaque,
  216. "small: %12zu %12"PRIu64" %12"PRIu64" %12"PRIu64"\n",
  217. small_allocated, small_nmalloc, small_ndalloc, small_nrequests);
  218. CTL_I_GET("stats.arenas.0.large.allocated", &large_allocated, size_t);
  219. CTL_I_GET("stats.arenas.0.large.nmalloc", &large_nmalloc, uint64_t);
  220. CTL_I_GET("stats.arenas.0.large.ndalloc", &large_ndalloc, uint64_t);
  221. CTL_I_GET("stats.arenas.0.large.nrequests", &large_nrequests, uint64_t);
  222. malloc_cprintf(write_cb, cbopaque,
  223. "large: %12zu %12"PRIu64" %12"PRIu64" %12"PRIu64"\n",
  224. large_allocated, large_nmalloc, large_ndalloc, large_nrequests);
  225. malloc_cprintf(write_cb, cbopaque,
  226. "total: %12zu %12"PRIu64" %12"PRIu64" %12"PRIu64"\n",
  227. small_allocated + large_allocated,
  228. small_nmalloc + large_nmalloc,
  229. small_ndalloc + large_ndalloc,
  230. small_nrequests + large_nrequests);
  231. malloc_cprintf(write_cb, cbopaque, "active: %12zu\n", pactive * page);
  232. CTL_I_GET("stats.arenas.0.mapped", &mapped, size_t);
  233. malloc_cprintf(write_cb, cbopaque, "mapped: %12zu\n", mapped);
  234. if (bins)
  235. stats_arena_bins_print(write_cb, cbopaque, i);
  236. if (large)
  237. stats_arena_lruns_print(write_cb, cbopaque, i);
  238. }
  239. void
  240. stats_print(void (*write_cb)(void *, const char *), void *cbopaque,
  241. const char *opts)
  242. {
  243. int err;
  244. uint64_t epoch;
  245. size_t u64sz;
  246. bool general = true;
  247. bool merged = true;
  248. bool unmerged = true;
  249. bool bins = true;
  250. bool large = true;
  251. /*
  252. * Refresh stats, in case mallctl() was called by the application.
  253. *
  254. * Check for OOM here, since refreshing the ctl cache can trigger
  255. * allocation. In practice, none of the subsequent mallctl()-related
  256. * calls in this function will cause OOM if this one succeeds.
  257. * */
  258. epoch = 1;
  259. u64sz = sizeof(uint64_t);
  260. err = je_mallctl("epoch", &epoch, &u64sz, &epoch, sizeof(uint64_t));
  261. if (err != 0) {
  262. if (err == EAGAIN) {
  263. malloc_write("<jemalloc>: Memory allocation failure in "
  264. "mallctl(\"epoch\", ...)\n");
  265. return;
  266. }
  267. malloc_write("<jemalloc>: Failure in mallctl(\"epoch\", "
  268. "...)\n");
  269. abort();
  270. }
  271. if (opts != NULL) {
  272. unsigned i;
  273. for (i = 0; opts[i] != '\0'; i++) {
  274. switch (opts[i]) {
  275. case 'g':
  276. general = false;
  277. break;
  278. case 'm':
  279. merged = false;
  280. break;
  281. case 'a':
  282. unmerged = false;
  283. break;
  284. case 'b':
  285. bins = false;
  286. break;
  287. case 'l':
  288. large = false;
  289. break;
  290. default:;
  291. }
  292. }
  293. }
  294. malloc_cprintf(write_cb, cbopaque,
  295. "___ Begin jemalloc statistics ___\n");
  296. if (general) {
  297. int err;
  298. const char *cpv;
  299. bool bv;
  300. unsigned uv;
  301. ssize_t ssv;
  302. size_t sv, bsz, ssz, sssz, cpsz;
  303. bsz = sizeof(bool);
  304. ssz = sizeof(size_t);
  305. sssz = sizeof(ssize_t);
  306. cpsz = sizeof(const char *);
  307. CTL_GET("version", &cpv, const char *);
  308. malloc_cprintf(write_cb, cbopaque, "Version: %s\n", cpv);
  309. CTL_GET("config.debug", &bv, bool);
  310. malloc_cprintf(write_cb, cbopaque, "Assertions %s\n",
  311. bv ? "enabled" : "disabled");
  312. #define OPT_WRITE_BOOL(n) \
  313. if ((err = je_mallctl("opt."#n, &bv, &bsz, NULL, 0)) \
  314. == 0) { \
  315. malloc_cprintf(write_cb, cbopaque, \
  316. " opt."#n": %s\n", bv ? "true" : "false"); \
  317. }
  318. #define OPT_WRITE_SIZE_T(n) \
  319. if ((err = je_mallctl("opt."#n, &sv, &ssz, NULL, 0)) \
  320. == 0) { \
  321. malloc_cprintf(write_cb, cbopaque, \
  322. " opt."#n": %zu\n", sv); \
  323. }
  324. #define OPT_WRITE_SSIZE_T(n) \
  325. if ((err = je_mallctl("opt."#n, &ssv, &sssz, NULL, 0)) \
  326. == 0) { \
  327. malloc_cprintf(write_cb, cbopaque, \
  328. " opt."#n": %zd\n", ssv); \
  329. }
  330. #define OPT_WRITE_CHAR_P(n) \
  331. if ((err = je_mallctl("opt."#n, &cpv, &cpsz, NULL, 0)) \
  332. == 0) { \
  333. malloc_cprintf(write_cb, cbopaque, \
  334. " opt."#n": \"%s\"\n", cpv); \
  335. }
  336. malloc_cprintf(write_cb, cbopaque,
  337. "Run-time option settings:\n");
  338. OPT_WRITE_BOOL(abort)
  339. OPT_WRITE_SIZE_T(lg_chunk)
  340. OPT_WRITE_SIZE_T(narenas)
  341. OPT_WRITE_SSIZE_T(lg_dirty_mult)
  342. OPT_WRITE_BOOL(stats_print)
  343. OPT_WRITE_BOOL(junk)
  344. OPT_WRITE_SIZE_T(quarantine)
  345. OPT_WRITE_BOOL(redzone)
  346. OPT_WRITE_BOOL(zero)
  347. OPT_WRITE_BOOL(utrace)
  348. OPT_WRITE_BOOL(valgrind)
  349. OPT_WRITE_BOOL(xmalloc)
  350. OPT_WRITE_BOOL(tcache)
  351. OPT_WRITE_SSIZE_T(lg_tcache_max)
  352. OPT_WRITE_BOOL(prof)
  353. OPT_WRITE_CHAR_P(prof_prefix)
  354. OPT_WRITE_BOOL(prof_active)
  355. OPT_WRITE_SSIZE_T(lg_prof_sample)
  356. OPT_WRITE_BOOL(prof_accum)
  357. OPT_WRITE_SSIZE_T(lg_prof_interval)
  358. OPT_WRITE_BOOL(prof_gdump)
  359. OPT_WRITE_BOOL(prof_final)
  360. OPT_WRITE_BOOL(prof_leak)
  361. #undef OPT_WRITE_BOOL
  362. #undef OPT_WRITE_SIZE_T
  363. #undef OPT_WRITE_SSIZE_T
  364. #undef OPT_WRITE_CHAR_P
  365. malloc_cprintf(write_cb, cbopaque, "CPUs: %u\n", ncpus);
  366. CTL_GET("arenas.narenas", &uv, unsigned);
  367. malloc_cprintf(write_cb, cbopaque, "Max arenas: %u\n", uv);
  368. malloc_cprintf(write_cb, cbopaque, "Pointer size: %zu\n",
  369. sizeof(void *));
  370. CTL_GET("arenas.quantum", &sv, size_t);
  371. malloc_cprintf(write_cb, cbopaque, "Quantum size: %zu\n", sv);
  372. CTL_GET("arenas.page", &sv, size_t);
  373. malloc_cprintf(write_cb, cbopaque, "Page size: %zu\n", sv);
  374. CTL_GET("opt.lg_dirty_mult", &ssv, ssize_t);
  375. if (ssv >= 0) {
  376. malloc_cprintf(write_cb, cbopaque,
  377. "Min active:dirty page ratio per arena: %u:1\n",
  378. (1U << ssv));
  379. } else {
  380. malloc_cprintf(write_cb, cbopaque,
  381. "Min active:dirty page ratio per arena: N/A\n");
  382. }
  383. if ((err = je_mallctl("arenas.tcache_max", &sv, &ssz, NULL, 0))
  384. == 0) {
  385. malloc_cprintf(write_cb, cbopaque,
  386. "Maximum thread-cached size class: %zu\n", sv);
  387. }
  388. if ((err = je_mallctl("opt.prof", &bv, &bsz, NULL, 0)) == 0 &&
  389. bv) {
  390. CTL_GET("opt.lg_prof_sample", &sv, size_t);
  391. malloc_cprintf(write_cb, cbopaque,
  392. "Average profile sample interval: %"PRIu64
  393. " (2^%zu)\n", (((uint64_t)1U) << sv), sv);
  394. CTL_GET("opt.lg_prof_interval", &ssv, ssize_t);
  395. if (ssv >= 0) {
  396. malloc_cprintf(write_cb, cbopaque,
  397. "Average profile dump interval: %"PRIu64
  398. " (2^%zd)\n",
  399. (((uint64_t)1U) << ssv), ssv);
  400. } else {
  401. malloc_cprintf(write_cb, cbopaque,
  402. "Average profile dump interval: N/A\n");
  403. }
  404. }
  405. CTL_GET("opt.lg_chunk", &sv, size_t);
  406. malloc_cprintf(write_cb, cbopaque, "Chunk size: %zu (2^%zu)\n",
  407. (ZU(1) << sv), sv);
  408. }
  409. if (config_stats) {
  410. size_t *cactive;
  411. size_t allocated, active, mapped;
  412. size_t chunks_current, chunks_high;
  413. uint64_t chunks_total;
  414. size_t huge_allocated;
  415. uint64_t huge_nmalloc, huge_ndalloc;
  416. CTL_GET("stats.cactive", &cactive, size_t *);
  417. CTL_GET("stats.allocated", &allocated, size_t);
  418. CTL_GET("stats.active", &active, size_t);
  419. CTL_GET("stats.mapped", &mapped, size_t);
  420. malloc_cprintf(write_cb, cbopaque,
  421. "Allocated: %zu, active: %zu, mapped: %zu\n",
  422. allocated, active, mapped);
  423. malloc_cprintf(write_cb, cbopaque,
  424. "Current active ceiling: %zu\n", atomic_read_z(cactive));
  425. /* Print chunk stats. */
  426. CTL_GET("stats.chunks.total", &chunks_total, uint64_t);
  427. CTL_GET("stats.chunks.high", &chunks_high, size_t);
  428. CTL_GET("stats.chunks.current", &chunks_current, size_t);
  429. malloc_cprintf(write_cb, cbopaque, "chunks: nchunks "
  430. "highchunks curchunks\n");
  431. malloc_cprintf(write_cb, cbopaque, " %13"PRIu64"%13zu%13zu\n",
  432. chunks_total, chunks_high, chunks_current);
  433. /* Print huge stats. */
  434. CTL_GET("stats.huge.nmalloc", &huge_nmalloc, uint64_t);
  435. CTL_GET("stats.huge.ndalloc", &huge_ndalloc, uint64_t);
  436. CTL_GET("stats.huge.allocated", &huge_allocated, size_t);
  437. malloc_cprintf(write_cb, cbopaque,
  438. "huge: nmalloc ndalloc allocated\n");
  439. malloc_cprintf(write_cb, cbopaque,
  440. " %12"PRIu64" %12"PRIu64" %12zu\n",
  441. huge_nmalloc, huge_ndalloc, huge_allocated);
  442. if (merged) {
  443. unsigned narenas;
  444. CTL_GET("arenas.narenas", &narenas, unsigned);
  445. {
  446. VARIABLE_ARRAY(bool, initialized, narenas);
  447. size_t isz;
  448. unsigned i, ninitialized;
  449. isz = sizeof(bool) * narenas;
  450. xmallctl("arenas.initialized", initialized,
  451. &isz, NULL, 0);
  452. for (i = ninitialized = 0; i < narenas; i++) {
  453. if (initialized[i])
  454. ninitialized++;
  455. }
  456. if (ninitialized > 1 || unmerged == false) {
  457. /* Print merged arena stats. */
  458. malloc_cprintf(write_cb, cbopaque,
  459. "\nMerged arenas stats:\n");
  460. stats_arena_print(write_cb, cbopaque,
  461. narenas, bins, large);
  462. }
  463. }
  464. }
  465. if (unmerged) {
  466. unsigned narenas;
  467. /* Print stats for each arena. */
  468. CTL_GET("arenas.narenas", &narenas, unsigned);
  469. {
  470. VARIABLE_ARRAY(bool, initialized, narenas);
  471. size_t isz;
  472. unsigned i;
  473. isz = sizeof(bool) * narenas;
  474. xmallctl("arenas.initialized", initialized,
  475. &isz, NULL, 0);
  476. for (i = 0; i < narenas; i++) {
  477. if (initialized[i]) {
  478. malloc_cprintf(write_cb,
  479. cbopaque,
  480. "\narenas[%u]:\n", i);
  481. stats_arena_print(write_cb,
  482. cbopaque, i, bins, large);
  483. }
  484. }
  485. }
  486. }
  487. }
  488. malloc_cprintf(write_cb, cbopaque, "--- End jemalloc statistics ---\n");
  489. }