summaryrefslogtreecommitdiffstats
path: root/deps/jemalloc/include/jemalloc/internal/psset.h
blob: e1d64970ee1402d2920eeeb475e48726b84af08a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#ifndef JEMALLOC_INTERNAL_PSSET_H
#define JEMALLOC_INTERNAL_PSSET_H

#include "jemalloc/internal/hpdata.h"

/*
 * A page-slab set.  What the eset is to PAC, the psset is to HPA.  It maintains
 * a collection of page-slabs (the intent being that they are backed by
 * hugepages, or at least could be), and handles allocation and deallocation
 * requests.
 */

/*
 * One more than the maximum pszind_t we will serve out of the HPA.
 * Practically, we expect only the first few to be actually used.  This
 * corresponds to a maximum size of of 512MB on systems with 4k pages and
 * SC_NGROUP == 4, which is already an unreasonably large maximum.  Morally, you
 * can think of this as being SC_NPSIZES, but there's no sense in wasting that
 * much space in the arena, making bitmaps that much larger, etc.
 */
#define PSSET_NPSIZES 64

/*
 * We keep two purge lists per page size class; one for hugified hpdatas (at
 * index 2*pszind), and one for the non-hugified hpdatas (at index 2*pszind +
 * 1).  This lets us implement a preference for purging non-hugified hpdatas
 * among similarly-dirty ones.
 * We reserve the last two indices for empty slabs, in that case purging
 * hugified ones (which are definitionally all waste) before non-hugified ones
 * (i.e. reversing the order).
 */
#define PSSET_NPURGE_LISTS (2 * PSSET_NPSIZES)

typedef struct psset_bin_stats_s psset_bin_stats_t;
struct psset_bin_stats_s {
	/* How many pageslabs are in this bin? */
	size_t npageslabs;
	/* Of them, how many pages are active? */
	size_t nactive;
	/* And how many are dirty? */
	size_t ndirty;
};

typedef struct psset_stats_s psset_stats_t;
struct psset_stats_s {
	/*
	 * The second index is huge stats; nonfull_slabs[pszind][0] contains
	 * stats for the non-huge slabs in bucket pszind, while
	 * nonfull_slabs[pszind][1] contains stats for the huge slabs.
	 */
	psset_bin_stats_t nonfull_slabs[PSSET_NPSIZES][2];

	/*
	 * Full slabs don't live in any edata heap, but we still track their
	 * stats.
	 */
	psset_bin_stats_t full_slabs[2];

	/* Empty slabs are similar. */
	psset_bin_stats_t empty_slabs[2];
};

typedef struct psset_s psset_t;
struct psset_s {
	/*
	 * The pageslabs, quantized by the size class of the largest contiguous
	 * free run of pages in a pageslab.
	 */
	hpdata_age_heap_t pageslabs[PSSET_NPSIZES];
	/* Bitmap for which set bits correspond to non-empty heaps. */
	fb_group_t pageslab_bitmap[FB_NGROUPS(PSSET_NPSIZES)];
	/*
	 * The sum of all bin stats in stats.  This lets us quickly answer
	 * queries for the number of dirty, active, and retained pages in the
	 * entire set.
	 */
	psset_bin_stats_t merged_stats;
	psset_stats_t stats;
	/*
	 * Slabs with no active allocations, but which are allowed to serve new
	 * allocations.
	 */
	hpdata_empty_list_t empty;
	/*
	 * Slabs which are available to be purged, ordered by how much we want
	 * to purge them (with later indices indicating slabs we want to purge
	 * more).
	 */
	hpdata_purge_list_t to_purge[PSSET_NPURGE_LISTS];
	/* Bitmap for which set bits correspond to non-empty purge lists. */
	fb_group_t purge_bitmap[FB_NGROUPS(PSSET_NPURGE_LISTS)];
	/* Slabs which are available to be hugified. */
	hpdata_hugify_list_t to_hugify;
};

void psset_init(psset_t *psset);
void psset_stats_accum(psset_stats_t *dst, psset_stats_t *src);

/*
 * Begin or end updating the given pageslab's metadata.  While the pageslab is
 * being updated, it won't be returned from psset_fit calls.
 */
void psset_update_begin(psset_t *psset, hpdata_t *ps);
void psset_update_end(psset_t *psset, hpdata_t *ps);

/* Analogous to the eset_fit; pick a hpdata to serve the request. */
hpdata_t *psset_pick_alloc(psset_t *psset, size_t size);
/* Pick one to purge. */
hpdata_t *psset_pick_purge(psset_t *psset);
/* Pick one to hugify. */
hpdata_t *psset_pick_hugify(psset_t *psset);

void psset_insert(psset_t *psset, hpdata_t *ps);
void psset_remove(psset_t *psset, hpdata_t *ps);

static inline size_t
psset_npageslabs(psset_t *psset) {
	return psset->merged_stats.npageslabs;
}

static inline size_t
psset_nactive(psset_t *psset) {
	return psset->merged_stats.nactive;
}

static inline size_t
psset_ndirty(psset_t *psset) {
	return psset->merged_stats.ndirty;
}

#endif /* JEMALLOC_INTERNAL_PSSET_H */