prof.h revision 0b25fe79aaf8840a5acda7e3160a053d42349872
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/******************************************************************************/
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef JEMALLOC_H_TYPES
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct prof_bt_s prof_bt_t;
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct prof_cnt_s prof_cnt_t;
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct prof_thr_cnt_s prof_thr_cnt_t;
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct prof_ctx_s prof_ctx_t;
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct prof_tdata_s prof_tdata_t;
9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Option defaults. */
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define	PROF_PREFIX_DEFAULT		"jeprof"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define	LG_PROF_SAMPLE_DEFAULT		19
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define	LG_PROF_INTERVAL_DEFAULT	-1
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)/*
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Hard limit on stack backtrace depth.  The version of prof_backtrace() that
17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) * is based on __builtin_return_address() necessarily has a hard-coded number
18d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) * of backtrace frame handlers, and should be kept in sync with this setting.
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define	PROF_BT_MAX			128
21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Maximum number of backtraces to store in each per thread LRU cache. */
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define	PROF_TCMAX			1024
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Initial hash table size. */
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define	PROF_CKH_MINITEMS		64
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Size of memory buffer to use when writing dump files. */
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define	PROF_DUMP_BUFSIZE		65536
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Size of stack-allocated buffer used by prof_printf(). */
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define	PROF_PRINTF_BUFSIZE		128
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Number of mutexes shared among all ctx's.  No space is allocated for these
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * unless profiling is enabled, so it's okay to over-provision.
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define	PROF_NCTX_LOCKS			1024
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif /* JEMALLOC_H_TYPES */
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/******************************************************************************/
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef JEMALLOC_H_STRUCTS
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct prof_bt_s {
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/* Backtrace, stored as len program counters. */
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	void		**vec;
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	unsigned	len;
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#ifdef JEMALLOC_PROF_LIBGCC
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/* Data structure passed to libgcc _Unwind_Backtrace() callback functions. */
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	prof_bt_t	*bt;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	unsigned	nignore;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	unsigned	max;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} prof_unwind_data_t;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct prof_cnt_s {
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/*
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * Profiling counters.  An allocation/deallocation pair can operate on
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * different prof_thr_cnt_t objects that are linked into the same
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * prof_ctx_t cnts_ql, so it is possible for the cur* counters to go
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * negative.  In principle it is possible for the *bytes counters to
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * overflow/underflow, but a general solution would require something
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * like 128-bit counters; this implementation doesn't bother to solve
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * that problem.
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 */
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int64_t		curobjs;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	int64_t		curbytes;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	uint64_t	accumobjs;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	uint64_t	accumbytes;
734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)};
744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)struct prof_thr_cnt_s {
764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)	/* Linkage into prof_ctx_t's cnts_ql. */
774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)	ql_elm(prof_thr_cnt_t)	cnts_link;
784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)	/* Linkage into thread's LRU. */
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	ql_elm(prof_thr_cnt_t)	lru_link;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/*
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * Associated context.  If a thread frees an object that it did not
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * allocate, it is possible that the context is not cached in the
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * thread's hash table, in which case it must be able to look up the
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * context, insert a new prof_thr_cnt_t into the thread's hash table,
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	 * and link it into the prof_ctx_t's cnts_ql.
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	 */
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	prof_ctx_t		*ctx;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/*
92a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)	 * Threads use memory barriers to update the counters.  Since there is
93a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)	 * only ever one writer, the only challenge is for the reader to get a
94a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)	 * consistent read of the counters.
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 *
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * The writer uses this series of operations:
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 *
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * 1) Increment epoch to an odd number.
99a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)	 * 2) Update counters.
100a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)	 * 3) Increment epoch to an even number.
101a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)	 *
102a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)	 * The reader must assure 1) that the epoch is even while it reads the
103a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)	 * counters, and 2) that the epoch doesn't change between the time it
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	 * starts and finishes reading the counters.
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	 */
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	unsigned		epoch;
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	/* Profiling counters. */
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	prof_cnt_t		cnts;
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)struct prof_ctx_s {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/* Associated backtrace. */
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	prof_bt_t		*bt;
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	/* Protects cnt_merged and cnts_ql. */
117c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch	malloc_mutex_t		*lock;
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	/* Temporary storage for summation during dump. */
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	prof_cnt_t		cnt_summed;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/* When threads exit, they merge their stats into cnt_merged. */
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	prof_cnt_t		cnt_merged;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/*
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * List of profile counters, one for each thread that has allocated in
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * this context.
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 */
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	ql_head(prof_thr_cnt_t)	cnts_ql;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct prof_tdata_s {
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	/*
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * Hash of (prof_bt_t *)-->(prof_thr_cnt_t *).  Each thread keeps a
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * cache of backtraces, with associated thread-specific prof_thr_cnt_t
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)	 * objects.  Other threads may read the prof_thr_cnt_t contents, but no
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * others will ever write them.
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 *
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * Upon thread exit, the thread must merge all the prof_thr_cnt_t
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * counter data into the associated prof_ctx_t objects, and unlink/free
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 * the prof_thr_cnt_t objects.
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 */
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	ckh_t			bt2cnt;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/* LRU for contents of bt2cnt. */
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	ql_head(prof_thr_cnt_t)	lru_ql;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/* Backtrace vector, used for calls to prof_backtrace(). */
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	void			**vec;
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/* Sampling state. */
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	uint64_t		prng_state;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	uint64_t		threshold;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	uint64_t		accum;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif /* JEMALLOC_H_STRUCTS */
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/******************************************************************************/
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef JEMALLOC_H_EXTERNS
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern bool	opt_prof;
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Even if opt_prof is true, sampling can be temporarily disabled by setting
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * opt_prof_active to false.  No locking is used when updating opt_prof_active,
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * so there are no guarantees regarding how long it will take for all threads
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * to notice state changes.
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern bool	opt_prof_active;
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern size_t	opt_lg_prof_sample;   /* Mean bytes between samples. */
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern ssize_t	opt_lg_prof_interval; /* lg(prof_interval). */
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern bool	opt_prof_gdump;       /* High-water memory dumping. */
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern bool	opt_prof_final;       /* Final profile dumping. */
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern bool	opt_prof_leak;        /* Dump leak summary at exit. */
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern bool	opt_prof_accum;       /* Report cumulative bytes. */
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern char	opt_prof_prefix[PATH_MAX + 1];
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Profile dump interval, measured in bytes allocated.  Each arena triggers a
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * profile dump when it reaches this threshold.  The effect is that the
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * interval between profile dumps averages prof_interval, though the actual
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * interval between dumps will tend to be sporadic, and the interval will be a
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * maximum of approximately (prof_interval * narenas).
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern uint64_t	prof_interval;
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)/*
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * If true, promote small sampled objects to large objects, since small run
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * headers do not have embedded profile context pointers.
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern bool	prof_promote;
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void	bt_init(prof_bt_t *bt, void **vec);
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void	prof_backtrace(prof_bt_t *bt, unsigned nignore);
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)prof_thr_cnt_t	*prof_lookup(prof_bt_t *bt);
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void	prof_idump(void);
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool	prof_mdump(const char *filename);
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void	prof_gdump(void);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)prof_tdata_t	*prof_tdata_init(void);
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void	prof_tdata_cleanup(void *arg);
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void	prof_boot0(void);
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void	prof_boot1(void);
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool	prof_boot2(void);
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif /* JEMALLOC_H_EXTERNS */
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/******************************************************************************/
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef JEMALLOC_H_INLINES
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define	PROF_ALLOC_PREP(nignore, size, ret) do {			\
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	prof_tdata_t *prof_tdata;					\
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	prof_bt_t bt;							\
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)									\
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	assert(size == s2u(size));					\
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)									\
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	prof_tdata = *prof_tdata_tsd_get();				\
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (prof_tdata == NULL) {					\
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		prof_tdata = prof_tdata_init();				\
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (prof_tdata == NULL) {				\
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			ret = NULL;					\
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			break;						\
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}							\
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}								\
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)									\
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (opt_prof_active == false) {					\
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		/* Sampling is currently inactive, so avoid sampling. */\
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		ret = (prof_thr_cnt_t *)(uintptr_t)1U;			\
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	} else if (opt_lg_prof_sample == 0) {				\
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		/* Don't bother with sampling logic, since sampling   */\
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		/* interval is 1.                                     */\
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		bt_init(&bt, prof_tdata->vec);				\
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		prof_backtrace(&bt, nignore);				\
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		ret = prof_lookup(&bt);					\
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	} else {							\
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (prof_tdata->threshold == 0) {			\
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			/* Initialize.  Seed the prng differently for */\
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			/* each thread.                               */\
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			prof_tdata->prng_state =			\
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			    (uint64_t)(uintptr_t)&size;			\
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			prof_sample_threshold_update(prof_tdata);	\
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}							\
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)									\
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		/* Determine whether to capture a backtrace based on  */\
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		/* whether size is enough for prof_accum to reach     */\
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		/* prof_tdata->threshold.  However, delay updating    */\
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		/* these variables until prof_{m,re}alloc(), because  */\
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		/* we don't know for sure that the allocation will    */\
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)		/* succeed.                                           */\
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		/*                                                    */\
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		/* Use subtraction rather than addition to avoid      */\
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		/* potential integer overflow.                        */\
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (size >= prof_tdata->threshold -			\
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		    prof_tdata->accum) {				\
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			bt_init(&bt, prof_tdata->vec);			\
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			prof_backtrace(&bt, nignore);			\
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			ret = prof_lookup(&bt);				\
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		} else							\
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			ret = (prof_thr_cnt_t *)(uintptr_t)1U;		\
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}								\
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} while (0)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef JEMALLOC_ENABLE_INLINE
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)malloc_tsd_protos(JEMALLOC_ATTR(unused), prof_tdata, prof_tdata_t *)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void	prof_sample_threshold_update(prof_tdata_t *prof_tdata);
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)prof_ctx_t	*prof_ctx_get(const void *ptr);
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void	prof_ctx_set(const void *ptr, prof_ctx_t *ctx);
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool	prof_sample_accum_update(size_t size);
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void	prof_malloc(const void *ptr, size_t size, prof_thr_cnt_t *cnt);
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void	prof_realloc(const void *ptr, size_t size, prof_thr_cnt_t *cnt,
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t old_size, prof_ctx_t *old_ctx);
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void	prof_free(const void *ptr, size_t size);
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_PROF_C_))
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Thread-specific backtrace cache, used to reduce bt2ctx contention. */
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)malloc_tsd_externs(prof_tdata, prof_tdata_t *)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)malloc_tsd_funcs(JEMALLOC_INLINE, prof_tdata, prof_tdata_t *, NULL,
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    prof_tdata_cleanup)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JEMALLOC_INLINE void
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)prof_sample_threshold_update(prof_tdata_t *prof_tdata)
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	uint64_t r;
2837d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	double u;
2847d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2857d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	cassert(config_prof);
2867d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	/*
2887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	 * Compute sample threshold as a geometrically distributed random
2897d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)	 * variable with mean (2^opt_lg_prof_sample).
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 *
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 *                         __        __
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 *                         |  log(u)  |                     1
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	 * prof_tdata->threshold = | -------- |, where p = -------------------
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 *                         | log(1-p) |             opt_lg_prof_sample
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 *                                                 2
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 *
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	 * For more information on the math, see:
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 *
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 *   Non-Uniform Random Variate Generation
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 *   Luc Devroye
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 *   Springer-Verlag, New York, 1986
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 *   pp 500
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 *   (http://cg.scs.carleton.ca/~luc/rnbookindex.html)
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	 */
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	prng64(r, 53, prof_tdata->prng_state,
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    UINT64_C(6364136223846793005), UINT64_C(1442695040888963407));
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	u = (double)r * (1.0/9007199254740992.0L);
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	prof_tdata->threshold = (uint64_t)(log(u) /
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    log(1.0 - (1.0 / (double)((uint64_t)1U << opt_lg_prof_sample))))
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    + (uint64_t)1U;
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JEMALLOC_INLINE prof_ctx_t *
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)prof_ctx_get(const void *ptr)
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	prof_ctx_t *ret;
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	arena_chunk_t *chunk;
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	cassert(config_prof);
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	assert(ptr != NULL);
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (chunk != ptr) {
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		/* Region. */
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		ret = arena_prof_ctx_get(ptr);
326effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch	} else
327effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch		ret = huge_prof_ctx_get(ptr);
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return (ret);
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)JEMALLOC_INLINE void
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)prof_ctx_set(const void *ptr, prof_ctx_t *ctx)
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	arena_chunk_t *chunk;
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	cassert(config_prof);
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	assert(ptr != NULL);
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (chunk != ptr) {
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		/* Region. */
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		arena_prof_ctx_set(ptr, ctx);
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	} else
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		huge_prof_ctx_set(ptr, ctx);
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)JEMALLOC_INLINE bool
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)prof_sample_accum_update(size_t size)
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	prof_tdata_t *prof_tdata;
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	cassert(config_prof);
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	/* Sampling logic is unnecessary if the interval is 1. */
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	assert(opt_lg_prof_sample != 0);
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
357	prof_tdata = *prof_tdata_tsd_get();
358	assert(prof_tdata != NULL);
359
360	/* Take care to avoid integer overflow. */
361	if (size >= prof_tdata->threshold - prof_tdata->accum) {
362		prof_tdata->accum -= (prof_tdata->threshold - size);
363		/* Compute new sample threshold. */
364		prof_sample_threshold_update(prof_tdata);
365		while (prof_tdata->accum >= prof_tdata->threshold) {
366			prof_tdata->accum -= prof_tdata->threshold;
367			prof_sample_threshold_update(prof_tdata);
368		}
369		return (false);
370	} else {
371		prof_tdata->accum += size;
372		return (true);
373	}
374}
375
376JEMALLOC_INLINE void
377prof_malloc(const void *ptr, size_t size, prof_thr_cnt_t *cnt)
378{
379
380	cassert(config_prof);
381	assert(ptr != NULL);
382	assert(size == isalloc(ptr, true));
383
384	if (opt_lg_prof_sample != 0) {
385		if (prof_sample_accum_update(size)) {
386			/*
387			 * Don't sample.  For malloc()-like allocation, it is
388			 * always possible to tell in advance how large an
389			 * object's usable size will be, so there should never
390			 * be a difference between the size passed to
391			 * PROF_ALLOC_PREP() and prof_malloc().
392			 */
393			assert((uintptr_t)cnt == (uintptr_t)1U);
394		}
395	}
396
397	if ((uintptr_t)cnt > (uintptr_t)1U) {
398		prof_ctx_set(ptr, cnt->ctx);
399
400		cnt->epoch++;
401		/*********/
402		mb_write();
403		/*********/
404		cnt->cnts.curobjs++;
405		cnt->cnts.curbytes += size;
406		if (opt_prof_accum) {
407			cnt->cnts.accumobjs++;
408			cnt->cnts.accumbytes += size;
409		}
410		/*********/
411		mb_write();
412		/*********/
413		cnt->epoch++;
414		/*********/
415		mb_write();
416		/*********/
417	} else
418		prof_ctx_set(ptr, (prof_ctx_t *)(uintptr_t)1U);
419}
420
421JEMALLOC_INLINE void
422prof_realloc(const void *ptr, size_t size, prof_thr_cnt_t *cnt,
423    size_t old_size, prof_ctx_t *old_ctx)
424{
425	prof_thr_cnt_t *told_cnt;
426
427	cassert(config_prof);
428	assert(ptr != NULL || (uintptr_t)cnt <= (uintptr_t)1U);
429
430	if (ptr != NULL) {
431		assert(size == isalloc(ptr, true));
432		if (opt_lg_prof_sample != 0) {
433			if (prof_sample_accum_update(size)) {
434				/*
435				 * Don't sample.  The size passed to
436				 * PROF_ALLOC_PREP() was larger than what
437				 * actually got allocated, so a backtrace was
438				 * captured for this allocation, even though
439				 * its actual size was insufficient to cross
440				 * the sample threshold.
441				 */
442				cnt = (prof_thr_cnt_t *)(uintptr_t)1U;
443			}
444		}
445	}
446
447	if ((uintptr_t)old_ctx > (uintptr_t)1U) {
448		told_cnt = prof_lookup(old_ctx->bt);
449		if (told_cnt == NULL) {
450			/*
451			 * It's too late to propagate OOM for this realloc(),
452			 * so operate directly on old_cnt->ctx->cnt_merged.
453			 */
454			malloc_mutex_lock(old_ctx->lock);
455			old_ctx->cnt_merged.curobjs--;
456			old_ctx->cnt_merged.curbytes -= old_size;
457			malloc_mutex_unlock(old_ctx->lock);
458			told_cnt = (prof_thr_cnt_t *)(uintptr_t)1U;
459		}
460	} else
461		told_cnt = (prof_thr_cnt_t *)(uintptr_t)1U;
462
463	if ((uintptr_t)told_cnt > (uintptr_t)1U)
464		told_cnt->epoch++;
465	if ((uintptr_t)cnt > (uintptr_t)1U) {
466		prof_ctx_set(ptr, cnt->ctx);
467		cnt->epoch++;
468	} else
469		prof_ctx_set(ptr, (prof_ctx_t *)(uintptr_t)1U);
470	/*********/
471	mb_write();
472	/*********/
473	if ((uintptr_t)told_cnt > (uintptr_t)1U) {
474		told_cnt->cnts.curobjs--;
475		told_cnt->cnts.curbytes -= old_size;
476	}
477	if ((uintptr_t)cnt > (uintptr_t)1U) {
478		cnt->cnts.curobjs++;
479		cnt->cnts.curbytes += size;
480		if (opt_prof_accum) {
481			cnt->cnts.accumobjs++;
482			cnt->cnts.accumbytes += size;
483		}
484	}
485	/*********/
486	mb_write();
487	/*********/
488	if ((uintptr_t)told_cnt > (uintptr_t)1U)
489		told_cnt->epoch++;
490	if ((uintptr_t)cnt > (uintptr_t)1U)
491		cnt->epoch++;
492	/*********/
493	mb_write(); /* Not strictly necessary. */
494}
495
496JEMALLOC_INLINE void
497prof_free(const void *ptr, size_t size)
498{
499	prof_ctx_t *ctx = prof_ctx_get(ptr);
500
501	cassert(config_prof);
502
503	if ((uintptr_t)ctx > (uintptr_t)1) {
504		assert(size == isalloc(ptr, true));
505		prof_thr_cnt_t *tcnt = prof_lookup(ctx->bt);
506
507		if (tcnt != NULL) {
508			tcnt->epoch++;
509			/*********/
510			mb_write();
511			/*********/
512			tcnt->cnts.curobjs--;
513			tcnt->cnts.curbytes -= size;
514			/*********/
515			mb_write();
516			/*********/
517			tcnt->epoch++;
518			/*********/
519			mb_write();
520			/*********/
521		} else {
522			/*
523			 * OOM during free() cannot be propagated, so operate
524			 * directly on cnt->ctx->cnt_merged.
525			 */
526			malloc_mutex_lock(ctx->lock);
527			ctx->cnt_merged.curobjs--;
528			ctx->cnt_merged.curbytes -= size;
529			malloc_mutex_unlock(ctx->lock);
530		}
531	}
532}
533#endif
534
535#endif /* JEMALLOC_H_INLINES */
536/******************************************************************************/
537