1 | #define JEMALLOC_STATS_C_ |
2 | #include "jemalloc/internal/jemalloc_internal.h" |
3 | |
4 | #define CTL_GET(n, v, t) do { \ |
5 | size_t sz = sizeof(t); \ |
6 | xmallctl(n, v, &sz, NULL, 0); \ |
7 | } while (0) |
8 | |
9 | #define CTL_M2_GET(n, i, v, t) do { \ |
10 | size_t mib[6]; \ |
11 | size_t miblen = sizeof(mib) / sizeof(size_t); \ |
12 | size_t sz = sizeof(t); \ |
13 | xmallctlnametomib(n, mib, &miblen); \ |
14 | mib[2] = (i); \ |
15 | xmallctlbymib(mib, miblen, v, &sz, NULL, 0); \ |
16 | } while (0) |
17 | |
18 | #define CTL_M2_M4_GET(n, i, j, v, t) do { \ |
19 | size_t mib[6]; \ |
20 | size_t miblen = sizeof(mib) / sizeof(size_t); \ |
21 | size_t sz = sizeof(t); \ |
22 | xmallctlnametomib(n, mib, &miblen); \ |
23 | mib[2] = (i); \ |
24 | mib[4] = (j); \ |
25 | xmallctlbymib(mib, miblen, v, &sz, NULL, 0); \ |
26 | } while (0) |
27 | |
28 | /******************************************************************************/ |
29 | /* Data. */ |
30 | |
31 | bool opt_stats_print = false; |
32 | |
33 | size_t stats_cactive = 0; |
34 | |
35 | /******************************************************************************/ |
36 | /* Function prototypes for non-inline static functions. */ |
37 | |
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_hchunks_print( |
43 | void (*write_cb)(void *, const char *), void *cbopaque, unsigned i); |
44 | static void stats_arena_print(void (*write_cb)(void *, const char *), |
45 | void *cbopaque, unsigned i, bool bins, bool large, bool huge); |
46 | |
47 | /******************************************************************************/ |
48 | |
49 | static void |
50 | stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, |
51 | unsigned i) |
52 | { |
53 | size_t page; |
54 | bool config_tcache, in_gap; |
55 | unsigned nbins, j; |
56 | |
57 | CTL_GET("arenas.page" , &page, size_t); |
58 | |
59 | CTL_GET("config.tcache" , &config_tcache, bool); |
60 | if (config_tcache) { |
61 | malloc_cprintf(write_cb, cbopaque, |
62 | "bins: size ind allocated nmalloc" |
63 | " ndalloc nrequests curregs curruns regs" |
64 | " pgs util nfills nflushes newruns" |
65 | " reruns\n" ); |
66 | } else { |
67 | malloc_cprintf(write_cb, cbopaque, |
68 | "bins: size ind allocated nmalloc" |
69 | " ndalloc nrequests curregs curruns regs" |
70 | " pgs util newruns reruns\n" ); |
71 | } |
72 | CTL_GET("arenas.nbins" , &nbins, unsigned); |
73 | for (j = 0, in_gap = false; j < nbins; j++) { |
74 | uint64_t nruns; |
75 | |
76 | CTL_M2_M4_GET("stats.arenas.0.bins.0.nruns" , i, j, &nruns, |
77 | uint64_t); |
78 | if (nruns == 0) |
79 | in_gap = true; |
80 | else { |
81 | size_t reg_size, run_size, curregs, availregs, milli; |
82 | size_t curruns; |
83 | uint32_t nregs; |
84 | uint64_t nmalloc, ndalloc, nrequests, nfills, nflushes; |
85 | uint64_t reruns; |
86 | char util[6]; /* "x.yyy". */ |
87 | |
88 | if (in_gap) { |
89 | malloc_cprintf(write_cb, cbopaque, |
90 | " ---\n" ); |
91 | in_gap = false; |
92 | } |
93 | CTL_M2_GET("arenas.bin.0.size" , j, ®_size, size_t); |
94 | CTL_M2_GET("arenas.bin.0.nregs" , j, &nregs, uint32_t); |
95 | CTL_M2_GET("arenas.bin.0.run_size" , j, &run_size, |
96 | size_t); |
97 | CTL_M2_M4_GET("stats.arenas.0.bins.0.nmalloc" , i, j, |
98 | &nmalloc, uint64_t); |
99 | CTL_M2_M4_GET("stats.arenas.0.bins.0.ndalloc" , i, j, |
100 | &ndalloc, uint64_t); |
101 | CTL_M2_M4_GET("stats.arenas.0.bins.0.curregs" , i, j, |
102 | &curregs, size_t); |
103 | CTL_M2_M4_GET("stats.arenas.0.bins.0.nrequests" , i, j, |
104 | &nrequests, uint64_t); |
105 | if (config_tcache) { |
106 | CTL_M2_M4_GET("stats.arenas.0.bins.0.nfills" , i, |
107 | j, &nfills, uint64_t); |
108 | CTL_M2_M4_GET("stats.arenas.0.bins.0.nflushes" , |
109 | i, j, &nflushes, uint64_t); |
110 | } |
111 | CTL_M2_M4_GET("stats.arenas.0.bins.0.nreruns" , i, j, |
112 | &reruns, uint64_t); |
113 | CTL_M2_M4_GET("stats.arenas.0.bins.0.curruns" , i, j, |
114 | &curruns, size_t); |
115 | |
116 | availregs = nregs * curruns; |
117 | milli = (availregs != 0) ? (1000 * curregs) / availregs |
118 | : 1000; |
119 | assert(milli <= 1000); |
120 | if (milli < 10) { |
121 | malloc_snprintf(util, sizeof(util), |
122 | "0.00%zu" , milli); |
123 | } else if (milli < 100) { |
124 | malloc_snprintf(util, sizeof(util), "0.0%zu" , |
125 | milli); |
126 | } else if (milli < 1000) { |
127 | malloc_snprintf(util, sizeof(util), "0.%zu" , |
128 | milli); |
129 | } else |
130 | malloc_snprintf(util, sizeof(util), "1" ); |
131 | |
132 | if (config_tcache) { |
133 | malloc_cprintf(write_cb, cbopaque, |
134 | "%20zu %3u %12zu %12" FMTu64 |
135 | " %12" FMTu64" %12" FMTu64" %12zu" |
136 | " %12zu %4u %3zu %-5s %12" FMTu64 |
137 | " %12" FMTu64" %12" FMTu64" %12" FMTu64"\n" , |
138 | reg_size, j, curregs * reg_size, nmalloc, |
139 | ndalloc, nrequests, curregs, curruns, nregs, |
140 | run_size / page, util, nfills, nflushes, |
141 | nruns, reruns); |
142 | } else { |
143 | malloc_cprintf(write_cb, cbopaque, |
144 | "%20zu %3u %12zu %12" FMTu64 |
145 | " %12" FMTu64" %12" FMTu64" %12zu" |
146 | " %12zu %4u %3zu %-5s %12" FMTu64 |
147 | " %12" FMTu64"\n" , |
148 | reg_size, j, curregs * reg_size, nmalloc, |
149 | ndalloc, nrequests, curregs, curruns, nregs, |
150 | run_size / page, util, nruns, reruns); |
151 | } |
152 | } |
153 | } |
154 | if (in_gap) { |
155 | malloc_cprintf(write_cb, cbopaque, |
156 | " ---\n" ); |
157 | } |
158 | } |
159 | |
160 | static void |
161 | stats_arena_lruns_print(void (*write_cb)(void *, const char *), void *cbopaque, |
162 | unsigned i) |
163 | { |
164 | unsigned nbins, nlruns, j; |
165 | bool in_gap; |
166 | |
167 | malloc_cprintf(write_cb, cbopaque, |
168 | "large: size ind allocated nmalloc ndalloc" |
169 | " nrequests curruns\n" ); |
170 | CTL_GET("arenas.nbins" , &nbins, unsigned); |
171 | CTL_GET("arenas.nlruns" , &nlruns, unsigned); |
172 | for (j = 0, in_gap = false; j < nlruns; j++) { |
173 | uint64_t nmalloc, ndalloc, nrequests; |
174 | size_t run_size, curruns; |
175 | |
176 | CTL_M2_M4_GET("stats.arenas.0.lruns.0.nmalloc" , i, j, &nmalloc, |
177 | uint64_t); |
178 | CTL_M2_M4_GET("stats.arenas.0.lruns.0.ndalloc" , i, j, &ndalloc, |
179 | uint64_t); |
180 | CTL_M2_M4_GET("stats.arenas.0.lruns.0.nrequests" , i, j, |
181 | &nrequests, uint64_t); |
182 | if (nrequests == 0) |
183 | in_gap = true; |
184 | else { |
185 | CTL_M2_GET("arenas.lrun.0.size" , j, &run_size, size_t); |
186 | CTL_M2_M4_GET("stats.arenas.0.lruns.0.curruns" , i, j, |
187 | &curruns, size_t); |
188 | if (in_gap) { |
189 | malloc_cprintf(write_cb, cbopaque, |
190 | " ---\n" ); |
191 | in_gap = false; |
192 | } |
193 | malloc_cprintf(write_cb, cbopaque, |
194 | "%20zu %3u %12zu %12" FMTu64" %12" FMTu64 |
195 | " %12" FMTu64" %12zu\n" , |
196 | run_size, nbins + j, curruns * run_size, nmalloc, |
197 | ndalloc, nrequests, curruns); |
198 | } |
199 | } |
200 | if (in_gap) { |
201 | malloc_cprintf(write_cb, cbopaque, |
202 | " ---\n" ); |
203 | } |
204 | } |
205 | |
206 | static void |
207 | stats_arena_hchunks_print(void (*write_cb)(void *, const char *), |
208 | void *cbopaque, unsigned i) |
209 | { |
210 | unsigned nbins, nlruns, nhchunks, j; |
211 | bool in_gap; |
212 | |
213 | malloc_cprintf(write_cb, cbopaque, |
214 | "huge: size ind allocated nmalloc ndalloc" |
215 | " nrequests curhchunks\n" ); |
216 | CTL_GET("arenas.nbins" , &nbins, unsigned); |
217 | CTL_GET("arenas.nlruns" , &nlruns, unsigned); |
218 | CTL_GET("arenas.nhchunks" , &nhchunks, unsigned); |
219 | for (j = 0, in_gap = false; j < nhchunks; j++) { |
220 | uint64_t nmalloc, ndalloc, nrequests; |
221 | size_t hchunk_size, curhchunks; |
222 | |
223 | CTL_M2_M4_GET("stats.arenas.0.hchunks.0.nmalloc" , i, j, |
224 | &nmalloc, uint64_t); |
225 | CTL_M2_M4_GET("stats.arenas.0.hchunks.0.ndalloc" , i, j, |
226 | &ndalloc, uint64_t); |
227 | CTL_M2_M4_GET("stats.arenas.0.hchunks.0.nrequests" , i, j, |
228 | &nrequests, uint64_t); |
229 | if (nrequests == 0) |
230 | in_gap = true; |
231 | else { |
232 | CTL_M2_GET("arenas.hchunk.0.size" , j, &hchunk_size, |
233 | size_t); |
234 | CTL_M2_M4_GET("stats.arenas.0.hchunks.0.curhchunks" , i, |
235 | j, &curhchunks, size_t); |
236 | if (in_gap) { |
237 | malloc_cprintf(write_cb, cbopaque, |
238 | " ---\n" ); |
239 | in_gap = false; |
240 | } |
241 | malloc_cprintf(write_cb, cbopaque, |
242 | "%20zu %3u %12zu %12" FMTu64" %12" FMTu64 |
243 | " %12" FMTu64" %12zu\n" , |
244 | hchunk_size, nbins + nlruns + j, |
245 | curhchunks * hchunk_size, nmalloc, ndalloc, |
246 | nrequests, curhchunks); |
247 | } |
248 | } |
249 | if (in_gap) { |
250 | malloc_cprintf(write_cb, cbopaque, |
251 | " ---\n" ); |
252 | } |
253 | } |
254 | |
255 | static void |
256 | stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, |
257 | unsigned i, bool bins, bool large, bool huge) |
258 | { |
259 | unsigned nthreads; |
260 | const char *dss; |
261 | ssize_t lg_dirty_mult, decay_time; |
262 | size_t page, pactive, pdirty, mapped, retained; |
263 | size_t metadata_mapped, metadata_allocated; |
264 | uint64_t npurge, nmadvise, purged; |
265 | size_t small_allocated; |
266 | uint64_t small_nmalloc, small_ndalloc, small_nrequests; |
267 | size_t large_allocated; |
268 | uint64_t large_nmalloc, large_ndalloc, large_nrequests; |
269 | size_t huge_allocated; |
270 | uint64_t huge_nmalloc, huge_ndalloc, huge_nrequests; |
271 | |
272 | CTL_GET("arenas.page" , &page, size_t); |
273 | |
274 | CTL_M2_GET("stats.arenas.0.nthreads" , i, &nthreads, unsigned); |
275 | malloc_cprintf(write_cb, cbopaque, |
276 | "assigned threads: %u\n" , nthreads); |
277 | CTL_M2_GET("stats.arenas.0.dss" , i, &dss, const char *); |
278 | malloc_cprintf(write_cb, cbopaque, "dss allocation precedence: %s\n" , |
279 | dss); |
280 | CTL_M2_GET("stats.arenas.0.lg_dirty_mult" , i, &lg_dirty_mult, ssize_t); |
281 | if (opt_purge == purge_mode_ratio) { |
282 | if (lg_dirty_mult >= 0) { |
283 | malloc_cprintf(write_cb, cbopaque, |
284 | "min active:dirty page ratio: %u:1\n" , |
285 | (1U << lg_dirty_mult)); |
286 | } else { |
287 | malloc_cprintf(write_cb, cbopaque, |
288 | "min active:dirty page ratio: N/A\n" ); |
289 | } |
290 | } |
291 | CTL_M2_GET("stats.arenas.0.decay_time" , i, &decay_time, ssize_t); |
292 | if (opt_purge == purge_mode_decay) { |
293 | if (decay_time >= 0) { |
294 | malloc_cprintf(write_cb, cbopaque, "decay time: %zd\n" , |
295 | decay_time); |
296 | } else |
297 | malloc_cprintf(write_cb, cbopaque, "decay time: N/A\n" ); |
298 | } |
299 | CTL_M2_GET("stats.arenas.0.pactive" , i, &pactive, size_t); |
300 | CTL_M2_GET("stats.arenas.0.pdirty" , i, &pdirty, size_t); |
301 | CTL_M2_GET("stats.arenas.0.npurge" , i, &npurge, uint64_t); |
302 | CTL_M2_GET("stats.arenas.0.nmadvise" , i, &nmadvise, uint64_t); |
303 | CTL_M2_GET("stats.arenas.0.purged" , i, &purged, uint64_t); |
304 | malloc_cprintf(write_cb, cbopaque, |
305 | "purging: dirty: %zu, sweeps: %" FMTu64", madvises: %" FMTu64", " |
306 | "purged: %" FMTu64"\n" , pdirty, npurge, nmadvise, purged); |
307 | |
308 | malloc_cprintf(write_cb, cbopaque, |
309 | " allocated nmalloc ndalloc" |
310 | " nrequests\n" ); |
311 | CTL_M2_GET("stats.arenas.0.small.allocated" , i, &small_allocated, |
312 | size_t); |
313 | CTL_M2_GET("stats.arenas.0.small.nmalloc" , i, &small_nmalloc, uint64_t); |
314 | CTL_M2_GET("stats.arenas.0.small.ndalloc" , i, &small_ndalloc, uint64_t); |
315 | CTL_M2_GET("stats.arenas.0.small.nrequests" , i, &small_nrequests, |
316 | uint64_t); |
317 | malloc_cprintf(write_cb, cbopaque, |
318 | "small: %12zu %12" FMTu64" %12" FMTu64 |
319 | " %12" FMTu64"\n" , |
320 | small_allocated, small_nmalloc, small_ndalloc, small_nrequests); |
321 | CTL_M2_GET("stats.arenas.0.large.allocated" , i, &large_allocated, |
322 | size_t); |
323 | CTL_M2_GET("stats.arenas.0.large.nmalloc" , i, &large_nmalloc, uint64_t); |
324 | CTL_M2_GET("stats.arenas.0.large.ndalloc" , i, &large_ndalloc, uint64_t); |
325 | CTL_M2_GET("stats.arenas.0.large.nrequests" , i, &large_nrequests, |
326 | uint64_t); |
327 | malloc_cprintf(write_cb, cbopaque, |
328 | "large: %12zu %12" FMTu64" %12" FMTu64 |
329 | " %12" FMTu64"\n" , |
330 | large_allocated, large_nmalloc, large_ndalloc, large_nrequests); |
331 | CTL_M2_GET("stats.arenas.0.huge.allocated" , i, &huge_allocated, size_t); |
332 | CTL_M2_GET("stats.arenas.0.huge.nmalloc" , i, &huge_nmalloc, uint64_t); |
333 | CTL_M2_GET("stats.arenas.0.huge.ndalloc" , i, &huge_ndalloc, uint64_t); |
334 | CTL_M2_GET("stats.arenas.0.huge.nrequests" , i, &huge_nrequests, |
335 | uint64_t); |
336 | malloc_cprintf(write_cb, cbopaque, |
337 | "huge: %12zu %12" FMTu64" %12" FMTu64 |
338 | " %12" FMTu64"\n" , |
339 | huge_allocated, huge_nmalloc, huge_ndalloc, huge_nrequests); |
340 | malloc_cprintf(write_cb, cbopaque, |
341 | "total: %12zu %12" FMTu64" %12" FMTu64 |
342 | " %12" FMTu64"\n" , |
343 | small_allocated + large_allocated + huge_allocated, |
344 | small_nmalloc + large_nmalloc + huge_nmalloc, |
345 | small_ndalloc + large_ndalloc + huge_ndalloc, |
346 | small_nrequests + large_nrequests + huge_nrequests); |
347 | malloc_cprintf(write_cb, cbopaque, |
348 | "active: %12zu\n" , pactive * page); |
349 | CTL_M2_GET("stats.arenas.0.mapped" , i, &mapped, size_t); |
350 | malloc_cprintf(write_cb, cbopaque, |
351 | "mapped: %12zu\n" , mapped); |
352 | CTL_M2_GET("stats.arenas.0.retained" , i, &retained, size_t); |
353 | malloc_cprintf(write_cb, cbopaque, |
354 | "retained: %12zu\n" , retained); |
355 | CTL_M2_GET("stats.arenas.0.metadata.mapped" , i, &metadata_mapped, |
356 | size_t); |
357 | CTL_M2_GET("stats.arenas.0.metadata.allocated" , i, &metadata_allocated, |
358 | size_t); |
359 | malloc_cprintf(write_cb, cbopaque, |
360 | "metadata: mapped: %zu, allocated: %zu\n" , |
361 | metadata_mapped, metadata_allocated); |
362 | |
363 | if (bins) |
364 | stats_arena_bins_print(write_cb, cbopaque, i); |
365 | if (large) |
366 | stats_arena_lruns_print(write_cb, cbopaque, i); |
367 | if (huge) |
368 | stats_arena_hchunks_print(write_cb, cbopaque, i); |
369 | } |
370 | |
371 | void |
372 | stats_print(void (*write_cb)(void *, const char *), void *cbopaque, |
373 | const char *opts) |
374 | { |
375 | int err; |
376 | uint64_t epoch; |
377 | size_t u64sz; |
378 | bool general = true; |
379 | bool merged = true; |
380 | bool unmerged = true; |
381 | bool bins = true; |
382 | bool large = true; |
383 | bool huge = true; |
384 | |
385 | /* |
386 | * Refresh stats, in case mallctl() was called by the application. |
387 | * |
388 | * Check for OOM here, since refreshing the ctl cache can trigger |
389 | * allocation. In practice, none of the subsequent mallctl()-related |
390 | * calls in this function will cause OOM if this one succeeds. |
391 | * */ |
392 | epoch = 1; |
393 | u64sz = sizeof(uint64_t); |
394 | err = je_mallctl("epoch" , &epoch, &u64sz, &epoch, sizeof(uint64_t)); |
395 | if (err != 0) { |
396 | if (err == EAGAIN) { |
397 | malloc_write("<jemalloc>: Memory allocation failure in " |
398 | "mallctl(\"epoch\", ...)\n" ); |
399 | return; |
400 | } |
401 | malloc_write("<jemalloc>: Failure in mallctl(\"epoch\", " |
402 | "...)\n" ); |
403 | abort(); |
404 | } |
405 | |
406 | if (opts != NULL) { |
407 | unsigned i; |
408 | |
409 | for (i = 0; opts[i] != '\0'; i++) { |
410 | switch (opts[i]) { |
411 | case 'g': |
412 | general = false; |
413 | break; |
414 | case 'm': |
415 | merged = false; |
416 | break; |
417 | case 'a': |
418 | unmerged = false; |
419 | break; |
420 | case 'b': |
421 | bins = false; |
422 | break; |
423 | case 'l': |
424 | large = false; |
425 | break; |
426 | case 'h': |
427 | huge = false; |
428 | break; |
429 | default:; |
430 | } |
431 | } |
432 | } |
433 | |
434 | malloc_cprintf(write_cb, cbopaque, |
435 | "___ Begin jemalloc statistics ___\n" ); |
436 | if (general) { |
437 | const char *cpv; |
438 | bool bv; |
439 | unsigned uv; |
440 | ssize_t ssv; |
441 | size_t sv, bsz, usz, ssz, sssz, cpsz; |
442 | |
443 | bsz = sizeof(bool); |
444 | usz = sizeof(unsigned); |
445 | ssz = sizeof(size_t); |
446 | sssz = sizeof(ssize_t); |
447 | cpsz = sizeof(const char *); |
448 | |
449 | CTL_GET("version" , &cpv, const char *); |
450 | malloc_cprintf(write_cb, cbopaque, "Version: %s\n" , cpv); |
451 | CTL_GET("config.debug" , &bv, bool); |
452 | malloc_cprintf(write_cb, cbopaque, "Assertions %s\n" , |
453 | bv ? "enabled" : "disabled" ); |
454 | malloc_cprintf(write_cb, cbopaque, |
455 | "config.malloc_conf: \"%s\"\n" , config_malloc_conf); |
456 | |
457 | #define OPT_WRITE_BOOL(n) \ |
458 | if (je_mallctl("opt."#n, &bv, &bsz, NULL, 0) == 0) { \ |
459 | malloc_cprintf(write_cb, cbopaque, \ |
460 | " opt."#n": %s\n", bv ? "true" : "false"); \ |
461 | } |
462 | #define OPT_WRITE_BOOL_MUTABLE(n, m) { \ |
463 | bool bv2; \ |
464 | if (je_mallctl("opt."#n, &bv, &bsz, NULL, 0) == 0 && \ |
465 | je_mallctl(#m, &bv2, &bsz, NULL, 0) == 0) { \ |
466 | malloc_cprintf(write_cb, cbopaque, \ |
467 | " opt."#n": %s ("#m": %s)\n", bv ? "true" \ |
468 | : "false", bv2 ? "true" : "false"); \ |
469 | } \ |
470 | } |
471 | #define OPT_WRITE_UNSIGNED(n) \ |
472 | if (je_mallctl("opt."#n, &uv, &usz, NULL, 0) == 0) { \ |
473 | malloc_cprintf(write_cb, cbopaque, \ |
474 | " opt."#n": %u\n", uv); \ |
475 | } |
476 | #define OPT_WRITE_SIZE_T(n) \ |
477 | if (je_mallctl("opt."#n, &sv, &ssz, NULL, 0) == 0) { \ |
478 | malloc_cprintf(write_cb, cbopaque, \ |
479 | " opt."#n": %zu\n", sv); \ |
480 | } |
481 | #define OPT_WRITE_SSIZE_T(n) \ |
482 | if (je_mallctl("opt."#n, &ssv, &sssz, NULL, 0) == 0) { \ |
483 | malloc_cprintf(write_cb, cbopaque, \ |
484 | " opt."#n": %zd\n", ssv); \ |
485 | } |
486 | #define OPT_WRITE_SSIZE_T_MUTABLE(n, m) { \ |
487 | ssize_t ssv2; \ |
488 | if (je_mallctl("opt."#n, &ssv, &sssz, NULL, 0) == 0 && \ |
489 | je_mallctl(#m, &ssv2, &sssz, NULL, 0) == 0) { \ |
490 | malloc_cprintf(write_cb, cbopaque, \ |
491 | " opt."#n": %zd ("#m": %zd)\n", \ |
492 | ssv, ssv2); \ |
493 | } \ |
494 | } |
495 | #define OPT_WRITE_CHAR_P(n) \ |
496 | if (je_mallctl("opt."#n, &cpv, &cpsz, NULL, 0) == 0) { \ |
497 | malloc_cprintf(write_cb, cbopaque, \ |
498 | " opt."#n": \"%s\"\n", cpv); \ |
499 | } |
500 | |
501 | malloc_cprintf(write_cb, cbopaque, |
502 | "Run-time option settings:\n" ); |
503 | OPT_WRITE_BOOL(abort) |
504 | OPT_WRITE_SIZE_T(lg_chunk) |
505 | OPT_WRITE_CHAR_P(dss) |
506 | OPT_WRITE_UNSIGNED(narenas) |
507 | OPT_WRITE_CHAR_P(purge) |
508 | if (opt_purge == purge_mode_ratio) { |
509 | OPT_WRITE_SSIZE_T_MUTABLE(lg_dirty_mult, |
510 | arenas.lg_dirty_mult) |
511 | } |
512 | if (opt_purge == purge_mode_decay) |
513 | OPT_WRITE_SSIZE_T_MUTABLE(decay_time, arenas.decay_time) |
514 | OPT_WRITE_BOOL(stats_print) |
515 | OPT_WRITE_CHAR_P(junk) |
516 | OPT_WRITE_SIZE_T(quarantine) |
517 | OPT_WRITE_BOOL(redzone) |
518 | OPT_WRITE_BOOL(zero) |
519 | OPT_WRITE_BOOL(utrace) |
520 | OPT_WRITE_BOOL(valgrind) |
521 | OPT_WRITE_BOOL(xmalloc) |
522 | OPT_WRITE_BOOL(tcache) |
523 | OPT_WRITE_SSIZE_T(lg_tcache_max) |
524 | OPT_WRITE_BOOL(prof) |
525 | OPT_WRITE_CHAR_P(prof_prefix) |
526 | OPT_WRITE_BOOL_MUTABLE(prof_active, prof.active) |
527 | OPT_WRITE_BOOL_MUTABLE(prof_thread_active_init, |
528 | prof.thread_active_init) |
529 | OPT_WRITE_SSIZE_T(lg_prof_sample) |
530 | OPT_WRITE_BOOL(prof_accum) |
531 | OPT_WRITE_SSIZE_T(lg_prof_interval) |
532 | OPT_WRITE_BOOL(prof_gdump) |
533 | OPT_WRITE_BOOL(prof_final) |
534 | OPT_WRITE_BOOL(prof_leak) |
535 | |
536 | #undef OPT_WRITE_BOOL |
537 | #undef OPT_WRITE_BOOL_MUTABLE |
538 | #undef OPT_WRITE_SIZE_T |
539 | #undef OPT_WRITE_SSIZE_T |
540 | #undef OPT_WRITE_CHAR_P |
541 | |
542 | malloc_cprintf(write_cb, cbopaque, "CPUs: %u\n" , ncpus); |
543 | |
544 | CTL_GET("arenas.narenas" , &uv, unsigned); |
545 | malloc_cprintf(write_cb, cbopaque, "Arenas: %u\n" , uv); |
546 | |
547 | malloc_cprintf(write_cb, cbopaque, "Pointer size: %zu\n" , |
548 | sizeof(void *)); |
549 | |
550 | CTL_GET("arenas.quantum" , &sv, size_t); |
551 | malloc_cprintf(write_cb, cbopaque, "Quantum size: %zu\n" , |
552 | sv); |
553 | |
554 | CTL_GET("arenas.page" , &sv, size_t); |
555 | malloc_cprintf(write_cb, cbopaque, "Page size: %zu\n" , sv); |
556 | |
557 | CTL_GET("arenas.lg_dirty_mult" , &ssv, ssize_t); |
558 | if (opt_purge == purge_mode_ratio) { |
559 | if (ssv >= 0) { |
560 | malloc_cprintf(write_cb, cbopaque, |
561 | "Min active:dirty page ratio per arena: " |
562 | "%u:1\n" , (1U << ssv)); |
563 | } else { |
564 | malloc_cprintf(write_cb, cbopaque, |
565 | "Min active:dirty page ratio per arena: " |
566 | "N/A\n" ); |
567 | } |
568 | } |
569 | CTL_GET("arenas.decay_time" , &ssv, ssize_t); |
570 | if (opt_purge == purge_mode_decay) { |
571 | malloc_cprintf(write_cb, cbopaque, |
572 | "Unused dirty page decay time: %zd%s\n" , |
573 | ssv, (ssv < 0) ? " (no decay)" : "" ); |
574 | } |
575 | if (je_mallctl("arenas.tcache_max" , &sv, &ssz, NULL, 0) == 0) { |
576 | malloc_cprintf(write_cb, cbopaque, |
577 | "Maximum thread-cached size class: %zu\n" , sv); |
578 | } |
579 | if (je_mallctl("opt.prof" , &bv, &bsz, NULL, 0) == 0 && bv) { |
580 | CTL_GET("prof.lg_sample" , &sv, size_t); |
581 | malloc_cprintf(write_cb, cbopaque, |
582 | "Average profile sample interval: %" FMTu64 |
583 | " (2^%zu)\n" , (((uint64_t)1U) << sv), sv); |
584 | |
585 | CTL_GET("opt.lg_prof_interval" , &ssv, ssize_t); |
586 | if (ssv >= 0) { |
587 | malloc_cprintf(write_cb, cbopaque, |
588 | "Average profile dump interval: %" FMTu64 |
589 | " (2^%zd)\n" , |
590 | (((uint64_t)1U) << ssv), ssv); |
591 | } else { |
592 | malloc_cprintf(write_cb, cbopaque, |
593 | "Average profile dump interval: N/A\n" ); |
594 | } |
595 | } |
596 | CTL_GET("opt.lg_chunk" , &sv, size_t); |
597 | malloc_cprintf(write_cb, cbopaque, |
598 | "Chunk size: %zu (2^%zu)\n" , (ZU(1) << sv), sv); |
599 | } |
600 | |
601 | if (config_stats) { |
602 | size_t *cactive; |
603 | size_t allocated, active, metadata, resident, mapped, retained; |
604 | |
605 | CTL_GET("stats.cactive" , &cactive, size_t *); |
606 | CTL_GET("stats.allocated" , &allocated, size_t); |
607 | CTL_GET("stats.active" , &active, size_t); |
608 | CTL_GET("stats.metadata" , &metadata, size_t); |
609 | CTL_GET("stats.resident" , &resident, size_t); |
610 | CTL_GET("stats.mapped" , &mapped, size_t); |
611 | CTL_GET("stats.retained" , &retained, size_t); |
612 | malloc_cprintf(write_cb, cbopaque, |
613 | "Allocated: %zu, active: %zu, metadata: %zu," |
614 | " resident: %zu, mapped: %zu, retained: %zu\n" , |
615 | allocated, active, metadata, resident, mapped, retained); |
616 | malloc_cprintf(write_cb, cbopaque, |
617 | "Current active ceiling: %zu\n" , |
618 | atomic_read_z(cactive)); |
619 | |
620 | if (merged) { |
621 | unsigned narenas; |
622 | |
623 | CTL_GET("arenas.narenas" , &narenas, unsigned); |
624 | { |
625 | VARIABLE_ARRAY(bool, initialized, narenas); |
626 | size_t isz; |
627 | unsigned i, ninitialized; |
628 | |
629 | isz = sizeof(bool) * narenas; |
630 | xmallctl("arenas.initialized" , initialized, |
631 | &isz, NULL, 0); |
632 | for (i = ninitialized = 0; i < narenas; i++) { |
633 | if (initialized[i]) |
634 | ninitialized++; |
635 | } |
636 | |
637 | if (ninitialized > 1 || !unmerged) { |
638 | /* Print merged arena stats. */ |
639 | malloc_cprintf(write_cb, cbopaque, |
640 | "\nMerged arenas stats:\n" ); |
641 | stats_arena_print(write_cb, cbopaque, |
642 | narenas, bins, large, huge); |
643 | } |
644 | } |
645 | } |
646 | |
647 | if (unmerged) { |
648 | unsigned narenas; |
649 | |
650 | /* Print stats for each arena. */ |
651 | |
652 | CTL_GET("arenas.narenas" , &narenas, unsigned); |
653 | { |
654 | VARIABLE_ARRAY(bool, initialized, narenas); |
655 | size_t isz; |
656 | unsigned i; |
657 | |
658 | isz = sizeof(bool) * narenas; |
659 | xmallctl("arenas.initialized" , initialized, |
660 | &isz, NULL, 0); |
661 | |
662 | for (i = 0; i < narenas; i++) { |
663 | if (initialized[i]) { |
664 | malloc_cprintf(write_cb, |
665 | cbopaque, |
666 | "\narenas[%u]:\n" , i); |
667 | stats_arena_print(write_cb, |
668 | cbopaque, i, bins, large, |
669 | huge); |
670 | } |
671 | } |
672 | } |
673 | } |
674 | } |
675 | malloc_cprintf(write_cb, cbopaque, "--- End jemalloc statistics ---\n" ); |
676 | } |
677 | |