mirror of
https://github.com/jemalloc/jemalloc.git
synced 2026-07-24 13:53:11 +00:00
Use a for-loop to fulfill flush requests that are larger than CACHE_BIN_NFLUSH_BATCH_MAX items
This commit is contained in:
@@ -600,6 +600,14 @@ cache_bin_nitems_get_remote(cache_bin_t *bin, cache_bin_sz_t *ncached,
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Limit how many items can be flushed in a batch (Which is the upper bound
|
||||||
|
* for the nflush parameter in tcache_bin_flush_impl()).
|
||||||
|
* This is to avoid stack overflow when we do batch edata look up, which
|
||||||
|
* reserves a nflush * sizeof(emap_batch_lookup_result_t) stack variable.
|
||||||
|
*/
|
||||||
|
#define CACHE_BIN_NFLUSH_BATCH_MAX (VARIABLE_ARRAY_SIZE_MAX >> LG_SIZEOF_PTR)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Filling and flushing are done in batch, on arrays of void *s. For filling,
|
* Filling and flushing are done in batch, on arrays of void *s. For filling,
|
||||||
* the arrays go forward, and can be accessed with ordinary array arithmetic.
|
* the arrays go forward, and can be accessed with ordinary array arithmetic.
|
||||||
|
|||||||
47
src/tcache.c
47
src/tcache.c
@@ -712,22 +712,37 @@ tcache_bin_flush_impl_large(tsd_t *tsd, tcache_t *tcache, cache_bin_t *cache_bin
|
|||||||
JEMALLOC_ALWAYS_INLINE void
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
tcache_bin_flush_impl(tsd_t *tsd, tcache_t *tcache, cache_bin_t *cache_bin,
|
tcache_bin_flush_impl(tsd_t *tsd, tcache_t *tcache, cache_bin_t *cache_bin,
|
||||||
szind_t binind, cache_bin_ptr_array_t *ptrs, unsigned nflush, bool small) {
|
szind_t binind, cache_bin_ptr_array_t *ptrs, unsigned nflush, bool small) {
|
||||||
/*
|
assert(ptrs != NULL && ptrs->ptr != NULL);
|
||||||
* The small/large flush logic is very similar; you might conclude that
|
unsigned nflush_batch, nflushed = 0;
|
||||||
* it's a good opportunity to share code. We've tried this, and by and
|
cache_bin_ptr_array_t ptrs_batch;
|
||||||
* large found this to obscure more than it helps; there are so many
|
do {
|
||||||
* fiddly bits around things like stats handling, precisely when and
|
nflush_batch = nflush - nflushed;
|
||||||
* which mutexes are acquired, etc., that almost all code ends up being
|
if (nflush_batch > CACHE_BIN_NFLUSH_BATCH_MAX) {
|
||||||
* gated behind 'if (small) { ... } else { ... }'. Even though the
|
nflush_batch = CACHE_BIN_NFLUSH_BATCH_MAX;
|
||||||
* '...' is morally equivalent, the code itself needs slight tweaks.
|
}
|
||||||
*/
|
assert(nflush_batch <= CACHE_BIN_NFLUSH_BATCH_MAX);
|
||||||
if (small) {
|
(&ptrs_batch)->n = (cache_bin_sz_t)nflush_batch;
|
||||||
tcache_bin_flush_impl_small(tsd, tcache, cache_bin, binind,
|
(&ptrs_batch)->ptr = ptrs->ptr + nflushed;
|
||||||
ptrs, nflush);
|
/*
|
||||||
} else {
|
* The small/large flush logic is very similar; you might conclude that
|
||||||
tcache_bin_flush_impl_large(tsd, tcache, cache_bin, binind,
|
* it's a good opportunity to share code. We've tried this, and by and
|
||||||
ptrs, nflush);
|
* large found this to obscure more than it helps; there are so many
|
||||||
}
|
* fiddly bits around things like stats handling, precisely when and
|
||||||
|
* which mutexes are acquired, etc., that almost all code ends up being
|
||||||
|
* gated behind 'if (small) { ... } else { ... }'. Even though the
|
||||||
|
* '...' is morally equivalent, the code itself needs slight tweaks.
|
||||||
|
*/
|
||||||
|
if (small) {
|
||||||
|
tcache_bin_flush_impl_small(tsd, tcache, cache_bin, binind,
|
||||||
|
&ptrs_batch, nflush_batch);
|
||||||
|
} else {
|
||||||
|
tcache_bin_flush_impl_large(tsd, tcache, cache_bin, binind,
|
||||||
|
&ptrs_batch, nflush_batch);
|
||||||
|
}
|
||||||
|
nflushed += nflush_batch;
|
||||||
|
} while (nflushed < nflush);
|
||||||
|
assert(nflush == nflushed);
|
||||||
|
assert((ptrs->ptr + nflush) == ((&ptrs_batch)->ptr + nflush_batch));
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
|
|||||||
Reference in New Issue
Block a user