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)