@@ -14,6 +14,48 @@ psset_init(psset_t *psset) {
1414 edata_heap_new (& psset -> pageslabs [i ]);
1515 }
1616 bitmap_init (psset -> bitmap , & psset_bitmap_info , /* fill */ true);
17+ psset -> full_slab_stats .npageslabs = 0 ;
18+ psset -> full_slab_stats .nactive = 0 ;
19+ psset -> full_slab_stats .ninactive = 0 ;
20+ for (unsigned i = 0 ; i < PSSET_NPSIZES ; i ++ ) {
21+ psset -> slab_stats [i ].npageslabs = 0 ;
22+ psset -> slab_stats [i ].nactive = 0 ;
23+ psset -> slab_stats [i ].ninactive = 0 ;
24+ }
25+ }
26+
27+ /*
28+ * The stats maintenance strategy is simple, but not necessarily obvious.
29+ * edata_nfree and the bitmap must remain consistent at all times. If they
30+ * change while an edata is within an edata_heap (or full), then the associated
31+ * stats bin (or the full bin) must also change. If they change while not in a
32+ * bin (say, in between extraction and reinsertion), then the bin stats need not
33+ * change. If a pageslab is removed from a bin (or becomes nonfull), it should
34+ * no longer contribute to that bin's stats (or the full stats). These help
35+ * ensure we don't miss any heap modification operations.
36+ */
37+ JEMALLOC_ALWAYS_INLINE void
38+ psset_bin_stats_adjust (psset_bin_stats_t * binstats , edata_t * ps , bool inc ) {
39+ size_t mul = inc ? (size_t )1 : (size_t )-1 ;
40+
41+ size_t npages = edata_size_get (ps ) >> LG_PAGE ;
42+ size_t ninactive = edata_nfree_get (ps );
43+ size_t nactive = npages - ninactive ;
44+ binstats -> npageslabs += mul * 1 ;
45+ binstats -> nactive += mul * nactive ;
46+ binstats -> ninactive += mul * ninactive ;
47+ }
48+
49+ static void
50+ psset_edata_heap_remove (psset_t * psset , pszind_t pind , edata_t * ps ) {
51+ edata_heap_remove (& psset -> pageslabs [pind ], ps );
52+ psset_bin_stats_adjust (& psset -> slab_stats [pind ], ps , /* inc */ false);
53+ }
54+
55+ static void
56+ psset_edata_heap_insert (psset_t * psset , pszind_t pind , edata_t * ps ) {
57+ edata_heap_insert (& psset -> pageslabs [pind ], ps );
58+ psset_bin_stats_adjust (& psset -> slab_stats [pind ], ps , /* inc */ true);
1759}
1860
1961JEMALLOC_ALWAYS_INLINE void
@@ -46,7 +88,8 @@ psset_recycle_extract(psset_t *psset, size_t size) {
4688 if (ret == NULL ) {
4789 return NULL ;
4890 }
49- edata_heap_remove (& psset -> pageslabs [ret_ind ], ret );
91+
92+ psset_edata_heap_remove (psset , ret_ind , ret );
5093 if (edata_heap_empty (& psset -> pageslabs [ret_ind ])) {
5194 bitmap_set (psset -> bitmap , & psset_bitmap_info , ret_ind );
5295 }
@@ -67,7 +110,7 @@ psset_insert(psset_t *psset, edata_t *ps, size_t largest_range) {
67110 if (edata_heap_empty (& psset -> pageslabs [pind ])) {
68111 bitmap_unset (psset -> bitmap , & psset_bitmap_info , (size_t )pind );
69112 }
70- edata_heap_insert ( & psset -> pageslabs [ pind ] , ps );
113+ psset_edata_heap_insert ( psset , pind , ps );
71114}
72115
73116/*
@@ -120,6 +163,9 @@ psset_ps_alloc_insert(psset_t *psset, edata_t *ps, edata_t *r_edata,
120163 EXTENT_NOT_HEAD );
121164 edata_ps_set (r_edata , ps );
122165 fb_set_range (ps_fb , ps_npages , begin , npages );
166+ edata_nfree_set (ps , (uint32_t )(edata_nfree_get (ps ) - npages ));
167+ /* The pageslab isn't in a bin, so no bin stats need to change. */
168+
123169 /*
124170 * OK, we've got to put the pageslab back. First we have to figure out
125171 * where, though; we've only checked run sizes before the pageslab we
@@ -144,7 +190,10 @@ psset_ps_alloc_insert(psset_t *psset, edata_t *ps, edata_t *r_edata,
144190 start = begin + len ;
145191 }
146192 edata_longest_free_range_set (ps , (uint32_t )largest_unchosen_range );
147- if (largest_unchosen_range != 0 ) {
193+ if (largest_unchosen_range == 0 ) {
194+ psset_bin_stats_adjust (& psset -> full_slab_stats , ps ,
195+ /* inc */ true);
196+ } else {
148197 psset_insert (psset , ps , largest_unchosen_range );
149198 }
150199}
@@ -164,8 +213,8 @@ psset_alloc_new(psset_t *psset, edata_t *ps, edata_t *r_edata, size_t size) {
164213 fb_group_t * ps_fb = edata_slab_data_get (ps )-> bitmap ;
165214 size_t ps_npages = edata_size_get (ps ) >> LG_PAGE ;
166215 assert (fb_empty (ps_fb , ps_npages ));
167-
168216 assert (ps_npages >= (size >> LG_PAGE ));
217+ edata_nfree_set (ps , (uint32_t )ps_npages );
169218 psset_ps_alloc_insert (psset , ps , r_edata , size );
170219}
171220
@@ -177,13 +226,35 @@ psset_dalloc(psset_t *psset, edata_t *edata) {
177226 edata_t * ps = edata_ps_get (edata );
178227 fb_group_t * ps_fb = edata_slab_data_get (ps )-> bitmap ;
179228 size_t ps_old_longest_free_range = edata_longest_free_range_get (ps );
229+ pszind_t old_pind = SC_NPSIZES ;
230+ if (ps_old_longest_free_range != 0 ) {
231+ old_pind = sz_psz2ind (sz_psz_quantize_floor (
232+ ps_old_longest_free_range << LG_PAGE ));
233+ }
180234
181235 size_t ps_npages = edata_size_get (ps ) >> LG_PAGE ;
182236 size_t begin =
183237 ((uintptr_t )edata_base_get (edata ) - (uintptr_t )edata_base_get (ps ))
184238 >> LG_PAGE ;
185239 size_t len = edata_size_get (edata ) >> LG_PAGE ;
186240 fb_unset_range (ps_fb , ps_npages , begin , len );
241+ if (ps_old_longest_free_range == 0 ) {
242+ /* We were in the (imaginary) full bin; update stats for it. */
243+ psset_bin_stats_adjust (& psset -> full_slab_stats , ps ,
244+ /* inc */ false);
245+ } else {
246+ /*
247+ * The edata is still in the bin, need to update its
248+ * contribution.
249+ */
250+ psset -> slab_stats [old_pind ].nactive -= len ;
251+ psset -> slab_stats [old_pind ].ninactive += len ;
252+ }
253+ /*
254+ * Note that we want to do this after the stats updates, since if it was
255+ * full it psset_bin_stats_adjust would have looked at the old version.
256+ */
257+ edata_nfree_set (ps , (uint32_t )(edata_nfree_get (ps ) + len ));
187258
188259 /* We might have just created a new, larger range. */
189260 size_t new_begin = (size_t )(fb_fls (ps_fb , ps_npages , begin ) + 1 );
@@ -215,9 +286,7 @@ psset_dalloc(psset_t *psset, edata_t *edata) {
215286 * and the issue becomes moot).
216287 */
217288 if (ps_old_longest_free_range > 0 ) {
218- pszind_t old_pind = sz_psz2ind (sz_psz_quantize_floor (
219- ps_old_longest_free_range << LG_PAGE ));
220- edata_heap_remove (& psset -> pageslabs [old_pind ], ps );
289+ psset_edata_heap_remove (psset , old_pind , ps );
221290 if (edata_heap_empty (& psset -> pageslabs [old_pind ])) {
222291 bitmap_set (psset -> bitmap , & psset_bitmap_info ,
223292 (size_t )old_pind );
@@ -234,6 +303,6 @@ psset_dalloc(psset_t *psset, edata_t *edata) {
234303 bitmap_unset (psset -> bitmap , & psset_bitmap_info ,
235304 (size_t )new_pind );
236305 }
237- edata_heap_insert ( & psset -> pageslabs [ new_pind ] , ps );
306+ psset_edata_heap_insert ( psset , new_pind , ps );
238307 return NULL ;
239308}
0 commit comments