Skip to content

Commit 55df669

Browse files
authored
Adaptive thread span cache (#96)
1 parent ea79cf6 commit 55df669

File tree

1 file changed

+59
-3
lines changed

1 file changed

+59
-3
lines changed

rpmalloc/rpmalloc.c

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020
//! Enable per-thread cache
2121
#define ENABLE_THREAD_CACHE 1
2222
#endif
23+
#ifndef ENABLE_ADAPTIVE_THREAD_CACHE
24+
//! Enable adaptive size of per-thread cache (still bounded by THREAD_CACHE_MULTIPLIER hard limit)
25+
#define ENABLE_ADAPTIVE_THREAD_CACHE 1
26+
#endif
2327
#ifndef ENABLE_GLOBAL_CACHE
2428
//! Enable global cache shared between all threads, requires thread cache
2529
#define ENABLE_GLOBAL_CACHE 1
@@ -51,7 +55,7 @@
5155

5256
#if ENABLE_THREAD_CACHE
5357
#ifndef ENABLE_UNLIMITED_CACHE
54-
//! Unlimited thread and global cache unified control
58+
//! Unlimited thread and global cache
5559
#define ENABLE_UNLIMITED_CACHE 0
5660
#endif
5761
#ifndef ENABLE_UNLIMITED_THREAD_CACHE
@@ -78,6 +82,11 @@
7882
# define ENABLE_GLOBAL_CACHE 0
7983
#endif
8084

85+
#if !ENABLE_THREAD_CACHE || ENABLE_UNLIMITED_THREAD_CACHE
86+
# undef ENABLE_ADAPTIVE_THREAD_CACHE
87+
# define ENABLE_ADAPTIVE_THREAD_CACHE 0
88+
#endif
89+
8190
#if DISABLE_UNMAP && !ENABLE_GLOBAL_CACHE
8291
# error Must use global cache if unmap is disabled
8392
#endif
@@ -266,6 +275,16 @@ union span_data_t {
266275
uint64_t compound;
267276
};
268277

278+
#if ENABLE_ADAPTIVE_THREAD_CACHE
279+
struct span_use_t {
280+
//! Current number of spans used (actually used, not in cache)
281+
unsigned int current;
282+
//! High water mark of spans used
283+
unsigned int high;
284+
};
285+
typedef struct span_use_t span_use_t;
286+
#endif
287+
269288
//A span can either represent a single span of memory pages with size declared by span_map_count configuration variable,
270289
//or a set of spans in a continuous region, a super span. Any reference to the term "span" usually refers to both a single
271290
//span or a super span. A super span can further be divided into multiple spans (or this, super spans), where the first
@@ -310,6 +329,10 @@ struct heap_t {
310329
#if ENABLE_THREAD_CACHE
311330
//! List of free spans (single linked list)
312331
span_t* span_cache[LARGE_CLASS_COUNT];
332+
#endif
333+
#if ENABLE_ADAPTIVE_THREAD_CACHE
334+
//! Current and high water mark of spans used per span count
335+
span_use_t span_use[LARGE_CLASS_COUNT];
313336
#endif
314337
//! Mapped but unused spans
315338
span_t* span_reserve;
@@ -806,8 +829,21 @@ _memory_heap_cache_insert(heap_t* heap, span_t* span) {
806829
_memory_span_list_push(&heap->span_cache[idx], span);
807830
#else
808831
const size_t release_count = (!idx ? _memory_span_release_count : _memory_span_release_count_large);
809-
if (_memory_span_list_push(&heap->span_cache[idx], span) <= (release_count * THREAD_CACHE_MULTIPLIER))
832+
size_t current_cache_size = _memory_span_list_push(&heap->span_cache[idx], span);
833+
if (current_cache_size <= release_count)
834+
return;
835+
const size_t hard_limit = release_count * THREAD_CACHE_MULTIPLIER;
836+
if (current_cache_size <= hard_limit) {
837+
#if ENABLE_ADAPTIVE_THREAD_CACHE
838+
//Require 25% of high water mark to remain in cache (and at least 1, if use is 0)
839+
size_t high_mark = heap->span_use[idx].high;
840+
const size_t min_limit = (high_mark >> 2) + release_count + 1;
841+
if (current_cache_size < min_limit)
842+
return;
843+
#else
810844
return;
845+
#endif
846+
}
811847
heap->span_cache[idx] = _memory_span_list_split(span, release_count);
812848
assert(span->data.list.size == release_count);
813849
#if ENABLE_STATISTICS
@@ -954,6 +990,12 @@ _memory_allocate_from_heap(heap_t* heap, size_t size) {
954990
return span;
955991
}
956992

993+
#if ENABLE_ADAPTIVE_THREAD_CACHE
994+
++heap->span_use[0].current;
995+
if (heap->span_use[0].current > heap->span_use[0].high)
996+
heap->span_use[0].high = heap->span_use[0].current;
997+
#endif
998+
957999
//Mark span as owned by this heap and set base data
9581000
assert(span->span_count == 1);
9591001
span->size_class = (uint16_t)class_idx;
@@ -989,6 +1031,11 @@ _memory_allocate_large_from_heap(heap_t* heap, size_t size) {
9891031
if (size & (_memory_span_size - 1))
9901032
++span_count;
9911033
size_t idx = span_count - 1;
1034+
#if ENABLE_ADAPTIVE_THREAD_CACHE
1035+
++heap->span_use[idx].current;
1036+
if (heap->span_use[idx].current > heap->span_use[idx].high)
1037+
heap->span_use[idx].high = heap->span_use[idx].current;
1038+
#endif
9921039

9931040
//Step 1: Find span in one of the cache levels
9941041
span_t* span = _memory_heap_cache_extract(heap, span_count);
@@ -1084,6 +1131,10 @@ _memory_deallocate_to_heap(heap_t* heap, span_t* span, void* p) {
10841131
//block (guard for classes with only 1 block) and add to heap cache
10851132
if (block_data->free_count > 0)
10861133
_memory_span_list_doublelink_remove(&heap->size_cache[class_idx], span);
1134+
#if ENABLE_ADAPTIVE_THREAD_CACHE
1135+
if (heap->span_use[0].current)
1136+
--heap->span_use[0].current;
1137+
#endif
10871138
_memory_heap_cache_insert(heap, span);
10881139
}
10891140
return;
@@ -1116,6 +1167,11 @@ _memory_deallocate_large_to_heap(heap_t* heap, span_t* span) {
11161167
assert(span->size_class - SIZE_CLASS_COUNT < LARGE_CLASS_COUNT);
11171168
assert(!(span->flags & SPAN_FLAG_MASTER) || !(span->flags & SPAN_FLAG_SUBSPAN));
11181169
assert((span->flags & SPAN_FLAG_MASTER) || (span->flags & SPAN_FLAG_SUBSPAN));
1170+
#if ENABLE_ADAPTIVE_THREAD_CACHE
1171+
size_t idx = span->span_count - 1;
1172+
if (heap->span_use[idx].current)
1173+
--heap->span_use[idx].current;
1174+
#endif
11191175
if ((span->span_count > 1) && !heap->spans_reserved) {
11201176
heap->span_reserve = span;
11211177
heap->spans_reserved = span->span_count;
@@ -1481,7 +1537,7 @@ rpmalloc_initialize_config(const rpmalloc_config_t* config) {
14811537
_memory_config.enable_huge_pages = _memory_huge_pages;
14821538

14831539
_memory_span_release_count = (_memory_span_map_count > 4 ? ((_memory_span_map_count < 64) ? _memory_span_map_count : 64) : 4);
1484-
_memory_span_release_count_large = (_memory_span_release_count > 4 ? (_memory_span_release_count / 2) : 2);
1540+
_memory_span_release_count_large = (_memory_span_release_count > 8 ? (_memory_span_release_count / 4) : 2);
14851541

14861542
#if (defined(__APPLE__) || defined(__HAIKU__)) && ENABLE_PRELOAD
14871543
if (pthread_key_create(&_memory_thread_heap, 0))

0 commit comments

Comments
 (0)