Home | History | Annotate | Download | only in internal
      1 #ifndef JEMALLOC_INTERNAL_ARENA_STATS_H
      2 #define JEMALLOC_INTERNAL_ARENA_STATS_H
      3 
      4 #include "jemalloc/internal/atomic.h"
      5 #include "jemalloc/internal/mutex.h"
      6 #include "jemalloc/internal/mutex_prof.h"
      7 #include "jemalloc/internal/size_classes.h"
      8 
      9 /*
     10  * In those architectures that support 64-bit atomics, we use atomic updates for
     11  * our 64-bit values.  Otherwise, we use a plain uint64_t and synchronize
     12  * externally.
     13  */
     14 #ifdef JEMALLOC_ATOMIC_U64
     15 typedef atomic_u64_t arena_stats_u64_t;
     16 #else
     17 /* Must hold the arena stats mutex while reading atomically. */
     18 typedef uint64_t arena_stats_u64_t;
     19 #endif
     20 
     21 typedef struct arena_stats_large_s arena_stats_large_t;
     22 struct arena_stats_large_s {
     23 	/*
     24 	 * Total number of allocation/deallocation requests served directly by
     25 	 * the arena.
     26 	 */
     27 	arena_stats_u64_t	nmalloc;
     28 	arena_stats_u64_t	ndalloc;
     29 
     30 	/*
     31 	 * Number of allocation requests that correspond to this size class.
     32 	 * This includes requests served by tcache, though tcache only
     33 	 * periodically merges into this counter.
     34 	 */
     35 	arena_stats_u64_t	nrequests; /* Partially derived. */
     36 
     37 	/* Current number of allocations of this size class. */
     38 	size_t		curlextents; /* Derived. */
     39 };
     40 
     41 typedef struct arena_stats_decay_s arena_stats_decay_t;
     42 struct arena_stats_decay_s {
     43 	/* Total number of purge sweeps. */
     44 	arena_stats_u64_t	npurge;
     45 	/* Total number of madvise calls made. */
     46 	arena_stats_u64_t	nmadvise;
     47 	/* Total number of pages purged. */
     48 	arena_stats_u64_t	purged;
     49 };
     50 
     51 /*
     52  * Arena stats.  Note that fields marked "derived" are not directly maintained
     53  * within the arena code; rather their values are derived during stats merge
     54  * requests.
     55  */
     56 typedef struct arena_stats_s arena_stats_t;
     57 struct arena_stats_s {
     58 #ifndef JEMALLOC_ATOMIC_U64
     59 	malloc_mutex_t		mtx;
     60 #endif
     61 
     62 	/* Number of bytes currently mapped, excluding retained memory. */
     63 	atomic_zu_t		mapped; /* Partially derived. */
     64 
     65 	/*
     66 	 * Number of unused virtual memory bytes currently retained.  Retained
     67 	 * bytes are technically mapped (though always decommitted or purged),
     68 	 * but they are excluded from the mapped statistic (above).
     69 	 */
     70 	atomic_zu_t		retained; /* Derived. */
     71 
     72 	arena_stats_decay_t	decay_dirty;
     73 	arena_stats_decay_t	decay_muzzy;
     74 
     75 	atomic_zu_t		base; /* Derived. */
     76 	atomic_zu_t		internal;
     77 	atomic_zu_t		resident; /* Derived. */
     78 	atomic_zu_t		metadata_thp;
     79 
     80 	atomic_zu_t		allocated_large; /* Derived. */
     81 	arena_stats_u64_t	nmalloc_large; /* Derived. */
     82 	arena_stats_u64_t	ndalloc_large; /* Derived. */
     83 	arena_stats_u64_t	nrequests_large; /* Derived. */
     84 
     85 	/* Number of bytes cached in tcache associated with this arena. */
     86 	atomic_zu_t		tcache_bytes; /* Derived. */
     87 
     88 	mutex_prof_data_t mutex_prof_data[mutex_prof_num_arena_mutexes];
     89 
     90 	/* One element for each large size class. */
     91 	arena_stats_large_t	lstats[NSIZES - NBINS];
     92 
     93 	/* Arena uptime. */
     94 	nstime_t		uptime;
     95 };
     96 
     97 static inline bool
     98 arena_stats_init(UNUSED tsdn_t *tsdn, arena_stats_t *arena_stats) {
     99 	if (config_debug) {
    100 		for (size_t i = 0; i < sizeof(arena_stats_t); i++) {
    101 			assert(((char *)arena_stats)[i] == 0);
    102 		}
    103 	}
    104 #ifndef JEMALLOC_ATOMIC_U64
    105 	if (malloc_mutex_init(&arena_stats->mtx, "arena_stats",
    106 	    WITNESS_RANK_ARENA_STATS, malloc_mutex_rank_exclusive)) {
    107 		return true;
    108 	}
    109 #endif
    110 	/* Memory is zeroed, so there is no need to clear stats. */
    111 	return false;
    112 }
    113 
    114 static inline void
    115 arena_stats_lock(tsdn_t *tsdn, arena_stats_t *arena_stats) {
    116 #ifndef JEMALLOC_ATOMIC_U64
    117 	malloc_mutex_lock(tsdn, &arena_stats->mtx);
    118 #endif
    119 }
    120 
    121 static inline void
    122 arena_stats_unlock(tsdn_t *tsdn, arena_stats_t *arena_stats) {
    123 #ifndef JEMALLOC_ATOMIC_U64
    124 	malloc_mutex_unlock(tsdn, &arena_stats->mtx);
    125 #endif
    126 }
    127 
    128 static inline uint64_t
    129 arena_stats_read_u64(tsdn_t *tsdn, arena_stats_t *arena_stats,
    130     arena_stats_u64_t *p) {
    131 #ifdef JEMALLOC_ATOMIC_U64
    132 	return atomic_load_u64(p, ATOMIC_RELAXED);
    133 #else
    134 	malloc_mutex_assert_owner(tsdn, &arena_stats->mtx);
    135 	return *p;
    136 #endif
    137 }
    138 
    139 static inline void
    140 arena_stats_add_u64(tsdn_t *tsdn, arena_stats_t *arena_stats,
    141     arena_stats_u64_t *p, uint64_t x) {
    142 #ifdef JEMALLOC_ATOMIC_U64
    143 	atomic_fetch_add_u64(p, x, ATOMIC_RELAXED);
    144 #else
    145 	malloc_mutex_assert_owner(tsdn, &arena_stats->mtx);
    146 	*p += x;
    147 #endif
    148 }
    149 
    150 UNUSED static inline void
    151 arena_stats_sub_u64(tsdn_t *tsdn, arena_stats_t *arena_stats,
    152     arena_stats_u64_t *p, uint64_t x) {
    153 #ifdef JEMALLOC_ATOMIC_U64
    154 	UNUSED uint64_t r = atomic_fetch_sub_u64(p, x, ATOMIC_RELAXED);
    155 	assert(r - x <= r);
    156 #else
    157 	malloc_mutex_assert_owner(tsdn, &arena_stats->mtx);
    158 	*p -= x;
    159 	assert(*p + x >= *p);
    160 #endif
    161 }
    162 
    163 /*
    164  * Non-atomically sets *dst += src.  *dst needs external synchronization.
    165  * This lets us avoid the cost of a fetch_add when its unnecessary (note that
    166  * the types here are atomic).
    167  */
    168 static inline void
    169 arena_stats_accum_u64(arena_stats_u64_t *dst, uint64_t src) {
    170 #ifdef JEMALLOC_ATOMIC_U64
    171 	uint64_t cur_dst = atomic_load_u64(dst, ATOMIC_RELAXED);
    172 	atomic_store_u64(dst, src + cur_dst, ATOMIC_RELAXED);
    173 #else
    174 	*dst += src;
    175 #endif
    176 }
    177 
    178 static inline size_t
    179 arena_stats_read_zu(tsdn_t *tsdn, arena_stats_t *arena_stats, atomic_zu_t *p) {
    180 #ifdef JEMALLOC_ATOMIC_U64
    181 	return atomic_load_zu(p, ATOMIC_RELAXED);
    182 #else
    183 	malloc_mutex_assert_owner(tsdn, &arena_stats->mtx);
    184 	return atomic_load_zu(p, ATOMIC_RELAXED);
    185 #endif
    186 }
    187 
    188 static inline void
    189 arena_stats_add_zu(tsdn_t *tsdn, arena_stats_t *arena_stats, atomic_zu_t *p,
    190     size_t x) {
    191 #ifdef JEMALLOC_ATOMIC_U64
    192 	atomic_fetch_add_zu(p, x, ATOMIC_RELAXED);
    193 #else
    194 	malloc_mutex_assert_owner(tsdn, &arena_stats->mtx);
    195 	size_t cur = atomic_load_zu(p, ATOMIC_RELAXED);
    196 	atomic_store_zu(p, cur + x, ATOMIC_RELAXED);
    197 #endif
    198 }
    199 
    200 static inline void
    201 arena_stats_sub_zu(tsdn_t *tsdn, arena_stats_t *arena_stats, atomic_zu_t *p,
    202     size_t x) {
    203 #ifdef JEMALLOC_ATOMIC_U64
    204 	UNUSED size_t r = atomic_fetch_sub_zu(p, x, ATOMIC_RELAXED);
    205 	assert(r - x <= r);
    206 #else
    207 	malloc_mutex_assert_owner(tsdn, &arena_stats->mtx);
    208 	size_t cur = atomic_load_zu(p, ATOMIC_RELAXED);
    209 	atomic_store_zu(p, cur - x, ATOMIC_RELAXED);
    210 #endif
    211 }
    212 
    213 /* Like the _u64 variant, needs an externally synchronized *dst. */
    214 static inline void
    215 arena_stats_accum_zu(atomic_zu_t *dst, size_t src) {
    216 	size_t cur_dst = atomic_load_zu(dst, ATOMIC_RELAXED);
    217 	atomic_store_zu(dst, src + cur_dst, ATOMIC_RELAXED);
    218 }
    219 
    220 static inline void
    221 arena_stats_large_nrequests_add(tsdn_t *tsdn, arena_stats_t *arena_stats,
    222     szind_t szind, uint64_t nrequests) {
    223 	arena_stats_lock(tsdn, arena_stats);
    224 	arena_stats_add_u64(tsdn, arena_stats, &arena_stats->lstats[szind -
    225 	    NBINS].nrequests, nrequests);
    226 	arena_stats_unlock(tsdn, arena_stats);
    227 }
    228 
    229 static inline void
    230 arena_stats_mapped_add(tsdn_t *tsdn, arena_stats_t *arena_stats, size_t size) {
    231 	arena_stats_lock(tsdn, arena_stats);
    232 	arena_stats_add_zu(tsdn, arena_stats, &arena_stats->mapped, size);
    233 	arena_stats_unlock(tsdn, arena_stats);
    234 }
    235 
    236 
    237 #endif /* JEMALLOC_INTERNAL_ARENA_STATS_H */
    238