Skip to content

Commit

Permalink
Reduce glibc memory fragmentation (netdata#19385)
Browse files Browse the repository at this point in the history
* reorder memory charts

* make aral use mmap only

* onewayalloc uses mmap

* faster growth for onewayalloc
  • Loading branch information
ktsaou authored Jan 12, 2025
1 parent 21a545a commit 3f172d7
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 56 deletions.
68 changes: 34 additions & 34 deletions src/daemon/pulse/pulse-daemon-memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -180,39 +180,6 @@ void pulse_daemon_memory_do(bool extended) {

// ----------------------------------------------------------------------------------------------------------------

OS_SYSTEM_MEMORY sm = os_system_memory(true);
if (sm.ram_total_bytes && dbengine_out_of_memory_protection) {
static RRDSET *st_memory_available = NULL;
static RRDDIM *rd_available = NULL;

if (unlikely(!st_memory_available)) {
st_memory_available = rrdset_create_localhost(
"netdata",
"out_of_memory_protection",
NULL,
"Memory Usage",
NULL,
"Out of Memory Protection",
"bytes",
"netdata",
"pulse",
130102,
localhost->rrd_update_every,
RRDSET_TYPE_AREA);

rd_available = rrddim_add(st_memory_available, "available", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}

// the sum of all these needs to be above at the total buffers calculation
rrddim_set_by_pointer(
st_memory_available, rd_available,
(collected_number)sm.ram_available_bytes);

rrdset_done(st_memory_available);
}

// ----------------------------------------------------------------------------------------------------------------

{
static RRDSET *st_memory_buffers = NULL;
static RRDDIM *rd_queries = NULL;
Expand Down Expand Up @@ -241,7 +208,7 @@ void pulse_daemon_memory_do(bool extended) {
"bytes",
"netdata",
"pulse",
130103,
130102,
localhost->rrd_update_every,
RRDSET_TYPE_STACKED);

Expand Down Expand Up @@ -282,5 +249,38 @@ void pulse_daemon_memory_do(bool extended) {

// ----------------------------------------------------------------------------------------------------------------

OS_SYSTEM_MEMORY sm = os_system_memory(true);
if (sm.ram_total_bytes && dbengine_out_of_memory_protection) {
static RRDSET *st_memory_available = NULL;
static RRDDIM *rd_available = NULL;

if (unlikely(!st_memory_available)) {
st_memory_available = rrdset_create_localhost(
"netdata",
"out_of_memory_protection",
NULL,
"Memory Usage",
NULL,
"Out of Memory Protection",
"bytes",
"netdata",
"pulse",
130103,
localhost->rrd_update_every,
RRDSET_TYPE_AREA);

rd_available = rrddim_add(st_memory_available, "available", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
}

// the sum of all these needs to be above at the total buffers calculation
rrddim_set_by_pointer(
st_memory_available, rd_available,
(collected_number)sm.ram_available_bytes);

rrdset_done(st_memory_available);
}

// ----------------------------------------------------------------------------------------------------------------

pulse_daemon_memory_system_do(extended);
}
13 changes: 10 additions & 3 deletions src/libnetdata/aral/aral.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@

// in malloc mode, when the page is bigger than this
// use anonymous private mmap pages
#define ARAL_MMAP_PAGES_ABOVE (32ULL * 1024)
#define ARAL_MALLOC_USE_MMAP_ABOVE (4096ULL * 4)

// do not allocate pages smaller than this
#define ARAL_MIN_PAGE_SIZE (4096ULL * 4)

#define ARAL_PAGE_INCOMING_PARTITIONS 4 // up to 32 (32-bits bitmap)

Expand Down Expand Up @@ -493,7 +496,7 @@ static size_t aral_next_allocation_size___adders_lock_needed(ARAL *ar, bool mark
ar->ops[idx].adders.allocation_size = size;
}

if(!ar->config.mmap.enabled && size < ARAL_MMAP_PAGES_ABOVE) {
if(!ar->config.mmap.enabled && size < ARAL_MALLOC_USE_MMAP_ABOVE) {
// when doing malloc, don't allocate entire pages, but only what needed
size =
aral_elements_in_page_size(ar, size) * ar->config.element_size +
Expand Down Expand Up @@ -542,7 +545,7 @@ static ARAL_PAGE *aral_create_page___no_lock_needed(ARAL *ar, size_t size TRACE_
else {
size_t ARAL_PAGE_size = memory_alignment(sizeof(ARAL_PAGE), SYSTEM_REQUIRED_ALIGNMENT);

if (size >= ARAL_MMAP_PAGES_ABOVE) {
if (size >= ARAL_MALLOC_USE_MMAP_ABOVE) {
bool mapped;
uint8_t *ptr = netdata_mmap(NULL, size, MAP_PRIVATE, 1, false, ar->config.options & ARAL_DONT_DUMP, NULL);
if (ptr) {
Expand Down Expand Up @@ -1104,6 +1107,10 @@ ARAL *aral_create(const char *name, size_t element_size, size_t initial_page_ele

// find the minimum page size we will use
size_t min_required_page_size = memory_alignment(sizeof(ARAL_PAGE), SYSTEM_REQUIRED_ALIGNMENT) + 2 * ar->config.element_size;

if(min_required_page_size < ARAL_MIN_PAGE_SIZE)
min_required_page_size = ARAL_MIN_PAGE_SIZE;

min_required_page_size = memory_alignment(min_required_page_size, ar->config.system_page_size);

// make sure the maximum is enough
Expand Down
48 changes: 29 additions & 19 deletions src/libnetdata/onewayalloc/onewayalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ typedef struct owa_page {
size_t stats_pages_size;
size_t stats_mallocs_made;
size_t stats_mallocs_size;
size_t size; // the total size of the page
size_t offset; // the first free byte of the page
struct owa_page *next; // the next page on the list
struct owa_page *last; // the last page on the list - we currently allocate on this
size_t size; // the total size of the page
size_t offset; // the first free byte of the page
struct owa_page *next; // the next page on the list
struct owa_page *last; // the last page on the list - we currently allocate on this
} OWA_PAGE;

static size_t onewayalloc_total_memory = 0;
Expand All @@ -30,7 +30,7 @@ static inline size_t natural_alignment(size_t size) {
}

// Create an OWA
// Once it is created, the called may call the onewayalloc_mallocz()
// Once it is created, the caller may call the onewayalloc_mallocz()
// any number of times, for any amount of memory.

static OWA_PAGE *onewayalloc_create_internal(OWA_PAGE *head, size_t size_hint) {
Expand All @@ -45,34 +45,44 @@ static OWA_PAGE *onewayalloc_create_internal(OWA_PAGE *head, size_t size_hint) {
}

// our default page size
size_t size = OWA_NATURAL_PAGE_SIZE;
size_t size = 32768;

// make sure the new page will fit both the requested size
// and the OWA_PAGE structure at its beginning
size_hint += natural_alignment(sizeof(OWA_PAGE));

// prefer the user size if it is bigger than our size
if(size_hint > size) size = size_hint;
if(size_hint > size)
size = size_hint;

// try to allocate half of the total we have allocated already
if(likely(head)) {
size_t optimal_size = head->stats_pages_size / 2;
if(optimal_size > size) size = optimal_size;
if(head) {
// double the current allocation
size_t optimal_size = head->stats_pages_size;

// cap it at 1 MiB
if(optimal_size > 1ULL * 1024 * 1024)
optimal_size = 1ULL * 1024 * 1024;

// use the optimal if it is more than the required size
if(optimal_size > size)
size = optimal_size;
}

// Make sure our allocations are always a multiple of the hardware page size
if(size % OWA_NATURAL_PAGE_SIZE) size = size + OWA_NATURAL_PAGE_SIZE - (size % OWA_NATURAL_PAGE_SIZE);
if(size % OWA_NATURAL_PAGE_SIZE)
size = size + OWA_NATURAL_PAGE_SIZE - (size % OWA_NATURAL_PAGE_SIZE);

// Use netdata_mmap instead of mallocz
OWA_PAGE *page = (OWA_PAGE *)netdata_mmap(NULL, size, MAP_ANONYMOUS|MAP_PRIVATE, 0, false, false, NULL);
if(unlikely(!page)) fatal("Cannot allocate onewayalloc buffer of size %zu", size);

// OWA_PAGE *page = (OWA_PAGE *)netdata_mmap(NULL, size, MAP_ANONYMOUS|MAP_PRIVATE, 0);
// if(unlikely(!page)) fatal("Cannot allocate onewayalloc buffer of size %zu", size);
OWA_PAGE *page = (OWA_PAGE *)mallocz(size);
__atomic_add_fetch(&onewayalloc_total_memory, size, __ATOMIC_RELAXED);

page->size = size;
page->offset = natural_alignment(sizeof(OWA_PAGE));
page->next = page->last = NULL;

if(unlikely(!head)) {
if(!head) {
// this is the first time we are called
head = page;
head->stats_pages = 0;
Expand Down Expand Up @@ -205,9 +215,9 @@ void onewayalloc_destroy(ONEWAYALLOC *owa) {
OWA_PAGE *p = page;
page = page->next;

// munmap(p, p->size);
freez(p);
// Use netdata_munmap instead of freez
netdata_munmap(p, p->size);
}

__atomic_sub_fetch(&onewayalloc_total_memory, total_size, __ATOMIC_RELAXED);
}
}

0 comments on commit 3f172d7

Please sign in to comment.