-
Notifications
You must be signed in to change notification settings - Fork 981
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce active defragmentation #448
Comments
The solution is to leverage helio's I suggest the following heuristic as a base line for mimalloc: // taken from mimalloc private code.
static inline mi_slice_t* mi_slice_first(const mi_slice_t* slice) {
mi_slice_t* start = (mi_slice_t*)((uint8_t*)slice - slice->slice_offset);
return start;
}
// taken from mimalloc private code.
static inline mi_segment_t* _mi_ptr_segment(const void* p) {
return (mi_segment_t*)((uintptr_t)p & ~MI_SEGMENT_MASK);
}
#define mi_likely(x) __builtin_expect(!!(x), true)
// returns true if page is not active, and its used blocks <= capacity * ratio
bool mi_heap_page_is_underutilized(mi_heap_t* heap, void* p, float ratio) {
mi_segment_t* const segment = _mi_ptr_segment(p);
// from _mi_segment_page_of
ptrdiff_t diff = (uint8_t*)p - (uint8_t*)segment;
size_t idx = (size_t)diff >> MI_SEGMENT_SLICE_SHIFT;
mi_slice_t* slice0 = (mi_slice_t*)&segment->slices[idx];
mi_slice_t* slice = mi_slice_first(slice0); // adjust to the block that holds the page data
mi_page_t* page = (mi_page_t*)slice;
// end from _mi_segment_page_of //
// from mi_page_heap
mi_heap_t* page_heap = (mi_heap_t*)(mi_atomic_load_relaxed(&(page)->xheap));
// the heap id matches and it is not a full page
if (mi_likely(page_heap == heap && page->flags.x.in_full == 0)) {
// mi_page_queue_t* pq = mi_heap_page_queue_of(heap, page);
// first in the list, meaning it's the head of page queue, thus being used for malloc
if (page->prev == NULL)
return false;
// this page belong to this heap and is not first in the page queue. Lets check its
// utilization.
return page->used <= unsigned(page->capacity * ratio);
}
return false;
} |
a. We can trigger defragmentation based on thread-local conditions like RSS/Used ratio in a specific thread. b. Another option is to use process-global conditions like |
|
This will implemented as follow:
The first version will not include the actual step of the memory re-allocation, to make this a simpler version of the |
…onflydb#448 Signed-off-by: Boaz Sade <boaz@dragonflydb.io>
…onflydb#448 Signed-off-by: Boaz Sade <boaz@dragonflydb.io>
Signed-off-by: Boaz Sade <boaz@dragonflydb.io>
Signed-off-by: Boaz Sade <boaz@dragonflydb.io>
The next step is to add the function mi_heap_page_is_underutilized as a patch to the build of third parties at helio. This would enable the implementation of the actual defragmentation. |
Signed-off-by: Boaz Sade <boaz@dragonflydb.io>
Signed-off-by: Boaz Sade <boaz@dragonflydb.io>
…onflydb#448 Signed-off-by: Boaz Sade <boaz@dragonflydb.io>
…onflydb#448 Signed-off-by: Boaz Sade <boaz@dragonflydb.io>
…onflydb#448 feat(server): memory defrag support - mi_option changed dragonflydb#448 Signed-off-by: Boaz Sade <boaz@dragonflydb.io>
…onflydb#448 feat(server): memory defrag support - mi_option changed dragonflydb#448 feat(server): active fragmentation - spell check issue dragonflydb#448 Signed-off-by: Boaz Sade <boaz@dragonflydb.io>
…onflydb#448 feat(server): memory defrag support - mi_option changed dragonflydb#448 feat(server): active fragmentation - spell check issue dragonflydb#448 feat(server): active memory defrag task dragonflydb#448 Signed-off-by: Boaz Sade <boaz@dragonflydb.io>
…onflydb#448 feat(server): memory defrag support - mi_option changed dragonflydb#448 feat(server): active fragmentation - spell check issue dragonflydb#448 feat(server): active memory defrag task dragonflydb#448 feat(server): active memory defrag task dragonflydb#448 Signed-off-by: Boaz Sade <boaz@dragonflydb.io>
…onflydb#448 feat(server): memory defrag support - mi_option changed dragonflydb#448 feat(server): active fragmentation - spell check issue dragonflydb#448 feat(server): active memory defrag task dragonflydb#448 feat(server): active memory defrag task dragonflydb#448 feat(server): active memory defrag task dragonflydb#448 Signed-off-by: Boaz Sade <boaz@dragonflydb.io>
…onflydb#448 feat(server): memory defrag support - mi_option changed dragonflydb#448 feat(server): active fragmentation - spell check issue dragonflydb#448 feat(server): active memory defrag task dragonflydb#448 Signed-off-by: Boaz Sade <boaz@dragonflydb.io>
Signed-off-by: Boaz Sade <boaz@dragonflydb.io>
Signed-off-by: Boaz Sade <boaz@dragonflydb.io>
…onflydb#448 feat(server): memory defrag support - mi_option changed dragonflydb#448 feat(server): active fragmentation - spell check issue dragonflydb#448 feat(server): active memory defrag task dragonflydb#448 Signed-off-by: Boaz Sade <boaz@dragonflydb.io>
…onflydb#448 feat(server): memory defrag support - mi_option changed dragonflydb#448 feat(server): active fragmentation - spell check issue dragonflydb#448 feat(server): active memory defrag task dragonflydb#448 Signed-off-by: Boaz Sade <boaz@dragonflydb.io>
…onflydb#448 feat(server): memory defrag support - mi_option changed dragonflydb#448 feat(server): active fragmentation - spell check issue dragonflydb#448 feat(server): active memory defrag task dragonflydb#448 Signed-off-by: Boaz Sade <boaz@dragonflydb.io>
…onflydb#448 feat(server): memory defrag support - mi_option changed dragonflydb#448 feat(server): active fragmentation - spell check issue dragonflydb#448 feat(server): active memory defrag task dragonflydb#448 Signed-off-by: Boaz Sade <boaz@dragonflydb.io>
Signed-off-by: Boaz Sade <boaz@dragonflydb.io>
Signed-off-by: Boaz Sade <boaz@dragonflydb.io>
Signed-off-by: Boaz Sade <boaz@dragonflydb.io>
Signed-off-by: Boaz Sade <boaz@dragonflydb.io>
Signed-off-by: Boaz Sade <boaz@dragonflydb.io>
Complements #448. Signed-off-by: Roman Gershman <roman@dragonflydb.io>
Complements #448. Signed-off-by: Roman Gershman <roman@dragonflydb.io> Signed-off-by: Roman Gershman <roman@dragonflydb.io>
Following feedback from our customers - Dragonfly suffers from external fragmentation in some cases.
This problem is common for any slab allocator like tcmalloc, jemalloc and mimalloc.
Consider the following scenario:
usedmemory ~= rss memory
.see the graph below. This situation is problematic and this is what we need to fix.
I do not see any other solution besides active defragmentation, i.e. go over all the allocated items in the heap and grouping them together, thus compressing them in fewer slabs. Something similar is done by active-defrag in Redis using
je_get_defrag_hint
utility function.We need to be smart about initial trigger conditions for the sweep and how we estimate the effectiveness of this defragmentation procedure in order not to introduce infinite loops.
The text was updated successfully, but these errors were encountered: