@cryptotaxi247 / netdata-1 / commits / 3f172d792

Reduce glibc memory fragmentation (#19385)

* reorder memory charts * make aral use mmap only * onewayalloc uses mmap * faster growth for onewayalloc

Costa Tsaousis committed Jan 12, 2025 at 23:24 UTC 3f172d7923bd32ebfc39d9b3c505d7363b21b7d3
3 files changed +73 -56
src/daemon/pulse/pulse-daemon-memory.c
+34 -34
@@ -180,39 +180,6 @@ void pulse_daemon_memory_do(bool extended) {
180
181 // ----------------------------------------------------------------------------------------------------------------
182
183 - OS_SYSTEM_MEMORY sm = os_system_memory(true);
184 - if (sm.ram_total_bytes && dbengine_out_of_memory_protection) {
185 - static RRDSET *st_memory_available = NULL;
186 - static RRDDIM *rd_available = NULL;
187 -
188 - if (unlikely(!st_memory_available)) {
189 - st_memory_available = rrdset_create_localhost(
190 - "netdata",
191 - "out_of_memory_protection",
192 - NULL,
193 - "Memory Usage",
194 - NULL,
195 - "Out of Memory Protection",
196 - "bytes",
197 - "netdata",
198 - "pulse",
199 - 130102,
200 - localhost->rrd_update_every,
201 - RRDSET_TYPE_AREA);
202 -
203 - rd_available = rrddim_add(st_memory_available, "available", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
204 - }
205 -
206 - // the sum of all these needs to be above at the total buffers calculation
207 - rrddim_set_by_pointer(
208 - st_memory_available, rd_available,
209 - (collected_number)sm.ram_available_bytes);
210 -
211 - rrdset_done(st_memory_available);
212 - }
213 -
214 - // ----------------------------------------------------------------------------------------------------------------
215 -
183 {
184 static RRDSET *st_memory_buffers = NULL;
185 static RRDDIM *rd_queries = NULL;
@@ -241,7 +208,7 @@ void pulse_daemon_memory_do(bool extended) {
208 "bytes",
209 "netdata",
210 "pulse",
244 - 130103,
211 + 130102,
212 localhost->rrd_update_every,
213 RRDSET_TYPE_STACKED);
214
@@ -282,5 +249,38 @@ void pulse_daemon_memory_do(bool extended) {
249
250 // ----------------------------------------------------------------------------------------------------------------
251
252 + OS_SYSTEM_MEMORY sm = os_system_memory(true);
253 + if (sm.ram_total_bytes && dbengine_out_of_memory_protection) {
254 + static RRDSET *st_memory_available = NULL;
255 + static RRDDIM *rd_available = NULL;
256 +
257 + if (unlikely(!st_memory_available)) {
258 + st_memory_available = rrdset_create_localhost(
259 + "netdata",
260 + "out_of_memory_protection",
261 + NULL,
262 + "Memory Usage",
263 + NULL,
264 + "Out of Memory Protection",
265 + "bytes",
266 + "netdata",
267 + "pulse",
268 + 130103,
269 + localhost->rrd_update_every,
270 + RRDSET_TYPE_AREA);
271 +
272 + rd_available = rrddim_add(st_memory_available, "available", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
273 + }
274 +
275 + // the sum of all these needs to be above at the total buffers calculation
276 + rrddim_set_by_pointer(
277 + st_memory_available, rd_available,
278 + (collected_number)sm.ram_available_bytes);
279 +
280 + rrdset_done(st_memory_available);
281 + }
282 +
283 + // ----------------------------------------------------------------------------------------------------------------
284 +
285 pulse_daemon_memory_system_do(extended);
286 }
src/libnetdata/aral/aral.c
+10 -3
@@ -27,7 +27,10 @@
27
28 // in malloc mode, when the page is bigger than this
29 // use anonymous private mmap pages
30 -#define ARAL_MMAP_PAGES_ABOVE (32ULL * 1024)
30 +#define ARAL_MALLOC_USE_MMAP_ABOVE (4096ULL * 4)
31 +
32 +// do not allocate pages smaller than this
33 +#define ARAL_MIN_PAGE_SIZE (4096ULL * 4)
34
35 #define ARAL_PAGE_INCOMING_PARTITIONS 4 // up to 32 (32-bits bitmap)
36
@@ -493,7 +496,7 @@ static size_t aral_next_allocation_size___adders_lock_needed(ARAL *ar, bool mark
496 ar->ops[idx].adders.allocation_size = size;
497 }
498
496 - if(!ar->config.mmap.enabled && size < ARAL_MMAP_PAGES_ABOVE) {
499 + if(!ar->config.mmap.enabled && size < ARAL_MALLOC_USE_MMAP_ABOVE) {
500 // when doing malloc, don't allocate entire pages, but only what needed
501 size =
502 aral_elements_in_page_size(ar, size) * ar->config.element_size +
@@ -542,7 +545,7 @@ static ARAL_PAGE *aral_create_page___no_lock_needed(ARAL *ar, size_t size TRACE_
545 else {
546 size_t ARAL_PAGE_size = memory_alignment(sizeof(ARAL_PAGE), SYSTEM_REQUIRED_ALIGNMENT);
547
545 - if (size >= ARAL_MMAP_PAGES_ABOVE) {
548 + if (size >= ARAL_MALLOC_USE_MMAP_ABOVE) {
549 bool mapped;
550 uint8_t *ptr = netdata_mmap(NULL, size, MAP_PRIVATE, 1, false, ar->config.options & ARAL_DONT_DUMP, NULL);
551 if (ptr) {
@@ -1104,6 +1107,10 @@ ARAL *aral_create(const char *name, size_t element_size, size_t initial_page_ele
1107
1108 // find the minimum page size we will use
1109 size_t min_required_page_size = memory_alignment(sizeof(ARAL_PAGE), SYSTEM_REQUIRED_ALIGNMENT) + 2 * ar->config.element_size;
1110 +
1111 + if(min_required_page_size < ARAL_MIN_PAGE_SIZE)
1112 + min_required_page_size = ARAL_MIN_PAGE_SIZE;
1113 +
1114 min_required_page_size = memory_alignment(min_required_page_size, ar->config.system_page_size);
1115
1116 // make sure the maximum is enough
src/libnetdata/onewayalloc/onewayalloc.c
+29 -19
@@ -8,10 +8,10 @@ typedef struct owa_page {
8 size_t stats_pages_size;
9 size_t stats_mallocs_made;
10 size_t stats_mallocs_size;
11 - size_t size; // the total size of the page
12 - size_t offset; // the first free byte of the page
13 - struct owa_page *next; // the next page on the list
14 - struct owa_page *last; // the last page on the list - we currently allocate on this
11 + size_t size; // the total size of the page
12 + size_t offset; // the first free byte of the page
13 + struct owa_page *next; // the next page on the list
14 + struct owa_page *last; // the last page on the list - we currently allocate on this
15 } OWA_PAGE;
16
17 static size_t onewayalloc_total_memory = 0;
@@ -30,7 +30,7 @@ static inline size_t natural_alignment(size_t size) {
30 }
31
32 // Create an OWA
33 -// Once it is created, the called may call the onewayalloc_mallocz()
33 +// Once it is created, the caller may call the onewayalloc_mallocz()
34 // any number of times, for any amount of memory.
35
36 static OWA_PAGE *onewayalloc_create_internal(OWA_PAGE *head, size_t size_hint) {
@@ -45,34 +45,44 @@ static OWA_PAGE *onewayalloc_create_internal(OWA_PAGE *head, size_t size_hint) {
45 }
46
47 // our default page size
48 - size_t size = OWA_NATURAL_PAGE_SIZE;
48 + size_t size = 32768;
49
50 // make sure the new page will fit both the requested size
51 // and the OWA_PAGE structure at its beginning
52 size_hint += natural_alignment(sizeof(OWA_PAGE));
53
54 // prefer the user size if it is bigger than our size
55 - if(size_hint > size) size = size_hint;
55 + if(size_hint > size)
56 + size = size_hint;
57
57 - // try to allocate half of the total we have allocated already
58 - if(likely(head)) {
59 - size_t optimal_size = head->stats_pages_size / 2;
60 - if(optimal_size > size) size = optimal_size;
58 + if(head) {
59 + // double the current allocation
60 + size_t optimal_size = head->stats_pages_size;
61 +
62 + // cap it at 1 MiB
63 + if(optimal_size > 1ULL * 1024 * 1024)
64 + optimal_size = 1ULL * 1024 * 1024;
65 +
66 + // use the optimal if it is more than the required size
67 + if(optimal_size > size)
68 + size = optimal_size;
69 }
70
71 // Make sure our allocations are always a multiple of the hardware page size
64 - if(size % OWA_NATURAL_PAGE_SIZE) size = size + OWA_NATURAL_PAGE_SIZE - (size % OWA_NATURAL_PAGE_SIZE);
72 + if(size % OWA_NATURAL_PAGE_SIZE)
73 + size = size + OWA_NATURAL_PAGE_SIZE - (size % OWA_NATURAL_PAGE_SIZE);
74 +
75 + // Use netdata_mmap instead of mallocz
76 + OWA_PAGE *page = (OWA_PAGE *)netdata_mmap(NULL, size, MAP_ANONYMOUS|MAP_PRIVATE, 0, false, false, NULL);
77 + if(unlikely(!page)) fatal("Cannot allocate onewayalloc buffer of size %zu", size);
78
66 - // OWA_PAGE *page = (OWA_PAGE *)netdata_mmap(NULL, size, MAP_ANONYMOUS|MAP_PRIVATE, 0);
67 - // if(unlikely(!page)) fatal("Cannot allocate onewayalloc buffer of size %zu", size);
68 - OWA_PAGE *page = (OWA_PAGE *)mallocz(size);
79 __atomic_add_fetch(&onewayalloc_total_memory, size, __ATOMIC_RELAXED);
80
81 page->size = size;
82 page->offset = natural_alignment(sizeof(OWA_PAGE));
83 page->next = page->last = NULL;
84
75 - if(unlikely(!head)) {
85 + if(!head) {
86 // this is the first time we are called
87 head = page;
88 head->stats_pages = 0;
@@ -205,9 +215,9 @@ void onewayalloc_destroy(ONEWAYALLOC *owa) {
215 OWA_PAGE *p = page;
216 page = page->next;
217
208 - // munmap(p, p->size);
209 - freez(p);
218 + // Use netdata_munmap instead of freez
219 + netdata_munmap(p, p->size);
220 }
221
222 __atomic_sub_fetch(&onewayalloc_total_memory, total_size, __ATOMIC_RELAXED);
213 -}
223 +}
\ No newline at end of file