Better handle burst allocation on tcache_alloc_small_hard
This commit is contained in:
parent
0c88be9e0a
commit
7c99686165
|
@ -600,6 +600,16 @@ cache_bin_nitems_get_remote(cache_bin_t *bin, cache_bin_sz_t *ncached,
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For small bins, used to calculate how many items to fill at a time.
|
||||||
|
* The final nfill is calculated by (ncached_max >> (base - offset)).
|
||||||
|
*/
|
||||||
|
typedef struct cache_bin_fill_ctl_s cache_bin_fill_ctl_t;
|
||||||
|
struct cache_bin_fill_ctl_s {
|
||||||
|
uint8_t base;
|
||||||
|
uint8_t offset;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Limit how many items can be flushed in a batch (Which is the upper bound
|
* Limit how many items can be flushed in a batch (Which is the upper bound
|
||||||
* for the nflush parameter in tcache_bin_flush_impl()).
|
* for the nflush parameter in tcache_bin_flush_impl()).
|
||||||
|
|
|
@ -39,8 +39,8 @@ struct tcache_slow_s {
|
||||||
szind_t next_gc_bin;
|
szind_t next_gc_bin;
|
||||||
szind_t next_gc_bin_small;
|
szind_t next_gc_bin_small;
|
||||||
szind_t next_gc_bin_large;
|
szind_t next_gc_bin_large;
|
||||||
/* For small bins, fill (ncached_max >> lg_fill_div). */
|
/* For small bins, help determine how many items to fill at a time. */
|
||||||
uint8_t lg_fill_div[SC_NBINS];
|
cache_bin_fill_ctl_t bin_fill_ctl_do_not_access_directly[SC_NBINS];
|
||||||
/* For small bins, whether has been refilled since last GC. */
|
/* For small bins, whether has been refilled since last GC. */
|
||||||
bool bin_refilled[SC_NBINS];
|
bool bin_refilled[SC_NBINS];
|
||||||
/*
|
/*
|
||||||
|
|
105
src/tcache.c
105
src/tcache.c
|
@ -121,6 +121,85 @@ tcache_gc_dalloc_postponed_event_wait(tsd_t *tsd) {
|
||||||
return TE_MIN_START_WAIT;
|
return TE_MIN_START_WAIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
tcache_bin_fill_ctl_init(tcache_slow_t *tcache_slow, szind_t szind) {
|
||||||
|
assert(szind < SC_NBINS);
|
||||||
|
cache_bin_fill_ctl_t *ctl =
|
||||||
|
&tcache_slow->bin_fill_ctl_do_not_access_directly[szind];
|
||||||
|
ctl->base = 1;
|
||||||
|
ctl->offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline cache_bin_fill_ctl_t *
|
||||||
|
tcache_bin_fill_ctl_get(tcache_slow_t *tcache_slow, szind_t szind) {
|
||||||
|
assert(szind < SC_NBINS);
|
||||||
|
cache_bin_fill_ctl_t *ctl =
|
||||||
|
&tcache_slow->bin_fill_ctl_do_not_access_directly[szind];
|
||||||
|
assert(ctl->base > ctl->offset);
|
||||||
|
return ctl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The number of items to be filled at a time for a given small bin is
|
||||||
|
* calculated by (ncached_max >> lg_fill_div).
|
||||||
|
* The actual ctl struct consists of two fields, i.e. base and offset,
|
||||||
|
* and the difference between the two(base - offset) is the final lg_fill_div.
|
||||||
|
* The base is adjusted during GC based on the traffic within a period of time,
|
||||||
|
* while the offset is updated in real time to handle the immediate traffic.
|
||||||
|
*/
|
||||||
|
static inline uint8_t
|
||||||
|
tcache_nfill_small_lg_div_get(tcache_slow_t *tcache_slow, szind_t szind) {
|
||||||
|
cache_bin_fill_ctl_t *ctl = tcache_bin_fill_ctl_get(tcache_slow, szind);
|
||||||
|
return (ctl->base - (opt_experimental_tcache_gc ? ctl->offset : 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When we want to fill more items to respond to burst load,
|
||||||
|
* offset is increased so that (base - offset) is decreased,
|
||||||
|
* which in return increases the number of items to be filled.
|
||||||
|
*/
|
||||||
|
static inline void
|
||||||
|
tcache_nfill_small_burst_prepare(tcache_slow_t *tcache_slow, szind_t szind) {
|
||||||
|
cache_bin_fill_ctl_t *ctl = tcache_bin_fill_ctl_get(tcache_slow, szind);
|
||||||
|
if (ctl->offset + 1 < ctl->base) {
|
||||||
|
ctl->offset++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
tcache_nfill_small_burst_reset(tcache_slow_t *tcache_slow, szind_t szind) {
|
||||||
|
cache_bin_fill_ctl_t *ctl = tcache_bin_fill_ctl_get(tcache_slow, szind);
|
||||||
|
ctl->offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* limit == 0: indicating that the fill count should be increased,
|
||||||
|
* i.e. lg_div(base) should be decreased.
|
||||||
|
*
|
||||||
|
* limit != 0: limit is set to ncached_max, indicating that the fill
|
||||||
|
* count should be decreased, i.e. lg_div(base) should be increased.
|
||||||
|
*/
|
||||||
|
static inline void
|
||||||
|
tcache_nfill_small_gc_update(tcache_slow_t *tcache_slow, szind_t szind,
|
||||||
|
cache_bin_sz_t limit) {
|
||||||
|
cache_bin_fill_ctl_t *ctl = tcache_bin_fill_ctl_get(tcache_slow, szind);
|
||||||
|
if (!limit && ctl->base > 1) {
|
||||||
|
/*
|
||||||
|
* Increase fill count by 2X for small bins. Make sure
|
||||||
|
* lg_fill_div stays greater than 1.
|
||||||
|
*/
|
||||||
|
ctl->base--;
|
||||||
|
} else if (limit && (limit >> ctl->base) > 1) {
|
||||||
|
/*
|
||||||
|
* Reduce fill count by 2X. Limit lg_fill_div such that
|
||||||
|
* the fill count is always at least 1.
|
||||||
|
*/
|
||||||
|
ctl->base++;
|
||||||
|
}
|
||||||
|
/* Reset the offset for the next GC period. */
|
||||||
|
ctl->offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
static uint8_t
|
static uint8_t
|
||||||
tcache_gc_item_delay_compute(szind_t szind) {
|
tcache_gc_item_delay_compute(szind_t szind) {
|
||||||
assert(szind < SC_NBINS);
|
assert(szind < SC_NBINS);
|
||||||
|
@ -298,21 +377,19 @@ tcache_gc_small(tsd_t *tsd, tcache_slow_t *tcache_slow, tcache_t *tcache,
|
||||||
cache_bin_sz_t low_water = cache_bin_low_water_get(cache_bin);
|
cache_bin_sz_t low_water = cache_bin_low_water_get(cache_bin);
|
||||||
if (low_water > 0) {
|
if (low_water > 0) {
|
||||||
/*
|
/*
|
||||||
* Reduce fill count by 2X. Limit lg_fill_div such that
|
* There is unused items within the GC period => reduce fill count.
|
||||||
* the fill count is always at least 1.
|
* limit field != 0 is borrowed to indicate that the fill count
|
||||||
|
* should be reduced.
|
||||||
*/
|
*/
|
||||||
if ((cache_bin_ncached_max_get(cache_bin) >>
|
tcache_nfill_small_gc_update(tcache_slow, szind,
|
||||||
tcache_slow->lg_fill_div[szind]) > 1) {
|
/* limit */ cache_bin_ncached_max_get(cache_bin));
|
||||||
tcache_slow->lg_fill_div[szind]++;
|
|
||||||
}
|
|
||||||
} else if (tcache_slow->bin_refilled[szind]) {
|
} else if (tcache_slow->bin_refilled[szind]) {
|
||||||
/*
|
/*
|
||||||
* Increase fill count by 2X for small bins. Make sure
|
* There has been refills within the GC period => increase fill count.
|
||||||
* lg_fill_div stays greater than 0.
|
* limit field set to 0 is borrowed to indicate that the fill count
|
||||||
|
* should be increased.
|
||||||
*/
|
*/
|
||||||
if (tcache_slow->lg_fill_div[szind] > 1) {
|
tcache_nfill_small_gc_update(tcache_slow, szind, /* limit */ 0);
|
||||||
tcache_slow->lg_fill_div[szind]--;
|
|
||||||
}
|
|
||||||
tcache_slow->bin_refilled[szind] = false;
|
tcache_slow->bin_refilled[szind] = false;
|
||||||
}
|
}
|
||||||
assert(!tcache_slow->bin_refilled[szind]);
|
assert(!tcache_slow->bin_refilled[szind]);
|
||||||
|
@ -526,7 +603,7 @@ tcache_alloc_small_hard(tsdn_t *tsdn, arena_t *arena,
|
||||||
assert(tcache_slow->arena != NULL);
|
assert(tcache_slow->arena != NULL);
|
||||||
assert(!tcache_bin_disabled(binind, cache_bin, tcache_slow));
|
assert(!tcache_bin_disabled(binind, cache_bin, tcache_slow));
|
||||||
cache_bin_sz_t nfill = cache_bin_ncached_max_get(cache_bin)
|
cache_bin_sz_t nfill = cache_bin_ncached_max_get(cache_bin)
|
||||||
>> tcache_slow->lg_fill_div[binind];
|
>> tcache_nfill_small_lg_div_get(tcache_slow, binind);
|
||||||
if (nfill == 0) {
|
if (nfill == 0) {
|
||||||
nfill = 1;
|
nfill = 1;
|
||||||
}
|
}
|
||||||
|
@ -534,6 +611,7 @@ tcache_alloc_small_hard(tsdn_t *tsdn, arena_t *arena,
|
||||||
/* nfill_min */ opt_experimental_tcache_gc ?
|
/* nfill_min */ opt_experimental_tcache_gc ?
|
||||||
((nfill >> 1) + 1) : nfill, /* nfill_max */ nfill);
|
((nfill >> 1) + 1) : nfill, /* nfill_max */ nfill);
|
||||||
tcache_slow->bin_refilled[binind] = true;
|
tcache_slow->bin_refilled[binind] = true;
|
||||||
|
tcache_nfill_small_burst_prepare(tcache_slow, binind);
|
||||||
ret = cache_bin_alloc(cache_bin, tcache_success);
|
ret = cache_bin_alloc(cache_bin, tcache_success);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1059,6 +1137,7 @@ tcache_bin_flush_bottom(tsd_t *tsd, tcache_t *tcache, cache_bin_t *cache_bin,
|
||||||
void
|
void
|
||||||
tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, cache_bin_t *cache_bin,
|
tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, cache_bin_t *cache_bin,
|
||||||
szind_t binind, unsigned rem) {
|
szind_t binind, unsigned rem) {
|
||||||
|
tcache_nfill_small_burst_reset(tcache->tcache_slow, binind);
|
||||||
tcache_bin_flush_bottom(tsd, tcache, cache_bin, binind, rem,
|
tcache_bin_flush_bottom(tsd, tcache, cache_bin, binind, rem,
|
||||||
/* small */ true);
|
/* small */ true);
|
||||||
}
|
}
|
||||||
|
@ -1233,7 +1312,7 @@ tcache_init(tsd_t *tsd, tcache_slow_t *tcache_slow, tcache_t *tcache,
|
||||||
&cur_offset);
|
&cur_offset);
|
||||||
for (unsigned i = 0; i < tcache_nbins; i++) {
|
for (unsigned i = 0; i < tcache_nbins; i++) {
|
||||||
if (i < SC_NBINS) {
|
if (i < SC_NBINS) {
|
||||||
tcache_slow->lg_fill_div[i] = 1;
|
tcache_bin_fill_ctl_init(tcache_slow, i);
|
||||||
tcache_slow->bin_refilled[i] = false;
|
tcache_slow->bin_refilled[i] = false;
|
||||||
tcache_slow->bin_flush_delay_items[i]
|
tcache_slow->bin_flush_delay_items[i]
|
||||||
= tcache_gc_item_delay_compute(i);
|
= tcache_gc_item_delay_compute(i);
|
||||||
|
|
Loading…
Reference in New Issue