@cryptotaxi247 / netdata-1 / commits / 57ee75946

Reduce EBPF memory usage (#19117)

* Add judy array to hold pids * Add check * Create entry if not found * Fix compilation with internal checks * Use pointer

Stelios Fragkakis committed Dec 4, 2024 at 20:09 UTC 57ee759468e8aed870eec2e5f71f699133cd1c3d
3 files changed +72 -14
src/collectors/ebpf.plugin/ebpf.c
+3 -3
@@ -993,8 +993,8 @@ static inline void ebpf_create_apps_for_module(ebpf_module_t *em, struct ebpf_ta
993 */
994 static void ebpf_create_apps_charts(struct ebpf_target *root)
995 {
996 - if (unlikely(!ebpf_pids))
997 - return;
996 +// if (unlikely(!ebpf_pids))
997 +// return;
998
999 struct ebpf_target *w;
1000 int newly_added = 0;
@@ -2675,7 +2675,7 @@ static void ebpf_allocate_common_vectors()
2675 {
2676 ebpf_judy_pid.pid_table = ebpf_allocate_pid_aral(NETDATA_EBPF_PID_SOCKET_ARAL_TABLE_NAME,
2677 sizeof(netdata_ebpf_judy_pid_stats_t));
2678 - ebpf_pids = callocz((size_t)pid_max, sizeof(ebpf_pid_data_t));
2678 +// ebpf_pids = callocz((size_t)pid_max, sizeof(ebpf_pid_data_t));
2679 ebpf_aral_init();
2680 }
2681
src/collectors/ebpf.plugin/ebpf_apps.c
+64 -9
@@ -306,7 +306,52 @@ int ebpf_read_apps_groups_conf(struct ebpf_target **agdt, struct ebpf_target **a
306
307 #define MAX_CMDLINE 16384
308
309 -ebpf_pid_data_t *ebpf_pids = NULL; // to avoid allocations, we pre-allocate the entire pid space.
309 +Pvoid_t ebpf_pid_judyL = NULL;
310 +SPINLOCK ebpf_pid_spinlock = NETDATA_SPINLOCK_INITIALIZER;
311 +
312 +void ebpf_pid_del(pid_t pid)
313 +{
314 + spinlock_lock(&ebpf_pid_spinlock);
315 + (void) JudyLDel(&ebpf_pid_judyL, (Word_t) pid, PJE0);
316 + spinlock_unlock(&ebpf_pid_spinlock);
317 +}
318 +
319 +static ebpf_pid_data_t *ebpf_find_pid_data_unsafe(pid_t pid)
320 +{
321 + ebpf_pid_data_t *pid_data = NULL;
322 + Pvoid_t *Pvalue = JudyLGet(ebpf_pid_judyL, (Word_t) pid, PJE0);
323 + if (Pvalue)
324 + pid_data = *Pvalue;
325 + return pid_data;
326 +}
327 +
328 +
329 +ebpf_pid_data_t *ebpf_find_pid_data(pid_t pid)
330 +{
331 + spinlock_lock(&ebpf_pid_spinlock);
332 + ebpf_pid_data_t *pid_data = ebpf_find_pid_data_unsafe(pid);
333 + spinlock_unlock(&ebpf_pid_spinlock);
334 + return pid_data;
335 +}
336 +
337 +ebpf_pid_data_t *ebpf_find_or_create_pid_data(pid_t pid)
338 +{
339 + spinlock_lock(&ebpf_pid_spinlock);
340 + ebpf_pid_data_t *pid_data = ebpf_find_pid_data_unsafe(pid);
341 + if (!pid_data) {
342 + Pvoid_t *Pvalue = JudyLIns(&ebpf_pid_judyL, (Word_t) pid, PJE0);
343 + internal_fatal(!Pvalue || Pvalue == PJERR, "EBPF: pid judy array");
344 + if (likely(!*Pvalue))
345 + *Pvalue = pid_data = callocz(1, sizeof(*pid_data));
346 + else
347 + pid_data = *Pvalue;
348 + }
349 + spinlock_unlock(&ebpf_pid_spinlock);
350 +
351 + return pid_data;
352 +}
353 +
354 +//ebpf_pid_data_t *ebpf_pids = NULL; // to avoid allocations, we pre-allocate the entire pid space.
355 ebpf_pid_data_t *ebpf_pids_link_list = NULL; // global list of all processes running
356
357 size_t ebpf_all_pids_count = 0; // the number of processes running read from /proc
@@ -573,8 +618,9 @@ static inline void link_all_processes_to_their_parents(void)
618 continue;
619 }
620
576 - pp = &ebpf_pids[p->ppid];
577 - if (likely(pp->pid)) {
621 +// pp = &ebpf_pids[p->ppid];
622 + pp = ebpf_find_pid_data(p->ppid);
623 + if (likely(pp && pp->pid)) {
624 p->parent = pp;
625 pp->children_count++;
626
@@ -665,10 +711,14 @@ static void apply_apps_groups_targets_inheritance(void)
711 }
712
713 // init goes always to default target
668 - ebpf_pids[INIT_PID].target = apps_groups_default_target;
714 + ebpf_pid_data_t *pid_entry = ebpf_find_or_create_pid_data(INIT_PID);
715 + pid_entry->target = apps_groups_default_target;
716 +// ebpf_pids[INIT_PID].target = apps_groups_default_target;
717
718 // pid 0 goes always to default target
671 - ebpf_pids[0].target = apps_groups_default_target;
719 + pid_entry = ebpf_find_or_create_pid_data(0);
720 + pid_entry->target = apps_groups_default_target;
721 + //ebpf_pids[0].target = apps_groups_default_target;
722
723 // give a default target on all top level processes
724 if (unlikely(debug_enabled))
@@ -684,7 +734,9 @@ static void apply_apps_groups_targets_inheritance(void)
734 p->sortlist = sortlist++;
735 }
736
687 - ebpf_pids[1].sortlist = sortlist++;
737 + //ebpf_pids[1].sortlist = sortlist++;
738 + pid_entry = ebpf_find_or_create_pid_data(1);
739 + pid_entry->sortlist = sortlist++;
740
741 // give a target to all merged child processes
742 found = 1;
@@ -734,7 +786,9 @@ static inline void post_aggregate_targets(struct ebpf_target *root)
786 */
787 void ebpf_del_pid_entry(pid_t pid)
788 {
737 - ebpf_pid_data_t *p = &ebpf_pids[pid];
789 +
790 + //ebpf_pid_data_t *p = &ebpf_pids[pid];
791 + ebpf_pid_data_t *p = ebpf_find_pid_data(pid);
792
793 debug_log("process %d %s exited, deleting it.", pid, p->comm);
794
@@ -746,7 +800,6 @@ void ebpf_del_pid_entry(pid_t pid)
800 if (p->prev)
801 p->prev->next = p->next;
802
749 -
803 if ((p->thread_collecting & EBPF_PIDS_PROC_FILE) || p->has_proc_file)
804 ebpf_all_pids_count--;
805
@@ -768,7 +821,9 @@ void ebpf_del_pid_entry(pid_t pid)
821 }
822 rw_spinlock_write_unlock(&ebpf_judy_pid.index.rw_spinlock);
823
771 - memset(p, 0, sizeof(ebpf_pid_data_t));
824 + freez(p);
825 + //memset(p, 0, sizeof(ebpf_pid_data_t));
826 + ebpf_pid_del(pid);
827 }
828
829 /**
src/collectors/ebpf.plugin/ebpf_apps.h
+5 -2
@@ -201,7 +201,7 @@ typedef struct __attribute__((packed)) ebpf_pid_data {
201
202 } ebpf_pid_data_t;
203
204 -extern ebpf_pid_data_t *ebpf_pids;
204 +//extern ebpf_pid_data_t *ebpf_pids;
205 extern ebpf_pid_data_t *ebpf_pids_link_list;
206 extern size_t ebpf_all_pids_count;
207 extern size_t ebpf_hash_table_pids_count;
@@ -303,8 +303,11 @@ static inline void ebpf_process_release_publish(ebpf_publish_process_t *ptr)
303 freez(ptr);
304 }
305
306 +ebpf_pid_data_t *ebpf_find_or_create_pid_data(pid_t pid);
307 +
308 static inline ebpf_pid_data_t *ebpf_get_pid_data(uint32_t pid, uint32_t tgid, char *name, uint32_t idx) {
307 - ebpf_pid_data_t *ptr = &ebpf_pids[pid];
309 +// ebpf_pid_data_t *ptr = &ebpf_pids[pid];
310 + ebpf_pid_data_t *ptr = ebpf_find_or_create_pid_data(pid);
311 ptr->thread_collecting |= 1<<idx;
312 // The caller is getting data to work.
313 if (!name && idx != EBPF_PIDS_PROC_FILE)