Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/jemalloc/src/prof.c
39478 views
1
#include "jemalloc/internal/jemalloc_preamble.h"
2
#include "jemalloc/internal/jemalloc_internal_includes.h"
3
4
#include "jemalloc/internal/ctl.h"
5
#include "jemalloc/internal/assert.h"
6
#include "jemalloc/internal/mutex.h"
7
#include "jemalloc/internal/counter.h"
8
#include "jemalloc/internal/prof_data.h"
9
#include "jemalloc/internal/prof_log.h"
10
#include "jemalloc/internal/prof_recent.h"
11
#include "jemalloc/internal/prof_stats.h"
12
#include "jemalloc/internal/prof_sys.h"
13
#include "jemalloc/internal/prof_hook.h"
14
#include "jemalloc/internal/thread_event.h"
15
16
/*
17
* This file implements the profiling "APIs" needed by other parts of jemalloc,
18
* and also manages the relevant "operational" data, mainly options and mutexes;
19
* the core profiling data structures are encapsulated in prof_data.c.
20
*/
21
22
/******************************************************************************/
23
24
/* Data. */
25
26
bool opt_prof = false;
27
bool opt_prof_active = true;
28
bool opt_prof_thread_active_init = true;
29
size_t opt_lg_prof_sample = LG_PROF_SAMPLE_DEFAULT;
30
ssize_t opt_lg_prof_interval = LG_PROF_INTERVAL_DEFAULT;
31
bool opt_prof_gdump = false;
32
bool opt_prof_final = false;
33
bool opt_prof_leak = false;
34
bool opt_prof_leak_error = false;
35
bool opt_prof_accum = false;
36
char opt_prof_prefix[PROF_DUMP_FILENAME_LEN];
37
bool opt_prof_sys_thread_name = false;
38
bool opt_prof_unbias = true;
39
40
/* Accessed via prof_sample_event_handler(). */
41
static counter_accum_t prof_idump_accumulated;
42
43
/*
44
* Initialized as opt_prof_active, and accessed via
45
* prof_active_[gs]et{_unlocked,}().
46
*/
47
bool prof_active_state;
48
static malloc_mutex_t prof_active_mtx;
49
50
/*
51
* Initialized as opt_prof_thread_active_init, and accessed via
52
* prof_thread_active_init_[gs]et().
53
*/
54
static bool prof_thread_active_init;
55
static malloc_mutex_t prof_thread_active_init_mtx;
56
57
/*
58
* Initialized as opt_prof_gdump, and accessed via
59
* prof_gdump_[gs]et{_unlocked,}().
60
*/
61
bool prof_gdump_val;
62
static malloc_mutex_t prof_gdump_mtx;
63
64
uint64_t prof_interval = 0;
65
66
size_t lg_prof_sample;
67
68
static uint64_t next_thr_uid;
69
static malloc_mutex_t next_thr_uid_mtx;
70
71
/* Do not dump any profiles until bootstrapping is complete. */
72
bool prof_booted = false;
73
74
/* Logically a prof_backtrace_hook_t. */
75
atomic_p_t prof_backtrace_hook;
76
77
/* Logically a prof_dump_hook_t. */
78
atomic_p_t prof_dump_hook;
79
80
/******************************************************************************/
81
82
void
83
prof_alloc_rollback(tsd_t *tsd, prof_tctx_t *tctx) {
84
cassert(config_prof);
85
86
if (tsd_reentrancy_level_get(tsd) > 0) {
87
assert((uintptr_t)tctx == (uintptr_t)1U);
88
return;
89
}
90
91
if ((uintptr_t)tctx > (uintptr_t)1U) {
92
malloc_mutex_lock(tsd_tsdn(tsd), tctx->tdata->lock);
93
tctx->prepared = false;
94
prof_tctx_try_destroy(tsd, tctx);
95
}
96
}
97
98
void
99
prof_malloc_sample_object(tsd_t *tsd, const void *ptr, size_t size,
100
size_t usize, prof_tctx_t *tctx) {
101
cassert(config_prof);
102
103
if (opt_prof_sys_thread_name) {
104
prof_sys_thread_name_fetch(tsd);
105
}
106
107
edata_t *edata = emap_edata_lookup(tsd_tsdn(tsd), &arena_emap_global,
108
ptr);
109
prof_info_set(tsd, edata, tctx, size);
110
111
szind_t szind = sz_size2index(usize);
112
113
malloc_mutex_lock(tsd_tsdn(tsd), tctx->tdata->lock);
114
/*
115
* We need to do these map lookups while holding the lock, to avoid the
116
* possibility of races with prof_reset calls, which update the map and
117
* then acquire the lock. This actually still leaves a data race on the
118
* contents of the unbias map, but we have not yet gone through and
119
* atomic-ified the prof module, and compilers are not yet causing us
120
* issues. The key thing is to make sure that, if we read garbage data,
121
* the prof_reset call is about to mark our tctx as expired before any
122
* dumping of our corrupted output is attempted.
123
*/
124
size_t shifted_unbiased_cnt = prof_shifted_unbiased_cnt[szind];
125
size_t unbiased_bytes = prof_unbiased_sz[szind];
126
tctx->cnts.curobjs++;
127
tctx->cnts.curobjs_shifted_unbiased += shifted_unbiased_cnt;
128
tctx->cnts.curbytes += usize;
129
tctx->cnts.curbytes_unbiased += unbiased_bytes;
130
if (opt_prof_accum) {
131
tctx->cnts.accumobjs++;
132
tctx->cnts.accumobjs_shifted_unbiased += shifted_unbiased_cnt;
133
tctx->cnts.accumbytes += usize;
134
tctx->cnts.accumbytes_unbiased += unbiased_bytes;
135
}
136
bool record_recent = prof_recent_alloc_prepare(tsd, tctx);
137
tctx->prepared = false;
138
malloc_mutex_unlock(tsd_tsdn(tsd), tctx->tdata->lock);
139
if (record_recent) {
140
assert(tctx == edata_prof_tctx_get(edata));
141
prof_recent_alloc(tsd, edata, size, usize);
142
}
143
144
if (opt_prof_stats) {
145
prof_stats_inc(tsd, szind, size);
146
}
147
}
148
149
void
150
prof_free_sampled_object(tsd_t *tsd, size_t usize, prof_info_t *prof_info) {
151
cassert(config_prof);
152
153
assert(prof_info != NULL);
154
prof_tctx_t *tctx = prof_info->alloc_tctx;
155
assert((uintptr_t)tctx > (uintptr_t)1U);
156
157
szind_t szind = sz_size2index(usize);
158
malloc_mutex_lock(tsd_tsdn(tsd), tctx->tdata->lock);
159
160
assert(tctx->cnts.curobjs > 0);
161
assert(tctx->cnts.curbytes >= usize);
162
/*
163
* It's not correct to do equivalent asserts for unbiased bytes, because
164
* of the potential for races with prof.reset calls. The map contents
165
* should really be atomic, but we have not atomic-ified the prof module
166
* yet.
167
*/
168
tctx->cnts.curobjs--;
169
tctx->cnts.curobjs_shifted_unbiased -= prof_shifted_unbiased_cnt[szind];
170
tctx->cnts.curbytes -= usize;
171
tctx->cnts.curbytes_unbiased -= prof_unbiased_sz[szind];
172
173
prof_try_log(tsd, usize, prof_info);
174
175
prof_tctx_try_destroy(tsd, tctx);
176
177
if (opt_prof_stats) {
178
prof_stats_dec(tsd, szind, prof_info->alloc_size);
179
}
180
}
181
182
prof_tctx_t *
183
prof_tctx_create(tsd_t *tsd) {
184
if (!tsd_nominal(tsd) || tsd_reentrancy_level_get(tsd) > 0) {
185
return NULL;
186
}
187
188
prof_tdata_t *tdata = prof_tdata_get(tsd, true);
189
if (tdata == NULL) {
190
return NULL;
191
}
192
193
prof_bt_t bt;
194
bt_init(&bt, tdata->vec);
195
prof_backtrace(tsd, &bt);
196
return prof_lookup(tsd, &bt);
197
}
198
199
/*
200
* The bodies of this function and prof_leakcheck() are compiled out unless heap
201
* profiling is enabled, so that it is possible to compile jemalloc with
202
* floating point support completely disabled. Avoiding floating point code is
203
* important on memory-constrained systems, but it also enables a workaround for
204
* versions of glibc that don't properly save/restore floating point registers
205
* during dynamic lazy symbol loading (which internally calls into whatever
206
* malloc implementation happens to be integrated into the application). Note
207
* that some compilers (e.g. gcc 4.8) may use floating point registers for fast
208
* memory moves, so jemalloc must be compiled with such optimizations disabled
209
* (e.g.
210
* -mno-sse) in order for the workaround to be complete.
211
*/
212
uint64_t
213
prof_sample_new_event_wait(tsd_t *tsd) {
214
#ifdef JEMALLOC_PROF
215
if (lg_prof_sample == 0) {
216
return TE_MIN_START_WAIT;
217
}
218
219
/*
220
* Compute sample interval as a geometrically distributed random
221
* variable with mean (2^lg_prof_sample).
222
*
223
* __ __
224
* | log(u) | 1
225
* bytes_until_sample = | -------- |, where p = ---------------
226
* | log(1-p) | lg_prof_sample
227
* 2
228
*
229
* For more information on the math, see:
230
*
231
* Non-Uniform Random Variate Generation
232
* Luc Devroye
233
* Springer-Verlag, New York, 1986
234
* pp 500
235
* (http://luc.devroye.org/rnbookindex.html)
236
*
237
* In the actual computation, there's a non-zero probability that our
238
* pseudo random number generator generates an exact 0, and to avoid
239
* log(0), we set u to 1.0 in case r is 0. Therefore u effectively is
240
* uniformly distributed in (0, 1] instead of [0, 1). Further, rather
241
* than taking the ceiling, we take the floor and then add 1, since
242
* otherwise bytes_until_sample would be 0 if u is exactly 1.0.
243
*/
244
uint64_t r = prng_lg_range_u64(tsd_prng_statep_get(tsd), 53);
245
double u = (r == 0U) ? 1.0 : (double)r * (1.0/9007199254740992.0L);
246
return (uint64_t)(log(u) /
247
log(1.0 - (1.0 / (double)((uint64_t)1U << lg_prof_sample))))
248
+ (uint64_t)1U;
249
#else
250
not_reached();
251
return TE_MAX_START_WAIT;
252
#endif
253
}
254
255
uint64_t
256
prof_sample_postponed_event_wait(tsd_t *tsd) {
257
/*
258
* The postponed wait time for prof sample event is computed as if we
259
* want a new wait time (i.e. as if the event were triggered). If we
260
* instead postpone to the immediate next allocation, like how we're
261
* handling the other events, then we can have sampling bias, if e.g.
262
* the allocation immediately following a reentrancy always comes from
263
* the same stack trace.
264
*/
265
return prof_sample_new_event_wait(tsd);
266
}
267
268
void
269
prof_sample_event_handler(tsd_t *tsd, uint64_t elapsed) {
270
cassert(config_prof);
271
assert(elapsed > 0 && elapsed != TE_INVALID_ELAPSED);
272
if (prof_interval == 0 || !prof_active_get_unlocked()) {
273
return;
274
}
275
if (counter_accum(tsd_tsdn(tsd), &prof_idump_accumulated, elapsed)) {
276
prof_idump(tsd_tsdn(tsd));
277
}
278
}
279
280
static void
281
prof_fdump(void) {
282
tsd_t *tsd;
283
284
cassert(config_prof);
285
assert(opt_prof_final);
286
287
if (!prof_booted) {
288
return;
289
}
290
tsd = tsd_fetch();
291
assert(tsd_reentrancy_level_get(tsd) == 0);
292
293
prof_fdump_impl(tsd);
294
}
295
296
static bool
297
prof_idump_accum_init(void) {
298
cassert(config_prof);
299
300
return counter_accum_init(&prof_idump_accumulated, prof_interval);
301
}
302
303
void
304
prof_idump(tsdn_t *tsdn) {
305
tsd_t *tsd;
306
prof_tdata_t *tdata;
307
308
cassert(config_prof);
309
310
if (!prof_booted || tsdn_null(tsdn) || !prof_active_get_unlocked()) {
311
return;
312
}
313
tsd = tsdn_tsd(tsdn);
314
if (tsd_reentrancy_level_get(tsd) > 0) {
315
return;
316
}
317
318
tdata = prof_tdata_get(tsd, true);
319
if (tdata == NULL) {
320
return;
321
}
322
if (tdata->enq) {
323
tdata->enq_idump = true;
324
return;
325
}
326
327
prof_idump_impl(tsd);
328
}
329
330
bool
331
prof_mdump(tsd_t *tsd, const char *filename) {
332
cassert(config_prof);
333
assert(tsd_reentrancy_level_get(tsd) == 0);
334
335
if (!opt_prof || !prof_booted) {
336
return true;
337
}
338
339
return prof_mdump_impl(tsd, filename);
340
}
341
342
void
343
prof_gdump(tsdn_t *tsdn) {
344
tsd_t *tsd;
345
prof_tdata_t *tdata;
346
347
cassert(config_prof);
348
349
if (!prof_booted || tsdn_null(tsdn) || !prof_active_get_unlocked()) {
350
return;
351
}
352
tsd = tsdn_tsd(tsdn);
353
if (tsd_reentrancy_level_get(tsd) > 0) {
354
return;
355
}
356
357
tdata = prof_tdata_get(tsd, false);
358
if (tdata == NULL) {
359
return;
360
}
361
if (tdata->enq) {
362
tdata->enq_gdump = true;
363
return;
364
}
365
366
prof_gdump_impl(tsd);
367
}
368
369
static uint64_t
370
prof_thr_uid_alloc(tsdn_t *tsdn) {
371
uint64_t thr_uid;
372
373
malloc_mutex_lock(tsdn, &next_thr_uid_mtx);
374
thr_uid = next_thr_uid;
375
next_thr_uid++;
376
malloc_mutex_unlock(tsdn, &next_thr_uid_mtx);
377
378
return thr_uid;
379
}
380
381
prof_tdata_t *
382
prof_tdata_init(tsd_t *tsd) {
383
return prof_tdata_init_impl(tsd, prof_thr_uid_alloc(tsd_tsdn(tsd)), 0,
384
NULL, prof_thread_active_init_get(tsd_tsdn(tsd)));
385
}
386
387
prof_tdata_t *
388
prof_tdata_reinit(tsd_t *tsd, prof_tdata_t *tdata) {
389
uint64_t thr_uid = tdata->thr_uid;
390
uint64_t thr_discrim = tdata->thr_discrim + 1;
391
char *thread_name = (tdata->thread_name != NULL) ?
392
prof_thread_name_alloc(tsd, tdata->thread_name) : NULL;
393
bool active = tdata->active;
394
395
prof_tdata_detach(tsd, tdata);
396
return prof_tdata_init_impl(tsd, thr_uid, thr_discrim, thread_name,
397
active);
398
}
399
400
void
401
prof_tdata_cleanup(tsd_t *tsd) {
402
prof_tdata_t *tdata;
403
404
if (!config_prof) {
405
return;
406
}
407
408
tdata = tsd_prof_tdata_get(tsd);
409
if (tdata != NULL) {
410
prof_tdata_detach(tsd, tdata);
411
}
412
}
413
414
bool
415
prof_active_get(tsdn_t *tsdn) {
416
bool prof_active_current;
417
418
prof_active_assert();
419
malloc_mutex_lock(tsdn, &prof_active_mtx);
420
prof_active_current = prof_active_state;
421
malloc_mutex_unlock(tsdn, &prof_active_mtx);
422
return prof_active_current;
423
}
424
425
bool
426
prof_active_set(tsdn_t *tsdn, bool active) {
427
bool prof_active_old;
428
429
prof_active_assert();
430
malloc_mutex_lock(tsdn, &prof_active_mtx);
431
prof_active_old = prof_active_state;
432
prof_active_state = active;
433
malloc_mutex_unlock(tsdn, &prof_active_mtx);
434
prof_active_assert();
435
return prof_active_old;
436
}
437
438
const char *
439
prof_thread_name_get(tsd_t *tsd) {
440
assert(tsd_reentrancy_level_get(tsd) == 0);
441
442
prof_tdata_t *tdata;
443
444
tdata = prof_tdata_get(tsd, true);
445
if (tdata == NULL) {
446
return "";
447
}
448
return (tdata->thread_name != NULL ? tdata->thread_name : "");
449
}
450
451
int
452
prof_thread_name_set(tsd_t *tsd, const char *thread_name) {
453
if (opt_prof_sys_thread_name) {
454
return ENOENT;
455
} else {
456
return prof_thread_name_set_impl(tsd, thread_name);
457
}
458
}
459
460
bool
461
prof_thread_active_get(tsd_t *tsd) {
462
assert(tsd_reentrancy_level_get(tsd) == 0);
463
464
prof_tdata_t *tdata;
465
466
tdata = prof_tdata_get(tsd, true);
467
if (tdata == NULL) {
468
return false;
469
}
470
return tdata->active;
471
}
472
473
bool
474
prof_thread_active_set(tsd_t *tsd, bool active) {
475
assert(tsd_reentrancy_level_get(tsd) == 0);
476
477
prof_tdata_t *tdata;
478
479
tdata = prof_tdata_get(tsd, true);
480
if (tdata == NULL) {
481
return true;
482
}
483
tdata->active = active;
484
return false;
485
}
486
487
bool
488
prof_thread_active_init_get(tsdn_t *tsdn) {
489
bool active_init;
490
491
malloc_mutex_lock(tsdn, &prof_thread_active_init_mtx);
492
active_init = prof_thread_active_init;
493
malloc_mutex_unlock(tsdn, &prof_thread_active_init_mtx);
494
return active_init;
495
}
496
497
bool
498
prof_thread_active_init_set(tsdn_t *tsdn, bool active_init) {
499
bool active_init_old;
500
501
malloc_mutex_lock(tsdn, &prof_thread_active_init_mtx);
502
active_init_old = prof_thread_active_init;
503
prof_thread_active_init = active_init;
504
malloc_mutex_unlock(tsdn, &prof_thread_active_init_mtx);
505
return active_init_old;
506
}
507
508
bool
509
prof_gdump_get(tsdn_t *tsdn) {
510
bool prof_gdump_current;
511
512
malloc_mutex_lock(tsdn, &prof_gdump_mtx);
513
prof_gdump_current = prof_gdump_val;
514
malloc_mutex_unlock(tsdn, &prof_gdump_mtx);
515
return prof_gdump_current;
516
}
517
518
bool
519
prof_gdump_set(tsdn_t *tsdn, bool gdump) {
520
bool prof_gdump_old;
521
522
malloc_mutex_lock(tsdn, &prof_gdump_mtx);
523
prof_gdump_old = prof_gdump_val;
524
prof_gdump_val = gdump;
525
malloc_mutex_unlock(tsdn, &prof_gdump_mtx);
526
return prof_gdump_old;
527
}
528
529
void
530
prof_backtrace_hook_set(prof_backtrace_hook_t hook) {
531
atomic_store_p(&prof_backtrace_hook, hook, ATOMIC_RELEASE);
532
}
533
534
prof_backtrace_hook_t
535
prof_backtrace_hook_get() {
536
return (prof_backtrace_hook_t)atomic_load_p(&prof_backtrace_hook,
537
ATOMIC_ACQUIRE);
538
}
539
540
void
541
prof_dump_hook_set(prof_dump_hook_t hook) {
542
atomic_store_p(&prof_dump_hook, hook, ATOMIC_RELEASE);
543
}
544
545
prof_dump_hook_t
546
prof_dump_hook_get() {
547
return (prof_dump_hook_t)atomic_load_p(&prof_dump_hook,
548
ATOMIC_ACQUIRE);
549
}
550
551
void
552
prof_boot0(void) {
553
cassert(config_prof);
554
555
memcpy(opt_prof_prefix, PROF_PREFIX_DEFAULT,
556
sizeof(PROF_PREFIX_DEFAULT));
557
}
558
559
void
560
prof_boot1(void) {
561
cassert(config_prof);
562
563
/*
564
* opt_prof must be in its final state before any arenas are
565
* initialized, so this function must be executed early.
566
*/
567
if (opt_prof_leak_error && !opt_prof_leak) {
568
opt_prof_leak = true;
569
}
570
571
if (opt_prof_leak && !opt_prof) {
572
/*
573
* Enable opt_prof, but in such a way that profiles are never
574
* automatically dumped.
575
*/
576
opt_prof = true;
577
opt_prof_gdump = false;
578
} else if (opt_prof) {
579
if (opt_lg_prof_interval >= 0) {
580
prof_interval = (((uint64_t)1U) <<
581
opt_lg_prof_interval);
582
}
583
}
584
}
585
586
bool
587
prof_boot2(tsd_t *tsd, base_t *base) {
588
cassert(config_prof);
589
590
/*
591
* Initialize the global mutexes unconditionally to maintain correct
592
* stats when opt_prof is false.
593
*/
594
if (malloc_mutex_init(&prof_active_mtx, "prof_active",
595
WITNESS_RANK_PROF_ACTIVE, malloc_mutex_rank_exclusive)) {
596
return true;
597
}
598
if (malloc_mutex_init(&prof_gdump_mtx, "prof_gdump",
599
WITNESS_RANK_PROF_GDUMP, malloc_mutex_rank_exclusive)) {
600
return true;
601
}
602
if (malloc_mutex_init(&prof_thread_active_init_mtx,
603
"prof_thread_active_init", WITNESS_RANK_PROF_THREAD_ACTIVE_INIT,
604
malloc_mutex_rank_exclusive)) {
605
return true;
606
}
607
if (malloc_mutex_init(&bt2gctx_mtx, "prof_bt2gctx",
608
WITNESS_RANK_PROF_BT2GCTX, malloc_mutex_rank_exclusive)) {
609
return true;
610
}
611
if (malloc_mutex_init(&tdatas_mtx, "prof_tdatas",
612
WITNESS_RANK_PROF_TDATAS, malloc_mutex_rank_exclusive)) {
613
return true;
614
}
615
if (malloc_mutex_init(&next_thr_uid_mtx, "prof_next_thr_uid",
616
WITNESS_RANK_PROF_NEXT_THR_UID, malloc_mutex_rank_exclusive)) {
617
return true;
618
}
619
if (malloc_mutex_init(&prof_stats_mtx, "prof_stats",
620
WITNESS_RANK_PROF_STATS, malloc_mutex_rank_exclusive)) {
621
return true;
622
}
623
if (malloc_mutex_init(&prof_dump_filename_mtx,
624
"prof_dump_filename", WITNESS_RANK_PROF_DUMP_FILENAME,
625
malloc_mutex_rank_exclusive)) {
626
return true;
627
}
628
if (malloc_mutex_init(&prof_dump_mtx, "prof_dump",
629
WITNESS_RANK_PROF_DUMP, malloc_mutex_rank_exclusive)) {
630
return true;
631
}
632
633
if (opt_prof) {
634
lg_prof_sample = opt_lg_prof_sample;
635
prof_unbias_map_init();
636
prof_active_state = opt_prof_active;
637
prof_gdump_val = opt_prof_gdump;
638
prof_thread_active_init = opt_prof_thread_active_init;
639
640
if (prof_data_init(tsd)) {
641
return true;
642
}
643
644
next_thr_uid = 0;
645
if (prof_idump_accum_init()) {
646
return true;
647
}
648
649
if (opt_prof_final && opt_prof_prefix[0] != '\0' &&
650
atexit(prof_fdump) != 0) {
651
malloc_write("<jemalloc>: Error in atexit()\n");
652
if (opt_abort) {
653
abort();
654
}
655
}
656
657
if (prof_log_init(tsd)) {
658
return true;
659
}
660
661
if (prof_recent_init()) {
662
return true;
663
}
664
665
prof_base = base;
666
667
gctx_locks = (malloc_mutex_t *)base_alloc(tsd_tsdn(tsd), base,
668
PROF_NCTX_LOCKS * sizeof(malloc_mutex_t), CACHELINE);
669
if (gctx_locks == NULL) {
670
return true;
671
}
672
for (unsigned i = 0; i < PROF_NCTX_LOCKS; i++) {
673
if (malloc_mutex_init(&gctx_locks[i], "prof_gctx",
674
WITNESS_RANK_PROF_GCTX,
675
malloc_mutex_rank_exclusive)) {
676
return true;
677
}
678
}
679
680
tdata_locks = (malloc_mutex_t *)base_alloc(tsd_tsdn(tsd), base,
681
PROF_NTDATA_LOCKS * sizeof(malloc_mutex_t), CACHELINE);
682
if (tdata_locks == NULL) {
683
return true;
684
}
685
for (unsigned i = 0; i < PROF_NTDATA_LOCKS; i++) {
686
if (malloc_mutex_init(&tdata_locks[i], "prof_tdata",
687
WITNESS_RANK_PROF_TDATA,
688
malloc_mutex_rank_exclusive)) {
689
return true;
690
}
691
}
692
693
prof_unwind_init();
694
prof_hooks_init();
695
}
696
prof_booted = true;
697
698
return false;
699
}
700
701
void
702
prof_prefork0(tsdn_t *tsdn) {
703
if (config_prof && opt_prof) {
704
unsigned i;
705
706
malloc_mutex_prefork(tsdn, &prof_dump_mtx);
707
malloc_mutex_prefork(tsdn, &bt2gctx_mtx);
708
malloc_mutex_prefork(tsdn, &tdatas_mtx);
709
for (i = 0; i < PROF_NTDATA_LOCKS; i++) {
710
malloc_mutex_prefork(tsdn, &tdata_locks[i]);
711
}
712
malloc_mutex_prefork(tsdn, &log_mtx);
713
for (i = 0; i < PROF_NCTX_LOCKS; i++) {
714
malloc_mutex_prefork(tsdn, &gctx_locks[i]);
715
}
716
malloc_mutex_prefork(tsdn, &prof_recent_dump_mtx);
717
}
718
}
719
720
void
721
prof_prefork1(tsdn_t *tsdn) {
722
if (config_prof && opt_prof) {
723
counter_prefork(tsdn, &prof_idump_accumulated);
724
malloc_mutex_prefork(tsdn, &prof_active_mtx);
725
malloc_mutex_prefork(tsdn, &prof_dump_filename_mtx);
726
malloc_mutex_prefork(tsdn, &prof_gdump_mtx);
727
malloc_mutex_prefork(tsdn, &prof_recent_alloc_mtx);
728
malloc_mutex_prefork(tsdn, &prof_stats_mtx);
729
malloc_mutex_prefork(tsdn, &next_thr_uid_mtx);
730
malloc_mutex_prefork(tsdn, &prof_thread_active_init_mtx);
731
}
732
}
733
734
void
735
prof_postfork_parent(tsdn_t *tsdn) {
736
if (config_prof && opt_prof) {
737
unsigned i;
738
739
malloc_mutex_postfork_parent(tsdn,
740
&prof_thread_active_init_mtx);
741
malloc_mutex_postfork_parent(tsdn, &next_thr_uid_mtx);
742
malloc_mutex_postfork_parent(tsdn, &prof_stats_mtx);
743
malloc_mutex_postfork_parent(tsdn, &prof_recent_alloc_mtx);
744
malloc_mutex_postfork_parent(tsdn, &prof_gdump_mtx);
745
malloc_mutex_postfork_parent(tsdn, &prof_dump_filename_mtx);
746
malloc_mutex_postfork_parent(tsdn, &prof_active_mtx);
747
counter_postfork_parent(tsdn, &prof_idump_accumulated);
748
malloc_mutex_postfork_parent(tsdn, &prof_recent_dump_mtx);
749
for (i = 0; i < PROF_NCTX_LOCKS; i++) {
750
malloc_mutex_postfork_parent(tsdn, &gctx_locks[i]);
751
}
752
malloc_mutex_postfork_parent(tsdn, &log_mtx);
753
for (i = 0; i < PROF_NTDATA_LOCKS; i++) {
754
malloc_mutex_postfork_parent(tsdn, &tdata_locks[i]);
755
}
756
malloc_mutex_postfork_parent(tsdn, &tdatas_mtx);
757
malloc_mutex_postfork_parent(tsdn, &bt2gctx_mtx);
758
malloc_mutex_postfork_parent(tsdn, &prof_dump_mtx);
759
}
760
}
761
762
void
763
prof_postfork_child(tsdn_t *tsdn) {
764
if (config_prof && opt_prof) {
765
unsigned i;
766
767
malloc_mutex_postfork_child(tsdn, &prof_thread_active_init_mtx);
768
malloc_mutex_postfork_child(tsdn, &next_thr_uid_mtx);
769
malloc_mutex_postfork_child(tsdn, &prof_stats_mtx);
770
malloc_mutex_postfork_child(tsdn, &prof_recent_alloc_mtx);
771
malloc_mutex_postfork_child(tsdn, &prof_gdump_mtx);
772
malloc_mutex_postfork_child(tsdn, &prof_dump_filename_mtx);
773
malloc_mutex_postfork_child(tsdn, &prof_active_mtx);
774
counter_postfork_child(tsdn, &prof_idump_accumulated);
775
malloc_mutex_postfork_child(tsdn, &prof_recent_dump_mtx);
776
for (i = 0; i < PROF_NCTX_LOCKS; i++) {
777
malloc_mutex_postfork_child(tsdn, &gctx_locks[i]);
778
}
779
malloc_mutex_postfork_child(tsdn, &log_mtx);
780
for (i = 0; i < PROF_NTDATA_LOCKS; i++) {
781
malloc_mutex_postfork_child(tsdn, &tdata_locks[i]);
782
}
783
malloc_mutex_postfork_child(tsdn, &tdatas_mtx);
784
malloc_mutex_postfork_child(tsdn, &bt2gctx_mtx);
785
malloc_mutex_postfork_child(tsdn, &prof_dump_mtx);
786
}
787
}
788
789
/******************************************************************************/
790
791