mirror of
https://github.com/jemalloc/jemalloc.git
synced 2026-07-25 06:13:13 +00:00
To improve reuse efficiency, the maximum coalesced size for large extents
in the dirty ecache has been limited. This patch was tested with real workloads using ClickHouse (Clickbench Q35) on a system with 2x240 vCPUs. The results showed a 2X in query per second (QPS) performance and a reduction in page faults to 29% of the previous rate. Additionally, microbenchmark testing involved 256 memory reallocations resizing from 4KB to 16KB in one arena, which demonstrated a 5X performance improvement. Signed-off-by: Jiebin Sun <jiebin.sun@intel.com>
This commit is contained in:
40
src/extent.c
40
src/extent.c
@@ -888,7 +888,7 @@ extent_coalesce(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks, ecache_t *ecache,
|
|||||||
|
|
||||||
static edata_t *
|
static edata_t *
|
||||||
extent_try_coalesce_impl(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
|
extent_try_coalesce_impl(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
|
||||||
ecache_t *ecache, edata_t *edata, bool *coalesced) {
|
ecache_t *ecache, edata_t *edata, size_t max_size, bool *coalesced) {
|
||||||
assert(!edata_guarded_get(edata));
|
assert(!edata_guarded_get(edata));
|
||||||
assert(coalesced != NULL);
|
assert(coalesced != NULL);
|
||||||
*coalesced = false;
|
*coalesced = false;
|
||||||
@@ -908,7 +908,8 @@ extent_try_coalesce_impl(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
|
|||||||
/* Try to coalesce forward. */
|
/* Try to coalesce forward. */
|
||||||
edata_t *next = emap_try_acquire_edata_neighbor(tsdn, pac->emap,
|
edata_t *next = emap_try_acquire_edata_neighbor(tsdn, pac->emap,
|
||||||
edata, EXTENT_PAI_PAC, ecache->state, /* forward */ true);
|
edata, EXTENT_PAI_PAC, ecache->state, /* forward */ true);
|
||||||
if (next != NULL) {
|
size_t max_next_neighbor = max_size > edata_size_get(edata) ? max_size - edata_size_get(edata) : 0;
|
||||||
|
if (next != NULL && edata_size_get(next) <= max_next_neighbor) {
|
||||||
if (!extent_coalesce(tsdn, pac, ehooks, ecache, edata,
|
if (!extent_coalesce(tsdn, pac, ehooks, ecache, edata,
|
||||||
next, true)) {
|
next, true)) {
|
||||||
if (ecache->delay_coalesce) {
|
if (ecache->delay_coalesce) {
|
||||||
@@ -923,7 +924,8 @@ extent_try_coalesce_impl(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
|
|||||||
/* Try to coalesce backward. */
|
/* Try to coalesce backward. */
|
||||||
edata_t *prev = emap_try_acquire_edata_neighbor(tsdn, pac->emap,
|
edata_t *prev = emap_try_acquire_edata_neighbor(tsdn, pac->emap,
|
||||||
edata, EXTENT_PAI_PAC, ecache->state, /* forward */ false);
|
edata, EXTENT_PAI_PAC, ecache->state, /* forward */ false);
|
||||||
if (prev != NULL) {
|
size_t max_prev_neighbor = max_size > edata_size_get(edata) ? max_size - edata_size_get(edata) : 0;
|
||||||
|
if (prev != NULL && edata_size_get(prev) <= max_prev_neighbor) {
|
||||||
if (!extent_coalesce(tsdn, pac, ehooks, ecache, edata,
|
if (!extent_coalesce(tsdn, pac, ehooks, ecache, edata,
|
||||||
prev, false)) {
|
prev, false)) {
|
||||||
edata = prev;
|
edata = prev;
|
||||||
@@ -947,14 +949,14 @@ static edata_t *
|
|||||||
extent_try_coalesce(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
|
extent_try_coalesce(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
|
||||||
ecache_t *ecache, edata_t *edata, bool *coalesced) {
|
ecache_t *ecache, edata_t *edata, bool *coalesced) {
|
||||||
return extent_try_coalesce_impl(tsdn, pac, ehooks, ecache, edata,
|
return extent_try_coalesce_impl(tsdn, pac, ehooks, ecache, edata,
|
||||||
coalesced);
|
SC_LARGE_MAXCLASS, coalesced);
|
||||||
}
|
}
|
||||||
|
|
||||||
static edata_t *
|
static edata_t *
|
||||||
extent_try_coalesce_large(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
|
extent_try_coalesce_large(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
|
||||||
ecache_t *ecache, edata_t *edata, bool *coalesced) {
|
ecache_t *ecache, edata_t *edata, size_t max_size, bool *coalesced) {
|
||||||
return extent_try_coalesce_impl(tsdn, pac, ehooks, ecache, edata,
|
return extent_try_coalesce_impl(tsdn, pac, ehooks, ecache, edata,
|
||||||
coalesced);
|
max_size, coalesced);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Purge a single extent to retained / unmapped directly. */
|
/* Purge a single extent to retained / unmapped directly. */
|
||||||
@@ -1004,11 +1006,35 @@ extent_record(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks, ecache_t *ecache,
|
|||||||
} else if (edata_size_get(edata) >= SC_LARGE_MINCLASS) {
|
} else if (edata_size_get(edata) >= SC_LARGE_MINCLASS) {
|
||||||
assert(ecache == &pac->ecache_dirty);
|
assert(ecache == &pac->ecache_dirty);
|
||||||
/* Always coalesce large extents eagerly. */
|
/* Always coalesce large extents eagerly. */
|
||||||
|
/**
|
||||||
|
* Maximum size limit (max_size) for large extents waiting to be coalesced
|
||||||
|
* in dirty ecache.
|
||||||
|
*
|
||||||
|
* When set to a non-zero value, this parameter restricts the maximum size
|
||||||
|
* of large extents after coalescing. If the combined size of two extents
|
||||||
|
* would exceed this threshold, the coalescing operation is skipped.
|
||||||
|
*
|
||||||
|
* This improves dirty ecache reuse efficiency by:
|
||||||
|
* - Maintaining appropriately sized extents that match common allocation requests
|
||||||
|
* - Limiting large extent coalescence to prevent overly large extents that are
|
||||||
|
* less likely to be reused efficiently
|
||||||
|
* - Setting lg_max_coalesce for large extent merging scenarios, similar to how
|
||||||
|
* lg_max_fit is used during extent reuse
|
||||||
|
*
|
||||||
|
* Note that during extent decay/purge operations, no coalescing restrictions
|
||||||
|
* are applied to dirty ecache despite the delay_coalesce setting. This ensures
|
||||||
|
* that while improving dirty ecache reuse efficiency, we don't compromise
|
||||||
|
* the final coalescing that happens during the transition from dirty ecache
|
||||||
|
* to muzzy/retained ecache states.
|
||||||
|
*/
|
||||||
|
unsigned lg_max_coalesce = (unsigned)opt_lg_extent_max_active_fit;
|
||||||
|
size_t edata_size = edata_size_get(edata);
|
||||||
|
size_t max_size = (SC_LARGE_MAXCLASS >> lg_max_coalesce) > edata_size ? (edata_size << lg_max_coalesce) : SC_LARGE_MAXCLASS;
|
||||||
bool coalesced;
|
bool coalesced;
|
||||||
do {
|
do {
|
||||||
assert(edata_state_get(edata) == extent_state_active);
|
assert(edata_state_get(edata) == extent_state_active);
|
||||||
edata = extent_try_coalesce_large(tsdn, pac, ehooks,
|
edata = extent_try_coalesce_large(tsdn, pac, ehooks,
|
||||||
ecache, edata, &coalesced);
|
ecache, edata, max_size, &coalesced);
|
||||||
} while (coalesced);
|
} while (coalesced);
|
||||||
if (edata_size_get(edata) >=
|
if (edata_size_get(edata) >=
|
||||||
atomic_load_zu(&pac->oversize_threshold, ATOMIC_RELAXED)
|
atomic_load_zu(&pac->oversize_threshold, ATOMIC_RELAXED)
|
||||||
|
|||||||
Reference in New Issue
Block a user